Les extraits de code sur cette page nécessitent les importations suivantes si vous êtes en dehors de la console pyqgis :

 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. Expressions, Filtrage et Calcul de valeurs

QGIS permet d’analyser des expressions de type SQL. Seul un petit sous-ensemble de la syntaxe SQL est pris en charge. Les expressions peuvent être évaluées soit comme prédicats booléens (en retournant True ou False) ou comme fonctions (en retournant une valeur scalaire). Voir Expressions dans le Manuel de l’utilisateur pour une liste complète des fonctions disponibles.

Trois types basiques sont supportés :

  • nombre — aussi bien les nombres entiers que décimaux, par exemple 123, 3.14

  • texte — ils doivent être entre guillemets simples: 'hello world'

  • référence de colonne — lors de l’évaluation, la référence est remplacée par la valeur réelle du champ. Les noms ne sont pas échappés.

Les opérations suivantes sont disponibles:

  • opérateurs arithmétiques: +, -, *, /, ^

  • parenthèses: pour faire respecter la précédence des opérateurs: (1 + 1) * 3

  • les unaires plus et moins: -12, +5

  • fonctions mathématiques: sqrt, sin, cos, tan, asin, acos, atan

  • fonctions de conversion : to_int, to_real, to_string, to_date

  • fonctions géométriques: $area, $length

  • Fonctions de manipulation de géométries : $x, $y, $geometry, num_geometries, centroid

Et les prédicats suivants sont pris en charge:

  • comparaison: =, !=, >, >=, <, <=

  • comparaison partielle: LIKE (avec % ou _), ~ (expressions régulières)

  • prédicats logiques: AND, OR, NOT

  • Vérification de la valeur NULL: IS NULL, IS NOT NULL

Exemples de prédicats:

  • 1 + 2 = 3

  • sin(angle) > 0

  • 'Hello' LIKE 'He%'

  • (x > 10 AND y > 10) OR z = 0

Exemples d’expressions scalaires:

  • 2 ^ 10

  • sqrt(val)

  • $length + 1

11.1. Analyse syntaxique d’expressions

L’exemple suivant montre comment vérifier si une expression donnée peut être analysée correctement:

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. Évaluation des expressions

Les expressions peuvent être utilisées dans différents contextes, par exemple pour filtrer des entités ou pour calculer de nouvelles valeurs de champ. Dans tous les cas, l’expression doit être évaluée. Cela signifie que sa valeur est calculée en effectuant les étapes de calcul spécifiées, qui peuvent aller de l’arithmétique simple aux expressions agrégées.

11.2.1. Expressions basiques

Cette expression basique évalue une simple opération arithmétique:

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

L’expression peut aussi être utilisée pour faire des comparaisons, renvoyant 1 (True) lorsque vrai, ou 0 (False) sinon.

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

11.2.2. Expressions avec entités

Pour évaluer une expression par rapport à une fonctionnalité, un objet QgsExpressionContext doit être créé et transmis à la fonction d’évaluation afin de permettre à l’expression d’accéder aux valeurs de champ de la fonctionnalité.

L’exemple suivant montre comment créer une entité avec un champ appelé « Colonne » et comment ajouter cette entité au contexte d’expression.

 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

Voici un exemple plus complet de la façon d’utiliser des expressions dans le contexte d’une couche vectorielle, afin de calculer de nouvelles valeurs de champ:

 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. Filtrer une couche à l’aide d’expressions

L’exemple suivant peut être utilisé pour filtrer une couche et ne renverra que les entités qui correspondent au prédicat.

 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. Gestion des erreurs dans une expression

Les erreurs liées à une expression peuvent se révéler lors de l’analyse de l’expression ou de son évaluation :

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