11. Espressioni, Filtraggio e Calcolo di Valori
Suggerimento
I frammenti di codice di questa pagina necessitano delle seguenti importazioni se sei al di fuori della console pyqgis:
1from qgis.core import (
2 edit,
3 QgsExpression,
4 QgsExpressionContext,
5 QgsFeature,
6 QgsFeatureRequest,
7 QgsField,
8 QgsFields,
9 QgsVectorLayer,
10 QgsPointXY,
11 QgsGeometry,
12 QgsProject,
13 QgsExpressionContextUtils
14)
QGIS ha un qualche supporto per l’analisi di espressioni di tipo SQL. È supportato solo un piccolo sottoinsieme della sintassi SQL. Le espressioni possono essere valutate come predicati booleani (restituendo True
o False
) o come funzioni (restituendo un valore scalare). Per un elenco completo delle funzioni disponibili, vedere Espressioni nel Manuale utente.
Sono supportati tre tipi base:
numero – sia numeri interi che decimali, e.g.
123
,3.14
stringa – devono essere racchiuse tra apici singoli:
'hello world'
riferimento a colonna – durante la valutazione, il riferimento é sostituito con il valore del campo. I nomi non sono racchiusi tra apici.
Sono disponibili le seguenti operazioni:
operatori aritmetici:
+
,-
,*
,/
,^
parentesi: per forzare la precedenza tra operatori:
(1 + 1) * 3
somma e sottrazione unari:
-12
,+5
funzioni matematiche:
sqrt
,sin
,cos
,tan
,asin
,acos
,atan
funzioni di conversione:
to_int
,to_real
,to_string
,to_date
funzioni sulla geometria:
$area
,$length
funzioni di manipolazione della geometria:
$x
,$y
,$geometry
,num_geometries
,centroid
Sono supportati i seguenti predicati:
comparazione:
=
,!=
,>
,>=
,<
,<=
pattern matching:
LIKE
(usando % e _),~
(espressioni regolari)predicati logici:
AND
,OR
,NOT
controllo di valori NULL:
IS NULL
,IS NOT NULL
Esempi di predicati:
1 + 2 = 3
sin(angolo) > 0
'Hello' LIKE 'He%'
(x > 10 AND y > 10) OR z = 0
Esempi di espressioni scalari:
2 ^ 10
sqrt(val)
$length + 1
11.1. Analisi di Espressioni
L’esempio seguente mostra come verificare se una determinata espressione può essere analizzata correttamente:
1exp = QgsExpression('1 + 1 = 2')
2assert(not exp.hasParserError())
3
4exp = QgsExpression('1 + 1 = ')
5assert(exp.hasParserError())
6
7assert(exp.parserErrorString() == '\nsyntax error, unexpected end of file')
11.2. Valutazione di Espressioni
Le espressioni possono essere utilizzate in diversi contesti, ad esempio per filtrare gli elementi o per calcolare i valori di nuovi campi. In ogni caso, l’espressione deve essere valorizzata. Ciò significa che il suo valore viene calcolato eseguendo le fasi di calcolo specificate, che possono andare dalla semplice aritmetica alle espressioni aggregate.
11.2.1. Espressioni Base
Questa espressione di base valuta una semplice operazione aritmetica:
exp = QgsExpression('2 * 3')
print(exp)
print(exp.evaluate())
<QgsExpression: '2 * 3'>
6
L’espressione può essere utilizzata anche per il confronto, fornendo una risposta pari a 1 (True
) o a 0 (False
).
exp = QgsExpression('1 + 1 = 2')
exp.evaluate()
# 1
11.2.2. Espressioni con geometrie
Per valutare un’espressione rispetto a un elemento, è necessario creare un oggetto QgsExpressionContext
e passarlo alla funzione evaluate, per consentire all’espressione di accedere ai valori dei campi dell’elemento.
L’esempio seguente mostra come creare un elemento con un campo chiamato «Column» e come aggiungere questo elemento al contesto dell’espressione.
1fields = QgsFields()
2field = QgsField('Column')
3fields.append(field)
4feature = QgsFeature()
5feature.setFields(fields)
6feature.setAttribute(0, 99)
7
8exp = QgsExpression('"Column"')
9context = QgsExpressionContext()
10context.setFeature(feature)
11exp.evaluate(context)
12# 99
Di seguito è riportato un esempio più completo di come utilizzare le espressioni nel contesto di un layer vettoriale, al fine di calcolare nuovi valori di campo:
1from qgis.PyQt.QtCore import QVariant
2
3# create a vector layer
4vl = QgsVectorLayer("Point", "Companies", "memory")
5pr = vl.dataProvider()
6pr.addAttributes([QgsField("Name", QVariant.String),
7 QgsField("Employees", QVariant.Int),
8 QgsField("Revenue", QVariant.Double),
9 QgsField("Rev. per employee", QVariant.Double),
10 QgsField("Sum", QVariant.Double),
11 QgsField("Fun", QVariant.Double)])
12vl.updateFields()
13
14# add data to the first three fields
15my_data = [
16 {'x': 0, 'y': 0, 'name': 'ABC', 'emp': 10, 'rev': 100.1},
17 {'x': 1, 'y': 1, 'name': 'DEF', 'emp': 2, 'rev': 50.5},
18 {'x': 5, 'y': 5, 'name': 'GHI', 'emp': 100, 'rev': 725.9}]
19
20for rec in my_data:
21 f = QgsFeature()
22 pt = QgsPointXY(rec['x'], rec['y'])
23 f.setGeometry(QgsGeometry.fromPointXY(pt))
24 f.setAttributes([rec['name'], rec['emp'], rec['rev']])
25 pr.addFeature(f)
26
27vl.updateExtents()
28QgsProject.instance().addMapLayer(vl)
29
30# The first expression computes the revenue per employee.
31# The second one computes the sum of all revenue values in the layer.
32# The final third expression doesn’t really make sense but illustrates
33# the fact that we can use a wide range of expression functions, such
34# as area and buffer in our expressions:
35expression1 = QgsExpression('"Revenue"/"Employees"')
36expression2 = QgsExpression('sum("Revenue")')
37expression3 = QgsExpression('area(buffer($geometry,"Employees"))')
38
39# QgsExpressionContextUtils.globalProjectLayerScopes() is a convenience
40# function that adds the global, project, and layer scopes all at once.
41# Alternatively, those scopes can also be added manually. In any case,
42# it is important to always go from “most generic” to “most specific”
43# scope, i.e. from global to project to layer
44context = QgsExpressionContext()
45context.appendScopes(QgsExpressionContextUtils.globalProjectLayerScopes(vl))
46
47with edit(vl):
48 for f in vl.getFeatures():
49 context.setFeature(f)
50 f['Rev. per employee'] = expression1.evaluate(context)
51 f['Sum'] = expression2.evaluate(context)
52 f['Fun'] = expression3.evaluate(context)
53 vl.updateFeature(f)
54
55print(f['Sum'])
876.5
11.2.3. Filtrare un layer con le espressioni
L’esempio seguente puó essere usato per filtrare un layer e restituire qualsiasi geometria che soddisfi il predicato.
1layer = QgsVectorLayer("Point?field=Test:integer",
2 "addfeat", "memory")
3
4layer.startEditing()
5
6for i in range(10):
7 feature = QgsFeature()
8 feature.setAttributes([i])
9 assert(layer.addFeature(feature))
10layer.commitChanges()
11
12expression = 'Test >= 3'
13request = QgsFeatureRequest().setFilterExpression(expression)
14
15matches = 0
16for f in layer.getFeatures(request):
17 matches += 1
18
19print(matches)
7
11.3. Gestione degli errori delle espressioni
Gli errori relativi alle espressioni possono verificarsi durante l’analisi o la valutazione delle stesse:
1exp = QgsExpression("1 + 1 = 2")
2if exp.hasParserError():
3 raise Exception(exp.parserErrorString())
4
5value = exp.evaluate()
6if exp.hasEvalError():
7 raise ValueError(exp.evalErrorString())