跳转至

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)或作为函数(返回标量值)来计算。有关可用功能的完整列表,请参阅“用户手册”中的“ 表达式”

支持三种基本类型:

  • 数字——整数和小数,例如1233.14
  • 字符串——它们必须用单引号括起来: 'hello world'
  • 列引用——在评估时,引用将替换为字段的实际值。名称不会被转义。

可以使用以下操作:

  • 算术运算符:+-*/^
  • 括号:用于强制运算符优先级: (1 + 1) * 3
  • 一元加减:-12+5
  • 数学函数:sqrtsincostanasinacosatan
  • 转换函数:to_intto_realto_stringto_date
  • 几何函数:$area$length
  • 几何处理函数:$x$y$geometrynum_geometriescentroid

支持以下运算:

  • 比较:=!=>>=<<=
  • 模式匹配:LIKE(使用%和_),~(正则表达式)
  • 逻辑谓词:ANDORNOT
  • NULL值检查:,IS NULLIS 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 解析表达式⚓︎

下面的例子展示了如何检查一个表达式是否能被正确解析:

1
2
3
4
5
6
7
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 基本表达式⚓︎

此基本表达式代表一个简单的算术运算:

1
2
3
4
5
6
exp = QgsExpression('2 * 3')
print(exp)
print(exp.evaluate())

# <QgsExpression: '2 * 3'>
# 6

表达式也可用于比较,1为真,0为假

1
2
3
4
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 处理异常错误⚓︎

在表达式解析或评估期间,可能发生表达相关的错误:

1
2
3
4
5
6
7
exp = QgsExpression("1 + 1 = 2 ")
if exp.hasParserError():
   raise Exception(exp.parserErrorString())

value = exp.evaluate()
if exp.hasEvalError():
   raise ValueError(exp.evalErrorString())