23.9. Escribir nuevos algoritmos de procesamiento como scripts de Python
Hay dos opciones para escribir algoritmos de procesamiento usando Python.
Dentro de QGIS, puede usar Crear nuevo script en el menú :guilabel:` Scripts` en la parte superior de Barra de Herramientas Procesos para abrir Editor de Scripst de Procesos donde puede escribir tu codigo. Para simplificar la tarea, puede comenzar con una plantilla de script usando Crear nuevo script desde plantilla del mismo menú. Esto abre una plantilla que se extiende QgsProcessingAlgorithm
.
Si guarda el script en la carpeta: file: scripts (la ubicación predeterminada) con la extensión .py
, el algoritmo estará disponible en Caja de Herramientas de Procesos.
23.9.1. Extendiendo QgsProcessingAlgorithm
El siguiente código
toma una capa vectorial como entrada
cuenta el número de objetos
hace una operación de buffer
crea una capa ráster a partir del resultado de la operación buffer
devuelve la capa buffer, la capa ráster y el número de objetos
1from qgis.PyQt.QtCore import QCoreApplication
2from qgis.core import (QgsProcessing,
3 QgsProcessingAlgorithm,
4 QgsProcessingException,
5 QgsProcessingOutputNumber,
6 QgsProcessingParameterDistance,
7 QgsProcessingParameterFeatureSource,
8 QgsProcessingParameterVectorDestination,
9 QgsProcessingParameterRasterDestination)
10from qgis import processing
11
12
13class ExampleProcessingAlgorithm(QgsProcessingAlgorithm):
14 """
15 This is an example algorithm that takes a vector layer,
16 creates some new layers and returns some results.
17 """
18
19 def tr(self, string):
20 """
21 Returns a translatable string with the self.tr() function.
22 """
23 return QCoreApplication.translate('Processing', string)
24
25 def createInstance(self):
26 # Must return a new copy of your algorithm.
27 return ExampleProcessingAlgorithm()
28
29 def name(self):
30 """
31 Returns the unique algorithm name.
32 """
33 return 'bufferrasterextend'
34
35 def displayName(self):
36 """
37 Returns the translated algorithm name.
38 """
39 return self.tr('Buffer and export to raster (extend)')
40
41 def group(self):
42 """
43 Returns the name of the group this algorithm belongs to.
44 """
45 return self.tr('Example scripts')
46
47 def groupId(self):
48 """
49 Returns the unique ID of the group this algorithm belongs
50 to.
51 """
52 return 'examplescripts'
53
54 def shortHelpString(self):
55 """
56 Returns a localised short help string for the algorithm.
57 """
58 return self.tr('Example algorithm short description')
59
60 def initAlgorithm(self, config=None):
61 """
62 Here we define the inputs and outputs of the algorithm.
63 """
64 # 'INPUT' is the recommended name for the main input
65 # parameter.
66 self.addParameter(
67 QgsProcessingParameterFeatureSource(
68 'INPUT',
69 self.tr('Input vector layer'),
70 types=[QgsProcessing.TypeVectorAnyGeometry]
71 )
72 )
73 self.addParameter(
74 QgsProcessingParameterVectorDestination(
75 'BUFFER_OUTPUT',
76 self.tr('Buffer output'),
77 )
78 )
79 # 'OUTPUT' is the recommended name for the main output
80 # parameter.
81 self.addParameter(
82 QgsProcessingParameterRasterDestination(
83 'OUTPUT',
84 self.tr('Raster output')
85 )
86 )
87 self.addParameter(
88 QgsProcessingParameterDistance(
89 'BUFFERDIST',
90 self.tr('BUFFERDIST'),
91 defaultValue = 1.0,
92 # Make distance units match the INPUT layer units:
93 parentParameterName='INPUT'
94 )
95 )
96 self.addParameter(
97 QgsProcessingParameterDistance(
98 'CELLSIZE',
99 self.tr('CELLSIZE'),
100 defaultValue = 10.0,
101 parentParameterName='INPUT'
102 )
103 )
104 self.addOutput(
105 QgsProcessingOutputNumber(
106 'NUMBEROFFEATURES',
107 self.tr('Number of features processed')
108 )
109 )
110
111 def processAlgorithm(self, parameters, context, feedback):
112 """
113 Here is where the processing itself takes place.
114 """
115 # First, we get the count of features from the INPUT layer.
116 # This layer is defined as a QgsProcessingParameterFeatureSource
117 # parameter, so it is retrieved by calling
118 # self.parameterAsSource.
119 input_featuresource = self.parameterAsSource(parameters,
120 'INPUT',
121 context)
122 numfeatures = input_featuresource.featureCount()
123
124 # Retrieve the buffer distance and raster cell size numeric
125 # values. Since these are numeric values, they are retrieved
126 # using self.parameterAsDouble.
127 bufferdist = self.parameterAsDouble(parameters, 'BUFFERDIST',
128 context)
129 rastercellsize = self.parameterAsDouble(parameters, 'CELLSIZE',
130 context)
131 if feedback.isCanceled():
132 return {}
133 buffer_result = processing.run(
134 'native:buffer',
135 {
136 # Here we pass on the original parameter values of INPUT
137 # and BUFFER_OUTPUT to the buffer algorithm.
138 'INPUT': parameters['INPUT'],
139 'OUTPUT': parameters['BUFFER_OUTPUT'],
140 'DISTANCE': bufferdist,
141 'SEGMENTS': 10,
142 'DISSOLVE': True,
143 'END_CAP_STYLE': 0,
144 'JOIN_STYLE': 0,
145 'MITER_LIMIT': 10
146 },
147 # Because the buffer algorithm is being run as a step in
148 # another larger algorithm, the is_child_algorithm option
149 # should be set to True
150 is_child_algorithm=True,
151 #
152 # It's important to pass on the context and feedback objects to
153 # child algorithms, so that they can properly give feedback to
154 # users and handle cancelation requests.
155 context=context,
156 feedback=feedback)
157
158 # Check for cancelation
159 if feedback.isCanceled():
160 return {}
161
162 # Run the separate rasterization algorithm using the buffer result
163 # as an input.
164 rasterized_result = processing.run(
165 'qgis:rasterize',
166 {
167 # Here we pass the 'OUTPUT' value from the buffer's result
168 # dictionary off to the rasterize child algorithm.
169 'LAYER': buffer_result['OUTPUT'],
170 'EXTENT': buffer_result['OUTPUT'],
171 'MAP_UNITS_PER_PIXEL': rastercellsize,
172 # Use the original parameter value.
173 'OUTPUT': parameters['OUTPUT']
174 },
175 is_child_algorithm=True,
176 context=context,
177 feedback=feedback)
178
179 if feedback.isCanceled():
180 return {}
181
182 # Return the results
183 return {'OUTPUT': rasterized_result['OUTPUT'],
184 'BUFFER_OUTPUT': buffer_result['OUTPUT'],
185 'NUMBEROFFEATURES': numfeatures}
Funciones estándar del algoritmo de Porcesamiento:
- createInstance (obligatorio)
Debe devolver una nueva copia de su algoritmo. Si cambia el nombre de la clase, asegúrese de actualizar también el valor devuelto aquí para que coincida.
- nombre (obligatorio)
Devuelve el nombre exclusivo del algoritmo, que se utiliza para identificar el algoritmo.
- displayName (obligatorio)
Devuelve el nombre del algoritmo traducido.
- grupo
Devuelve el nombre del grupo al que pertenece este algoritmo.
- groupId
Devuelve el ID único del grupo al que pertenece este algoritmo.
- shortHelpString
Devuelve una cadena de ayuda corta localizada para el algoritmo.
- initAlgorithm (obligatorio)
Aquí definimos las entradas y salidas del algoritmo.
INPUT
yOUTPUT
son nombres recomendados para los parámetros de entrada y salida principal, respectivamente.Si un parámetro depende de otro parámetro, se usa
parentParameterName
para especificar esta relación (podría ser el campo / banda de una capa o las unidades de distancia de una capa).
- processAlgorithm (obligatorio)
Aquí es donde tiene lugar el procesamiento.
Los parámetros se recuperan mediante funciones especiales, por ejemplo,
parameterAsSource
yparameterAsDouble
.processing.run
se puede utilizar para ejecutar otros algoritmos de procesamiento desde un algoritmo de procesamiento. El primer parámetro es el nombre del algoritmo, el segundo es un diccionario de los parámetros del algoritmo.Is_child_algorithm
normalmente se establece enTrue
cuando se ejecuta un algoritmo desde dentro de otro algoritmo. Elcontexto
y laretroalimentación
informan al algoritmo sobre el entorno en el que se ejecutará y el canal para comunicarse con el usuario (capturando la solicitud de cancelación, reportando el progreso, proporcionando retroalimentación textual). Cuando se utilizan los parámetros del algoritmo (principal) como parámetros de los algoritmos «secundarios», se deben utilizar los valores de los parámetros originales (por ejemplo,parámetros ['OUTPUT']
).¡Es una buena práctica verificar el objeto de retroalimentación para la cancelación tanto como sea posible! Hacerlo permite una cancelación receptiva, en lugar de obligar a los usuarios a esperar a que ocurra un procesamiento no deseado.
El algoritmo debe devolver valores para todos los parámetros de salida que ha definido como diccionario. En este caso, eso es el búfer y las capas de salida rasterizadas, y el recuento de entidades procesadas. Las claves del diccionario deben coincidir con los nombres de salida / parámetros originales.
23.9.2. El decorador @alg
Con el decorador @alg, puede crear sus propios algoritmos escribiendo el código Python y agregando algunas líneas adicionales para proporcionar la información adicional necesaria para convertirlo en un algoritmo de procesamiento adecuado. Esto simplifica la creación de algoritmos y la especificación de entradas y salidas.
Una limitación importante con el enfoque del decorador es que los algoritmos creados de esta manera siempre se agregarán al proveedor de Scripts de procesamiento de un usuario; no es posible agregar estos algoritmos a un proveedor personalizado, p. Ej. para su uso en complementos.
EL siguiente ejemplo usa el decorador @alg a
usa una capa vectorial como entrada
cuenta el número de objetos
hace una operación buffer
crea una capa ráster a partir del resultado de la operación buffer
devuelve la capa buffer, la capa ráster y el número de objetos
1from qgis import processing
2from qgis.processing import alg
3from qgis.core import QgsProject
4
5@alg(name='bufferrasteralg', label='Buffer and export to raster (alg)',
6 group='examplescripts', group_label='Example scripts')
7# 'INPUT' is the recommended name for the main input parameter
8@alg.input(type=alg.SOURCE, name='INPUT', label='Input vector layer')
9# 'OUTPUT' is the recommended name for the main output parameter
10@alg.input(type=alg.RASTER_LAYER_DEST, name='OUTPUT',
11 label='Raster output')
12@alg.input(type=alg.VECTOR_LAYER_DEST, name='BUFFER_OUTPUT',
13 label='Buffer output')
14@alg.input(type=alg.DISTANCE, name='BUFFERDIST', label='BUFFER DISTANCE',
15 default=1.0)
16@alg.input(type=alg.DISTANCE, name='CELLSIZE', label='RASTER CELL SIZE',
17 default=10.0)
18@alg.output(type=alg.NUMBER, name='NUMBEROFFEATURES',
19 label='Number of features processed')
20
21def bufferrasteralg(instance, parameters, context, feedback, inputs):
22 """
23 Description of the algorithm.
24 (If there is no comment here, you will get an error)
25 """
26 input_featuresource = instance.parameterAsSource(parameters,
27 'INPUT', context)
28 numfeatures = input_featuresource.featureCount()
29 bufferdist = instance.parameterAsDouble(parameters, 'BUFFERDIST',
30 context)
31 rastercellsize = instance.parameterAsDouble(parameters, 'CELLSIZE',
32 context)
33 if feedback.isCanceled():
34 return {}
35 buffer_result = processing.run('native:buffer',
36 {'INPUT': parameters['INPUT'],
37 'OUTPUT': parameters['BUFFER_OUTPUT'],
38 'DISTANCE': bufferdist,
39 'SEGMENTS': 10,
40 'DISSOLVE': True,
41 'END_CAP_STYLE': 0,
42 'JOIN_STYLE': 0,
43 'MITER_LIMIT': 10
44 },
45 is_child_algorithm=True,
46 context=context,
47 feedback=feedback)
48 if feedback.isCanceled():
49 return {}
50 rasterized_result = processing.run('qgis:rasterize',
51 {'LAYER': buffer_result['OUTPUT'],
52 'EXTENT': buffer_result['OUTPUT'],
53 'MAP_UNITS_PER_PIXEL': rastercellsize,
54 'OUTPUT': parameters['OUTPUT']
55 },
56 is_child_algorithm=True, context=context,
57 feedback=feedback)
58 if feedback.isCanceled():
59 return {}
60 return {'OUTPUT': rasterized_result['OUTPUT'],
61 'BUFFER_OUTPUT': buffer_result['OUTPUT'],
62 'NUMBEROFFEATURES': numfeatures}
Como puede ver, involucra dos algoritmos (“native:buffer” y “qgis:rasterize”). El último (“qgis:rasterize”) crea una capa ráster a partir de la capa de búfer que fue generada por el primero (“native:buffer”).
La parte del código donde tiene lugar este procesamiento no es difícil de entender si ha leído el capítulo anterior. Sin embargo, las primeras líneas necesitan una explicación adicional. Proporcionan la información que se necesita para convertir su código en un algoritmo que se puede ejecutar desde cualquiera de los componentes de la GUI, como la caja de herramientas o el modelador gráfico.
Todas estas líneas son llamadas a las funciones del decorador @alg
que ayudan a simplificar la codificación del algoritmo.
El decorador @alg se utiliza para definir el nombre y la ubicación del algoritmo en la Caja de herramientas.
El decorador @alg.input se utiliza para definir las entradas del algoritmo.
El decorador @alg.output se utiliza para definir las salidas del algoritmo.
23.9.3. Tipos de entrada y salida para algoritmos de procesamiento
Aquí está la lista de tipos de entrada y salida que son compatibles con Procesos con sus correspondientes constantes de decorador de alg (algfactory.py
contiene la lista completa de constantes de alg). Ordenado por nombre de clase.
23.9.3.1. Tipos de entrada
Clase |
Alg constante |
Descripción |
---|---|---|
|
Permite a los usuarios seleccionar entre las configuraciones de autenticación disponibles o crear nuevas configuraciones de autenticación |
|
|
Una banda de una capa ráster |
|
|
Un valor booleano |
|
|
Un color |
|
|
Una operación de coordenada (para transformaciones SRC) |
|
|
Un Sistema de Coordenadas de Referencia |
|
|
Un esquema de Base de Datos |
|
|
Una tabla de Base de Datos |
|
|
Una fecha y hora (o una fecha u hora pura) |
|
|
Un parámetro numérico doble para valores de distancia |
|
|
Una enumeración, permitiendo la selección de un conjunto de valores predefinidos |
|
|
Una expresión |
|
|
Una extensión espacial definida por xmin, xmax, ymin, ymax |
|
|
Un campo en la tabla de atributos de una capa vectorial |
|
|
Un nombre de archivo de un archivo existente |
|
|
Un nombre de archivo para un archivo de salida recién creado |
|
|
Una carpeta (carpeta de destino) |
|
|
Un entero |
|
|
Un diseño |
|
|
Un elemento de diseño |
|
|
Una capa de mapa |
|
|
Un tema de mapa de proyecto |
|
|
Una matriz |
|
|
Una capa de malla |
|
|
Un conjunto de capas |
|
|
Un valor numérico |
|
|
Un punto |
|
|
Una conexión disponible para un proveedor de base de datos |
|
|
Un rango de número |
|
|
Una capa ráster. |
|
|
Una capa ráster. |
|
|
Una escala de mapa |
|
|
Un destino de objetos |
|
|
Una fuente de objetos |
|
|
Una cadena de texto |
|
|
Una capa vectorial. |
|
|
Una capa vectorial. |
23.9.3.2. Tipos de salida
Clase |
Alg constante |
Descripción |
---|---|---|
|
Un valor booleano |
|
|
Un parámetro numérico doble para valores de distancia |
|
|
Un nombre de archivo de un archivo existente |
|
|
Una carpeta |
|
|
HTML |
|
|
Un Entero |
|
|
Una definición de capa |
|
|
Una capa de mapa |
|
|
Un conjunto de capas |
|
|
Un valor numérico |
|
|
Una capa ráster. |
|
|
Una cadena de texto |
|
|
Una capa vectorial. |
23.9.4. Manejo de salida de algoritmo
Cuando declara una salida que representa una capa (ráster o vector), el algoritmo intentará agregarla a QGIS una vez que haya terminado.
Capa ráster saliente: QgsProcessingParameterRasterDestination / alg.RASTER_LAYER_DEST.
Capa vectorial saliente: QgsProcessingParameterVectorDestination / alg.VECTOR_LAYER_DEST.
Entonces, incluso si el método processing.run()
no agrega las capas que crea al proyecto actual del usuario, se cargarán las dos capas de salida (búfer y búfer ráster), ya que se guardan en los destinos ingresados por el usuario (o a destinos temporales si el usuario no especifica destinos).
Si se crea una capa como salida de un algoritmo, debe declararse como tal. De lo contrario, no podrá utilizar correctamente el algoritmo en el modelador, ya que lo que se declara no coincidirá con lo que realmente crea el algoritmo.
Puede devolver cadenas, números y más especificándolos en el diccionario de resultados (como se demuestra para «NUMBEROFFEATURES»), pero siempre deben definirse explícitamente como salidas de su algoritmo. Alentamos a los algoritmos a generar tantos valores útiles como sea posible, ya que estos pueden ser valiosos para su uso en algoritmos posteriores cuando su algoritmo se usa como parte de un modelo.
23.9.5. La comunicación con el usuario
Si su algoritmo tarda mucho en procesarse, es una buena idea informar al usuario sobre el progreso. Puedes usar feedback
(QgsProcessingFeedback
) para esto.
El texto de progreso y la barra de progreso se pueden actualizar usando dos métodos: setProgressText(text)
y setProgress(percent)
.
Puede proporcionar más información utilizando pushCommandInfo(text)
, pushDebugInfo(text)
, pushInfo(text)
and reportError(text)
.
Si su guión tiene un problema, la forma correcta de manejarlo es generar una QgsProcessingException
. Puede pasar un mensaje como argumento al constructor de la excepción. Procesos se encargará de manejarlo y comunicarse con el usuario, dependiendo de dónde se esté ejecutando el algoritmo (caja de herramientas, modelador, consola Python, …)
23.9.6. Documentando sus scripts
Puede documentar sus scripts sobrecargando el helpString()
and helpUrl()
methods of QgsProcessingAlgorithm
.
23.9.7. Banderas
Puede anular el método flags()
de QgsProcessingAlgorithm
para decirle a QGIS más sobre su algoritmo. Por ejemplo, puede decirle a QGIS que el script se ocultará al modelador, que se puede cancelar, que no es seguro para subprocesos y más.
Truco
De forma predeterminada, Procesos ejecuta algoritmos en un hilo separado para mantener la respuesta de QGIS mientras se ejecuta la tarea de procesamiento. Si su algoritmo falla regularmente, probablemente esté utilizando llamadas a la API que no son seguras de hacer en un hilo en segundo plano. Intente devolver el indicador QgsProcessingAlgorithm.FlagNoThreading del método flags() de su algoritmo para forzar a Processing a ejecutar su algoritmo en el hilo principal.
23.9.8. Las mejores practivas al escribir scripts de algoritmos
Aquí hay un resumen rápido de ideas a considerar al crear sus algoritmos de script y, especialmente, si desea compartirlos con otros usuarios de QGIS. Seguir estas sencillas reglas garantizará la coherencia entre los diferentes elementos de procesamiento, como la caja de herramientas, el modelador o la interfaz de procesamiento por lotes.
No cargar la capa resultante. Deje al Procesamiento manejar sus resultados y cargue sus capas si es necesario.
Siempre declare las salidas que crea su algoritmo.
No muestre cuadros de mensaje ni use ningún elemento GUI del script. Si desea comunicarse con el usuario, utilice los métodos del objeto de comentarios (
QgsProcessingFeedback
) o lance unaQgsProcessingException
.
Ya hay muchos algoritmos de procesamiento disponibles en QGIS. Puede encontrar el código en https://github.com/qgis/QGIS/blob/release-3_16/python/plugins/processing/algs/qgis.