11. Expresiones, Filtros y Calculando Valores

Consejo

Los fragmentos de código en esta página necesitan las siguientes adiciones si está fuera de la consola de 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 tiene cierto soporte para analizar expresiones similares a SQL. Solo se admite un pequeño subconjunto de sintaxis SQL. Las expresiones se pueden evaluar como predicados booleanos (devolviendo True o False) o como funciones (devolviendo un valor escalar). Consulte Expresiones en el Manual del usuario para obtener una lista completa de las funciones disponibles.

Se le da apoyo a tres tipos:

  • numero - números enteros y números con decimales, e.j. 123, 3.14

  • cadena - se tiene que encerrar en comas individuales: 'hola mundo'

  • columna de referencia - cuando se evalúa, la referencia se substituye con el valor actual del campo. Los nombres no se escapan.

Los siguientes operadores están disponibles:

  • operadores aritméticos: «+». «-», «/», ^

  • paréntesis: para hacer cumplir la precedencia del operador: (1 + 1) * 3

  • unario mas y menos: -12, +5

  • funciones matemáticas: sqrt, sin, cos, tan, asin, acos, atan

  • funciones de conversión: to_int, to_real, to_string, to_date

  • funciones geométricas: $area, $length

  • funciones de manejo de geometría: $x, $y, $geometry, num_geometries, centroid

Se apoya las siguientes predicciones:

  • comparación: =, !=, >, >=, <, <=

  • patrones iguales: LIKE (using % and _), ~ (expresión regular)

  • lógica predicado: AND, OR, NOT

  • revisión de valores NULO: IS NULL, IS NOT NULL

Ejemplos de predicado:

  • 1 + 2 = 3

  • sin(angulo) > 0

  • “Hello” LIKE “He%”`

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

Ejemplo de escala de expresiones:

  • 2 ^ 10

  • sqrt(val)

  • $length + 1

11.1. Análisis de expresiones

El siguiente ejemplo muestra cómo verificar si una expresión dada se puede analizar correctamente:

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. Evaluar expresiones

Las expresiones se pueden usar en diferentes contextos, por ejemplo, para filtrar entidades o para calcular nuevos valores de campo. En cualquier caso, la expresión tiene que ser evaluada. Eso significa que su valor se calcula realizando los pasos computacionales especificados, que pueden variar desde expresiones aritméticas simples hasta expresiones agregadas.

11.2.1. Expresiones Basicas

Esta expresión básica evalúa una operación aritmética simple:

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

La expresión también se puede utilizar para comparar, evaluando 1 (True) o 0 (False)

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

11.2.2. Expresiones con caracteristicas

Para evaluar una expresión sobre una entidad, se debe crear un objeto :clase:`QgsExpressionContext <qgis.core.QgsExpressionContext>` y pasarlo a la función de evaluación para permitir que la expresión acceda a los valores de campo de la entidad.

El siguiente ejemplo muestra cómo crear una entidad con un campo llamado «Columna» y cómo agregar esta entidad al contexto de expresión.

 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

El siguiente es un ejemplo más completo de cómo usar expresiones en el contexto de una capa vectorial, para calcular nuevos valores de 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. Flitrando una capa con expresiones

El siguiente ejemplo se puede utilizar para filtra capas y regresar cualquier característica que empata con el predicado.

 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. Manejando errores de expresión

Los errores relacionados con la expresión pueden ocurrir durante el análisis o la evaluación de expresiones:

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