11 表达式,过滤和计算值
此页面上的代码段需要导入以下模块:
1
2
3
4
5
6
7
8
9
10
11
12
13
14 | from qgis.core import (
edit,
QgsExpression,
QgsExpressionContext,
QgsFeature,
QgsFeatureRequest,
QgsField,
QgsFields,
QgsVectorLayer,
QgsPointXY,
QgsGeometry,
QgsProject,
QgsExpressionContextUtils
)
|
QGIS支持解析类似SQL的表达式。仅支持一小部分SQL语法。表达式可以作为布尔值(返回True或False)或作为函数(返回标量值)来计算。有关可用功能的完整列表,请参阅“用户手册”中的“ 表达式”。
支持三种基本类型:
- 数字——整数和小数,例如
123
,3.14
- 字符串——它们必须用单引号括起来:
'hello world'
- 列引用——在评估时,引用将替换为字段的实际值。名称不会被转义。
可以使用以下操作:
- 算术运算符:
+
,-
,*
,/
,^
- 括号:用于强制运算符优先级:
(1 + 1) * 3
- 一元加减:
-12
,+5
- 数学函数:
sqrt
,sin
,cos
,tan
,asin
, acos
,atan
- 转换函数:
to_int
,to_real
,to_string
,to_date
- 几何函数:
$area
,$length
- 几何处理函数:
$x
,$y
,$geometry
,num_geometries
,centroid
支持以下运算:
- 比较:
=
,!=
,>
,>=
,<
,<=
- 模式匹配:
LIKE
(使用%和_),~
(正则表达式)
- 逻辑谓词:
AND
,OR
,NOT
- NULL值检查:,
IS NULL
,IS NOT NULL
示例:
1 + 2 = 3
sin(angle) > 0
'Hello' LIKE 'He%'
(x > 10 AND y > 10) OR z = 0
标量表达式的示例:
2 ^ 10
sqrt(val)
$length + 1
11.1 解析表达式
下面的例子展示了如何检查一个表达式是否能被正确解析:
| exp = QgsExpression('1 + 1 = 2')
assert(not exp.hasParserError())
exp = QgsExpression('1 + 1 = ')
assert(exp.hasParserError())
assert(exp.parserErrorString() == '\nsyntax error, unexpected end of file')
|
11.2 评估表达式
表达式可以在不同的情况下使用,例如过滤要素或计算新的字段值。在任何情况下,表达式都必须被评估。这意味着它的值是通过执行指定的计算步骤计算出来的,计算步骤可以从简单的算术到集合表达式。
11.2.1 基本表达式
此基本表达式代表一个简单的算术运算:
| exp = QgsExpression('2 * 3')
print(exp)
print(exp.evaluate())
# <QgsExpression: '2 * 3'>
# 6
|
表达式也可用于比较,1为真,0为假
| exp = QgsExpression('1 + 1 = 2')
exp.evaluate()
# 1
|
11.2.2 要素表达式
要对一个要素进行表达式评估,必须创建一个QgsExpressionContext
对象,并将其传递给evaluation
函数,以允许表达式访问该要素的字段值。
下面的示例展示了如何创建一个名为 "Column "字段的要素,以及如何将该要素添加到表达式上下文中。
1
2
3
4
5
6
7
8
9
10
11
12 | fields = QgsFields()
field = QgsField('Column')
fields.append(field)
feature = QgsFeature()
feature.setFields(fields)
feature.setAttribute(0, 99)
exp = QgsExpression('"Column"')
context = QgsExpressionContext()
context.setFeature(feature)
exp.evaluate(context)
# 99
|
下面是一个比较完整的例子,说明如何在矢量图层的上下文中使用表达式,以计算新的字段值:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51 | from qgis.PyQt.QtCore import QMetaType
# 创建矢量图层
vl = QgsVectorLayer("Point", "Companies", "memory")
pr = vl.dataProvider()
pr.addAttributes([QgsField("Name", QMetaType.Type.QString),
QgsField("Employees", QMetaType.Type.Int),
QgsField("Revenue", QMetaType.Type.Double),
QgsField("Rev. per employee", QMetaType.Type.Double),
QgsField("Sum", QMetaType.Type.Double),
QgsField("Fun", QMetaType.Type.Double)])
vl.updateFields()
# 将数据添加到前三个字段
my_data = [
{'x': 0, 'y': 0, 'name': 'ABC', 'emp': 10, 'rev': 100.1},
{'x': 1, 'y': 1, 'name': 'DEF', 'emp': 2, 'rev': 50.5},
{'x': 5, 'y': 5, 'name': 'GHI', 'emp': 100, 'rev': 725.9}]
for rec in my_data:
f = QgsFeature()
pt = QgsPointXY(rec['x'], rec['y'])
f.setGeometry(QgsGeometry.fromPointXY(pt))
f.setAttributes([rec['name'], rec['emp'], rec['rev']])
pr.addFeature(f)
vl.updateExtents()
QgsProject.instance().addMapLayer(vl)
# 第一个表达式计算每个员工的收入
# 第二个计算图层中所有收入值的总和。
# 第三个表达式并没有什么意义,但是说明了我们可以在表达式中使用各种表达式函数(例如area和buffer):
expression1 = QgsExpression('"Revenue"/"Employees"')
expression2 = QgsExpression('sum("Revenue")')
expression3 = QgsExpression('area(buffer($geometry,"Employees"))')
# QgsExpressionContextUtils.globalProjectLayerScopes()是一个方便函数,可一次添加全局,项目和图层范围。另外,这些范围也可以手动添加。无论如何,重要的是始终从“最通用”到“最具体”的范围,即从全局到项目再到图层
context = QgsExpressionContext()
context.appendScopes(QgsExpressionContextUtils.globalProjectLayerScopes(vl))
with edit(vl):
for f in vl.getFeatures():
context.setFeature(f)
f['Rev. per employee'] = expression1.evaluate(context)
f['Sum'] = expression2.evaluate(context)
f['Fun'] = expression3.evaluate(context)
vl.updateFeature(f)
print( f['Sum'])
# 876.5
|
11.2.3 表达式过滤图层
以下示例可用于过滤图层并返回与谓词匹配的所有要素:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 | layer = QgsVectorLayer("Point?field=Test:integer",
"addfeat", "memory")
layer.startEditing()
for i in range(10):
feature = QgsFeature()
feature.setAttributes([i])
assert(layer.addFeature(feature))
layer.commitChanges()
expression = 'Test >= 3'
request = QgsFeatureRequest().setFilterExpression(expression)
matches = 0
for f in layer.getFeatures(request):
matches += 1
print(matches)
# 7
|
11.3 处理异常错误
在表达式解析或评估期间,可能发生表达相关的错误:
| exp = QgsExpression("1 + 1 = 2 ")
if exp.hasParserError():
raise Exception(exp.parserErrorString())
value = exp.evaluate()
if exp.hasEvalError():
raise ValueError(exp.evalErrorString())
|