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
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 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 | from qgis.PyQt.QtCore import QCoreApplication
from qgis.core import (QgsProcessing,
QgsProcessingAlgorithm,
QgsProcessingException,
QgsProcessingOutputNumber,
QgsProcessingParameterDistance,
QgsProcessingParameterFeatureSource,
QgsProcessingParameterVectorDestination,
QgsProcessingParameterRasterDestination)
from qgis import processing
class ExampleProcessingAlgorithm(QgsProcessingAlgorithm):
"""
This is an example algorithm that takes a vector layer,
creates some new layers and returns some results.
"""
def tr(self, string):
"""
Returns a translatable string with the self.tr() function.
"""
return QCoreApplication.translate('Processing', string)
def createInstance(self):
# Must return a new copy of your algorithm.
return ExampleProcessingAlgorithm()
def name(self):
"""
Returns the unique algorithm name.
"""
return 'bufferrasterextend'
def displayName(self):
"""
Returns the translated algorithm name.
"""
return self.tr('Buffer and export to raster (extend)')
def group(self):
"""
Returns the name of the group this algorithm belongs to.
"""
return self.tr('Example scripts')
def groupId(self):
"""
Returns the unique ID of the group this algorithm belongs
to.
"""
return 'examplescripts'
def shortHelpString(self):
"""
Returns a localised short help string for the algorithm.
"""
return self.tr('Example algorithm short description')
def initAlgorithm(self, config=None):
"""
Here we define the inputs and outputs of the algorithm.
"""
# 'INPUT' is the recommended name for the main input
# parameter.
self.addParameter(
QgsProcessingParameterFeatureSource(
'INPUT',
self.tr('Input vector layer'),
types=[QgsProcessing.TypeVectorAnyGeometry]
)
)
self.addParameter(
QgsProcessingParameterVectorDestination(
'BUFFER_OUTPUT',
self.tr('Buffer output'),
)
)
# 'OUTPUT' is the recommended name for the main output
# parameter.
self.addParameter(
QgsProcessingParameterRasterDestination(
'OUTPUT',
self.tr('Raster output')
)
)
self.addParameter(
QgsProcessingParameterDistance(
'BUFFERDIST',
self.tr('BUFFERDIST'),
defaultValue = 1.0,
# Make distance units match the INPUT layer units:
parentParameterName='INPUT'
)
)
self.addParameter(
QgsProcessingParameterDistance(
'CELLSIZE',
self.tr('CELLSIZE'),
defaultValue = 10.0,
parentParameterName='INPUT'
)
)
self.addOutput(
QgsProcessingOutputNumber(
'NUMBEROFFEATURES',
self.tr('Number of features processed')
)
)
def processAlgorithm(self, parameters, context, feedback):
"""
Here is where the processing itself takes place.
"""
# First, we get the count of features from the INPUT layer.
# This layer is defined as a QgsProcessingParameterFeatureSource
# parameter, so it is retrieved by calling
# self.parameterAsSource.
input_featuresource = self.parameterAsSource(parameters,
'INPUT',
context)
numfeatures = input_featuresource.featureCount()
# Retrieve the buffer distance and raster cell size numeric
# values. Since these are numeric values, they are retrieved
# using self.parameterAsDouble.
bufferdist = self.parameterAsDouble(parameters, 'BUFFERDIST',
context)
rastercellsize = self.parameterAsDouble(parameters, 'CELLSIZE',
context)
if feedback.isCanceled():
return {}
buffer_result = processing.run(
'native:buffer',
{
# Here we pass on the original parameter values of INPUT
# and BUFFER_OUTPUT to the buffer algorithm.
'INPUT': parameters['INPUT'],
'OUTPUT': parameters['BUFFER_OUTPUT'],
'DISTANCE': bufferdist,
'SEGMENTS': 10,
'DISSOLVE': True,
'END_CAP_STYLE': 0,
'JOIN_STYLE': 0,
'MITER_LIMIT': 10
},
# Because the buffer algorithm is being run as a step in
# another larger algorithm, the is_child_algorithm option
# should be set to True
is_child_algorithm=True,
#
# It's important to pass on the context and feedback objects to
# child algorithms, so that they can properly give feedback to
# users and handle cancelation requests.
context=context,
feedback=feedback)
# Check for cancelation
if feedback.isCanceled():
return {}
# Run the separate rasterization algorithm using the buffer result
# as an input.
rasterized_result = processing.run(
'qgis:rasterize',
{
# Here we pass the 'OUTPUT' value from the buffer's result
# dictionary off to the rasterize child algorithm.
'LAYER': buffer_result['OUTPUT'],
'EXTENT': buffer_result['OUTPUT'],
'MAP_UNITS_PER_PIXEL': rastercellsize,
# Use the original parameter value.
'OUTPUT': parameters['OUTPUT']
},
is_child_algorithm=True,
context=context,
feedback=feedback)
if feedback.isCanceled():
return {}
# Return the results
return {'OUTPUT': rasterized_result['OUTPUT'],
'BUFFER_OUTPUT': buffer_result['OUTPUT'],
'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
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 56 57 58 59 60 61 62 | from qgis import processing
from qgis.processing import alg
from qgis.core import QgsProject
@alg(name='bufferrasteralg', label='Buffer and export to raster (alg)',
group='examplescripts', group_label='Example scripts')
# 'INPUT' is the recommended name for the main input parameter
@alg.input(type=alg.SOURCE, name='INPUT', label='Input vector layer')
# 'OUTPUT' is the recommended name for the main output parameter
@alg.input(type=alg.RASTER_LAYER_DEST, name='OUTPUT',
label='Raster output')
@alg.input(type=alg.VECTOR_LAYER_DEST, name='BUFFER_OUTPUT',
label='Buffer output')
@alg.input(type=alg.DISTANCE, name='BUFFERDIST', label='BUFFER DISTANCE',
default=1.0)
@alg.input(type=alg.DISTANCE, name='CELLSIZE', label='RASTER CELL SIZE',
default=10.0)
@alg.output(type=alg.NUMBER, name='NUMBEROFFEATURES',
label='Number of features processed')
def bufferrasteralg(instance, parameters, context, feedback, inputs):
"""
Description of the algorithm.
(If there is no comment here, you will get an error)
"""
input_featuresource = instance.parameterAsSource(parameters,
'INPUT', context)
numfeatures = input_featuresource.featureCount()
bufferdist = instance.parameterAsDouble(parameters, 'BUFFERDIST',
context)
rastercellsize = instance.parameterAsDouble(parameters, 'CELLSIZE',
context)
if feedback.isCanceled():
return {}
buffer_result = processing.run('native:buffer',
{'INPUT': parameters['INPUT'],
'OUTPUT': parameters['BUFFER_OUTPUT'],
'DISTANCE': bufferdist,
'SEGMENTS': 10,
'DISSOLVE': True,
'END_CAP_STYLE': 0,
'JOIN_STYLE': 0,
'MITER_LIMIT': 10
},
is_child_algorithm=True,
context=context,
feedback=feedback)
if feedback.isCanceled():
return {}
rasterized_result = processing.run('qgis:rasterize',
{'LAYER': buffer_result['OUTPUT'],
'EXTENT': buffer_result['OUTPUT'],
'MAP_UNITS_PER_PIXEL': rastercellsize,
'OUTPUT': parameters['OUTPUT']
},
is_child_algorithm=True, context=context,
feedback=feedback)
if feedback.isCanceled():
return {}
return {'OUTPUT': rasterized_result['OUTPUT'],
'BUFFER_OUTPUT': buffer_result['OUTPUT'],
'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.