Importante

Translation is a community effort you can join. This page is currently translated at 97.37%.

27.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.

27.9.1. Extendiendo QgsProcessingAlgorithm

El siguiente código

  1. toma una capa vectorial como entrada

  2. cuenta el número de objetos

  3. hace una operación de buffer

  4. crea una capa ráster a partir del resultado de la operación buffer

  5. 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 y OUTPUT 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 y parameterAsDouble.

    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 en True cuando se ejecuta un algoritmo desde dentro de otro algoritmo. El contexto y la retroalimentació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.

27.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

  1. usa una capa vectorial como entrada

  2. cuenta el número de objetos

  3. hace una operación buffer

  4. crea una capa ráster a partir del resultado de la operación buffer

  5. 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 en la que tiene lugar este procesamiento no es difícil de entender si se ha leído el capítulo anterior. Las primeras líneas, sin embargo, necesitan alguna explicación adicional. Proporcionan la información que se necesita para convertir tu código en un algoritmo que pueda ejecutarse desde cualquiera de los componentes de la IGU, como la caja de herramientas o el diseñador de modelos.

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.

For existing parameters and their correspondance, read Input and output types for Processing Algorithms.

27.9.3. 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.

27.9.4. 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, …)

27.9.5. Documentando sus scripts

Puede documentar sus scripts sobrecargando el helpString() and helpUrl() methods of QgsProcessingAlgorithm.

27.9.6. 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.

27.9.7. 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 una QgsProcessingException.

Ya hay muchos algoritmos de procesamiento disponibles en QGIS. Puedes encontrar código en el repositorio QGIS.