The code snippets on this page need the following imports if you're outside the pyqgis console:

 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
)

11. 式、フィルタ適用および値の算出

QGIS has some support for parsing of SQL-like expressions. Only a small subset of SQL syntax is supported. The expressions can be evaluated either as boolean predicates (returning True or False) or as functions (returning a scalar value). See in the User Manual for a complete list of available functions.

3つの基本的な型がサポートされています。

  • 数 --- 整数および小数。例. 123, 3.14

  • 文字列 --- 一重引用符で囲む必要があります: 'hello world'

  • 列参照 --- 評価する際に、参照はフィールドの実際の値で置き換えられます。名前はエスケープされません。

次の演算子が利用可能です:

  • 算術演算子: +, -, *, /, ^

  • 丸括弧: 演算を優先します: (1 + 1) * 3

  • 単項のプラスとマイナス: -12, +5

  • 数学的関数: sqrt, sin, cos, tan, asin, acos, atan

  • 変換関数: to_intto_realto_stringto_date

  • ジオメトリ関数: $area, $length

  • ジオメトリ処理関数: $x$y$geometrynum_geometriescentroid

以下の述語がサポートされています:

  • 比較: =, !=, >, >=, <, <=

  • パターンマッチング: 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. 式を構文解析する

与えられた式が正しくパースできるかどうかは、以下の例で示す方法で確認します。

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')

11.2. 式を評価する

式は、例えば地物をフィルタしたり、新しいフィールド値を計算するなど、異なったコンテクストで使うことができます。いずれの場合においても、式は評価されなければなりません。つまり式の値は、単純な算術式から集約式まで、指定された計算ステップを実行することによって計算されます。

11.2.1. 基本的な式

This basic expression evaluates a simple arithmetic operation:

exp = QgsExpression('2 * 3')
print(exp)
print(exp.evaluate())
<QgsExpression: '2 * 3'>
6

Expression can also be used for comparison, evaluating to 1 (True) or 0 (False)

exp = QgsExpression('1 + 1 = 2')
exp.evaluate()
# 1

11.2.2. 地物に関わる式

地物に関わる式を評価するためには、式が地物のフィールド値にアクセスできるようにするために、 QgsExpressionContext オブジェクトを生成し、評価関数に渡さなければなりません。

以下の例は、"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
52
53
54
55
from qgis.PyQt.QtCore import QVariant

# create a vector layer
vl = QgsVectorLayer("Point", "Companies", "memory")
pr = vl.dataProvider()
pr.addAttributes([QgsField("Name", QVariant.String),
                  QgsField("Employees",  QVariant.Int),
                  QgsField("Revenue", QVariant.Double),
                  QgsField("Rev. per employee", QVariant.Double),
                  QgsField("Sum", QVariant.Double),
                  QgsField("Fun", QVariant.Double)])
vl.updateFields()

# add data to the first three fields
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)

# The first expression computes the revenue per employee.
# The second one computes the sum of all revenue values in the layer.
# The final third expression doesn’t really make sense but illustrates
# the fact that we can use a wide range of expression functions, such
# as area and buffer in our expressions:
expression1 = QgsExpression('"Revenue"/"Employees"')
expression2 = QgsExpression('sum("Revenue")')
expression3 = QgsExpression('area(buffer($geometry,"Employees"))')

# QgsExpressionContextUtils.globalProjectLayerScopes() is a convenience
# function that adds the global, project, and layer scopes all at once.
# Alternatively, those scopes can also be added manually. In any case,
# it is important to always go from “most generic” to “most specific”
# scope, i.e. from global to project to layer
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
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())