23.7. Utilizar algoritmos de procesamiento desde la consola

La consola permite a los usuarios avanzados incrementar su productividad y realizar operaciones complejas que no se pueden realizar utilizando cualquiera de los otros elementos de la GUI del marco de procesamiento. Modelos que involucran varios algoritmos se pueden definir mediante la interfaz de línea de comandos y operaciones adicionales tales como bucles y sentencias condicionales que se pueden añadir para crear flujos de trabajo más flexibles y potentes.

No hay una consola de procesamiento en QGIS, pero todos los comandos de procesamiento están disponibles en su lugar desde el constructor de QGIS consola de Python. Eso significa que puede incorporar esos comandos en el trabajo de su consola y conectar algoritmos de procesamiento a todas las demás funciones (incluidos los métodos de la API de QGIS) disponibles desde allí.

El código se puede ejecutar desde la consola de Python, incluso si no especifica ningún método de procesamiento, se puede convertir en un nuevo algoritmo que más tarde puede llamar desde la caja de herramientas, el modelador gráfico o algún otro componente, tal como lo hace con cualquier otro algoritmo. De hecho, algunos de los algoritmos que se pueden encontrar en la caja de herramientas son sencillas secuencias de comandos.

En esta sección, veremos como utilizar algoritmos de procesado desde la consola de Python de QGIS, y también cómo escribir algoritmos utilizando Python.

23.7.1. Invocando algoritmos desde la consola de Python

Lo primero que tiene que hacer es importar las funciones de procesamiento con la siguiente línea:

>>> from qgis import processing

Ahora, básicamente hay una cosa (interesante) que puedes hacer con eso desde la consola: ejecutar un algoritmo. Eso se hace usando el método run(), que toma el nombre del algoritmo a ejecutar como su primer parámetro, y luego un número variable de parámetros adicionales dependiendo de los requisitos del algoritmo. Entonces, lo primero que necesita saber es el nombre del algoritmo a ejecutar. Ese no es el nombre que ve en la caja de herramientas, sino un nombre de línea de comandos único. Para encontrar el nombre correcto para su algoritmo, puede usar processingRegistry. Escriba la siguiente línea en su consola:

>>> for alg in QgsApplication.processingRegistry().algorithms():
        print(alg.id(), "->", alg.displayName())

Verá algo como esto (con algunos guiones adicionales agregados para mejorar la legibilidad).

3d:tessellate --------------> Tessellate
gdal:aspect ----------------> Aspect
gdal:assignprojection ------> Assign projection
gdal:buffervectors ---------> Buffer vectors
gdal:buildvirtualraster ----> Build Virtual Raster
gdal:cliprasterbyextent ----> Clip raster by extent
gdal:cliprasterbymasklayer -> Clip raster by mask layer
gdal:clipvectorbyextent ----> Clip vector by extent
gdal:clipvectorbypolygon ---> Clip vector by mask layer
gdal:colorrelief -----------> Color relief
gdal:contour ---------------> Contour
gdal:convertformat ---------> Convert format
gdal:dissolve --------------> Dissolve
...

Esa es una lista de todos los ID de algoritmos disponibles, ordenados por nombre de proveedor y nombre de algoritmo, junto con sus nombres correspondientes.

Una vez que conozca el nombre de la línea de comandos del algoritmo, lo siguiente que debe hacer es determinar la sintaxis correcta para ejecutarlo. Eso significa saber qué parámetros se necesitan al llamar al método run().

Existe un método para describir un algoritmo en detalle, que se puede utilizar para obtener una lista de los parámetros que requiere un algoritmo y las salidas que generará. Para obtener esta información, puede utilizar el método algorithmHelp(id_of_the_algorithm). Utilice el ID del algoritmo, no el nombre descriptivo completo.

Llamando al método con native:buffer como parámetro (qgis:buffer es un alias para native:buffer y también funcionará), obtienes la siguiente descripción:

>>> processing.algorithmHelp("native:buffer")
Buffer (native:buffer)

This algorithm computes a buffer area for all the features in an
input layer, using a fixed or dynamic distance.

The segments parameter controls the number of line segments to
use to approximate a quarter circle when creating rounded
offsets.

The end cap style parameter controls how line endings are handled
in the buffer.

The join style parameter specifies whether round, miter or
beveled joins should be used when offsetting corners in a line.

The miter limit parameter is only applicable for miter join
styles, and controls the maximum distance from the offset curve
to use when creating a mitered join.


----------------
Input parameters
----------------

INPUT: Input layer

   Parameter type: QgsProcessingParameterFeatureSource

   Accepted data types:
           - str: layer ID
           - str: layer name
           - str: layer source
           - QgsProcessingFeatureSourceDefinition
           - QgsProperty
           - QgsVectorLayer

DISTANCE: Distance

   Parameter type: QgsProcessingParameterDistance

   Accepted data types:
           - int
           - float
           - QgsProperty

SEGMENTS: Segments

   Parameter type: QgsProcessingParameterNumber

   Accepted data types:
           - int
           - float
           - QgsProperty

END_CAP_STYLE: End cap style

   Parameter type: QgsProcessingParameterEnum

   Available values:
           - 0: Round
           - 1: Flat
           - 2: Square

   Accepted data types:
           - int
           - str: as string representation of int, e.g. '1'
           - QgsProperty

JOIN_STYLE: Join style

   Parameter type: QgsProcessingParameterEnum

   Available values:
           - 0: Round
           - 1: Miter
           - 2: Bevel

   Accepted data types:
           - int
           - str: as string representation of int, e.g. '1'
           - QgsProperty

MITER_LIMIT: Miter limit

   Parameter type: QgsProcessingParameterNumber

   Accepted data types:
           - int
           - float
           - QgsProperty

DISSOLVE: Dissolve result

   Parameter type: QgsProcessingParameterBoolean

   Accepted data types:
           - bool
           - int
           - str
           - QgsProperty

OUTPUT: Buffered

   Parameter type: QgsProcessingParameterFeatureSink

   Accepted data types:
           - str: destination vector file, e.g. 'd:/test.shp'
           - str: 'memory:' to store result in temporary memory layer
           - str: using vector provider ID prefix and destination URI,
                  e.g. 'postgres:...' to store result in PostGIS table
           - QgsProcessingOutputLayerDefinition
           - QgsProperty

----------------
Outputs
----------------

OUTPUT:  <QgsProcessingOutputVectorLayer>
   Buffered

Ahora tienes todo lo que necesitas para ejecutar cualquier algoritmo. Como ya hemos mencionado, los algoritmos se pueden ejecutar usando: run(). Su sintaxis es la siguiente:

>>> processing.run(name_of_the_algorithm, parameters)

Donde parámetros es un diccionario de parámetros que dependen del algoritmo que desea ejecutar, y es exactamente la lista que le proporciona el método algorithmHelp().

1
2
3
4
5
6
7
8
 >>> processing.run("native:buffer", {'INPUT': '/data/lines.shp',
               'DISTANCE': 100.0,
               'SEGMENTS': 10,
               'DISSOLVE': True,
               'END_CAP_STYLE': 0,
               'JOIN_STYLE': 0,
               'MITER_LIMIT': 10,
               'OUTPUT': '/data/buffers.shp'})

Si un parámetro es opcional y no desea utilizarlo, no lo incluya en el diccionario.

Si no se especifica un parámetro, se utilizará el valor predeterminado.

Dependiendo del tipo de parámetro, los valores se introducen de manera diferente. La siguiente lista da una rápida revisión de cómo introducir los valores para cada tipo de parámetro de entrada.

  • Capa ráster, capa vectorial o tabla. Simplemente use una cadena con el nombre que identifica el objeto de datos a usar (el nombre que tiene en la Tabla de contenido de QGIS) o un nombre de archivo (si la capa correspondiente no está abierta, se abrirá pero no se agregará al lienzo del mapa) . Si tiene una instancia de un objeto QGIS que representa la capa, también puede pasarla como parámetro.

  • Enumeración. Si un algoritmo tiene un parámetro de enumeración, el valor de ese parámetro debe ingresarse usando un valor entero. Para conocer las opciones disponibles, puede usar el comando algorithmHelp(), como arriba. Por ejemplo, el algoritmo native:buffer tiene una enumeración llamada JOIN_STYLE:

    JOIN_STYLE: Join style
    
       Parameter type: QgsProcessingParameterEnum
    
       Available values:
               - 0: Round
               - 1: Miter
               - 2: Bevel
    
       Accepted data types:
               - int
               - str: as string representation of int, e.g. '1'
               - QgsProperty
    

    En este caso, el parámetro tiene tres opciones. Tenga en cuenta que el orden parte de cero.

  • Boolean. Use True o False.

  • La entrada múltiple. El valor es una cadena con descriptores de entrada separadas por punto y coma (;). Como en el caso de capas individuales o tablas, cada descriptor de entrada se puede el nombre del objeto de datos, o su ruta de archivo.

  • El campo de la tabla de XXX. Utilice una cadena con el nombre del campo a usar. Este parámetro es sensible a mayúsculas y minúsculas.

  • Tabla fija. Escribir la lista de todas las tablas de valores separadas por comas (,) y cerrar entre comillas ("). Los valores que empiezan en la fila superior y van de izquierda a derecha. También se puede utilizar un arreglo 2-D de valores que representen la tabla.

  • SRC. Introduzca el número del código EPSG del SRC deseado.

  • Extensión. Se debe utilizar una cadena con valores de xmin, xmax, ymin y ymax` separados por comas (,``).

Los parámetros boolean, archivo, cadena y numéricos no necesitan alguna explicación adicional.

Los parámetros de entrada como cadenas, booleanos o valores numéricos tienen valores predeterminados. El valor predeterminado se utiliza si falta la entrada de parámetro correspondiente.

Para los objetos de datos de salida, escriba la ruta del archivo que se utilizará para guardarlos, tal como se hace en la caja de herramientas. Si no se especifica el objeto de salida, el resultado se guarda en un archivo temporal (o se omite si es una salida opcional). La extensión del archivo determina el formato del archivo. Si ingresa una extensión de archivo no admitida por el algoritmo, se utilizará el formato de archivo predeterminado para ese tipo de salida y su extensión correspondiente se agregará a la ruta de archivo dada.

A diferencia de cuando se ejecuta un algoritmo desde la caja de herramientas, las salidas no se agregan al lienzo del mapa si ejecuta ese mismo algoritmo desde la consola de Python usando run(), pero runAndLoadResults() hará eso.

El método run() devuelve un diccionario con uno o más nombres de salida (los que se muestran en la descripción del algoritmo) como claves y las rutas de archivo de esas salidas como valores:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
 >>> myresult = processing.run("native:buffer", {'INPUT': '/data/lines.shp',
               'DISTANCE': 100.0,
               'SEGMENTS': 10,
               'DISSOLVE': True,
               'END_CAP_STYLE': 0,
               'JOIN_STYLE': 0,
               'MITER_LIMIT': 10,
               'OUTPUT': '/data/buffers.shp'})
 >>> myresult['OUTPUT']
 /data/buffers.shp

Puede cargar la salida de la función pasando las rutas de archivo correspondientes al método load(). O puede usar runAndLoadResults() en lugar de run() para cargarlos inmediatamente.

Si desea abrir un diálogo de algoritmo desde la consola, puede usar el método createAlgorithmDialog. El único parámetro obligatorio es el nombre del algoritmo, pero también puedes definir el diccionario de parámetros para que el diálogo se llene automáticamente:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
 >>> my_dialog = processing.createAlgorithmDialog("native:buffer", {
               'INPUT': '/data/lines.shp',
               'DISTANCE': 100.0,
               'SEGMENTS': 10,
               'DISSOLVE': True,
               'END_CAP_STYLE': 0,
               'JOIN_STYLE': 0,
               'MITER_LIMIT': 10,
               'OUTPUT': '/data/buffers.shp'})
 >>> my_dialog.show()

El método execAlgorithmDialog abre el diálogo inmediatamente:

1
2
3
4
5
6
7
8
9
 >>> processing.execAlgorithmDialog("native:buffer", {
               'INPUT': '/data/lines.shp',
               'DISTANCE': 100.0,
               'SEGMENTS': 10,
               'DISSOLVE': True,
               'END_CAP_STYLE': 0,
               'JOIN_STYLE': 0,
               'MITER_LIMIT': 10,
               'OUTPUT': '/data/buffers.shp'})

23.7.2. Crear scripts y ejecurarlos desde le Caja de Herramientas

Puede crear sus propios algoritmos escribiendo código Python. Los scripts de procesamiento extienden QgsProcessingAlgorithm, por lo que necesita agregar algunas líneas adicionales de código para implementar funciones obligatorias. Puede encontrar Create new script (hoja limpia) y Create New Script from Template (plantilla que incluye código para funciones obligatorias de QgsProcessingAlgorithm) en el menú desplegable Scripts desplegable en la parte superior de la caja de herramientas de Procesamiento. Se abrirá Processing Script Editor, y ahí es donde debe escribir su código. Guardar el script desde allí en la carpeta scripts (la carpeta predeterminada cuando abre el cuadro de diálogo para guardar el archivo) con una extensión .py debería crear el algoritmo correspondiente.

El nombre del algoritmo (el que verá en la caja de herramientas) se define dentro del código.

Echemos un vistazo al siguiente código, que define un algoritmo de procesamiento que realiza una operación de búfer con una distancia de búfer definida por el usuario en una capa vectorial especificada por el usuario, después de suavizar primero la capa.

 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
from qgis.core import (QgsProcessingAlgorithm,
       QgsProcessingParameterNumber,
       QgsProcessingParameterFeatureSource,
       QgsProcessingParameterFeatureSink)

from qgis import processing

class algTest(QgsProcessingAlgorithm):
    INPUT_BUFFERDIST = 'BUFFERDIST'
    OUTPUT_BUFFER = 'OUTPUT_BUFFER'
    INPUT_VECTOR = 'INPUT_VECTOR'

    def __init__(self):
        super().__init__()

    def name(self):
        return "algTest"

    def displayName(self):
        return "algTest script"

    def createInstance(self):
        return type(self)()

    def initAlgorithm(self, config=None):
        self.addParameter(QgsProcessingParameterFeatureSource(
            self.INPUT_VECTOR, "Input vector"))
        self.addParameter(QgsProcessingParameterNumber(
            self.INPUT_BUFFERDIST, "Buffer distance",
            QgsProcessingParameterNumber.Double,
            100.0))
        self.addParameter(QgsProcessingParameterFeatureSink(
            self.OUTPUT_BUFFER, "Output buffer"))

    def processAlgorithm(self, parameters, context, feedback):
        #DO SOMETHING
        algresult = processing.run("native:smoothgeometry",
            {'INPUT': parameters[self.INPUT_VECTOR],
             'ITERATIONS':2,
             'OFFSET':0.25,
             'MAX_ANGLE':180,
             'OUTPUT': 'memory:'},
            context=context, feedback=feedback, is_child_algorithm=True)
        smoothed = algresult['OUTPUT']
        algresult = processing.run('native:buffer',
            {'INPUT': smoothed,
            'DISTANCE': parameters[self.INPUT_BUFFERDIST],
            'SEGMENTS': 5,
            'END_CAP_STYLE': 0,
            'JOIN_STYLE': 0,
            'MITER_LIMIT': 10,
            'DISSOLVE': True,
            'OUTPUT': parameters[self.OUTPUT_BUFFER]},
            context=context, feedback=feedback, is_child_algorithm=True)
        buffered = algresult['OUTPUT']
        return {self.OUTPUT_BUFFER: buffered}

Después de hacer las importaciones necesarias, las siguientes funciones QgsProcessingAlgorithm son especificadas:

  • name(): La id del algoritmo (minúsculas).

  • displayName(): Un nombre de algoritmo legible por humanos

  • createInstance(): Crear una nueva instancia de la clase del algoritmo.

  • initAlgorithm(): Comfigurar las definiciones de Parámetro y Definiciones de Salida.

    Aquí describe los parámetros y la salida del algoritmo. En este caso, una fuente de objetos para la entrada, una salida de objetos para el resultado y un número para la distancia del búfer.

  • processAlgorithm(): Hacer el trabajo.

    Aquí primero ejecutamos el algoritmo de smoothgeometry para suavizar la geometría, y luego ejecutamos el algoritmo de buffer en la salida suavizada. Para poder ejecutar algoritmos desde otro algoritmo, debemos establecer el argumento is_child_algorithm en True. Puede ver cómo los parámetros de entrada y salida se utilizan como parámetros para los algoritmos smoothgeometry y buffer.

Hay varios tipos de parámetros diferentes disponibles para entrada y salida. A continuación se muestra una lista ordenada alfabéticamente:

El primer parámetro para los constructores es el nombre del parámetro y el segundo es la descripción del parámetro (para la interfaz de usuario). El resto de los parámetros del constructor son específicos del tipo de parámetro.

La entrada se puede convertir en clases QGIS usando las funciones parameterAs de QgsProcessingAlgorithm. Por ejemplo, para obtener el número proporcionado para la distancia del búfer como un doble:

self.parameterAsDouble(parameters, self.INPUT_BUFFERDIST, context)).

La función processAlgorithm debe devolver un diccionario que contenga valores para cada salida definida por el algoritmo. Esto permite el acceso a estas salidas de otros algoritmos, incluidos otros algoritmos contenidos dentro del mismo modelo.

Los algoritmos que se comportan bien deben definir y devolver tantas salidas como tenga sentido. Las salidas que no son objetos, como números y cadenas, son muy útiles cuando se ejecuta su algoritmo como parte de un modelo más grande, ya que estos valores se pueden usar como parámetros de entrada para algoritmos posteriores dentro del modelo. Considere agregar salidas numéricas para cosas como la cantidad de objetos procesados, la cantidad de objetos no válidos encontrados, la cantidad de objetos de salida, etc. ¡Cuantas más salidas devuelva, más útil se volverá su algoritmo!

23.7.2.1. Revisión

El objeto feedback pasado a processAlgorithm() debe usarse para la retroalimentación / interacción del usuario. Puede usar la función setProgress() del objeto feedback para actualizar la barra de progreso (0 a 100) para informar el usuario sobre el progreso del algoritmo. Esto es muy útil si su algoritmo tarda mucho en completarse.

El objeto feedback proporciona un método isCanceled() que debe ser monitoreado para permitir la cancelación del algoritmo por parte del usuario. El pushInfo() método de feedback se puede utilizar para enviar información al usuario, y :meth:`reportError( ) <qgis.core.QgsProcessingFeedback.reportError> `es útil para enviar errores no fatales a los usuarios.

Los algoritmos deben evitar el uso de otras formas de proporcionar retroalimentación a los usuarios, como declaraciones de impresión o registro en QgsMessageLog, y siempre deben usar el objeto de retroalimentación en su lugar. Esto permite un registro detallado para el algoritmo y también es seguro para subprocesos (lo cual es importante, dado que los algoritmos generalmente se ejecutan en un subproceso en segundo plano).

23.7.2.2. Manejo de errores

Si su algoritmo encuentra un error que le impide ejecutarse, como valores de entrada no válidos o alguna otra condición de la que no puede o no debe recuperarse, entonces debe generar un QgsProcessingException. P.Ejemplo

if feature['value'] < 20:
  raise QgsProcessingException('Invalid input value {}, must be >= 20'.format(feature['value']))

Trate de evitar generar QgsProcessingException para errores no fatales (por ejemplo, cuando un objeto tiene una geometría nula) y, en su lugar, solo informe estos errores a través de feedback.reportError() y omita la función. Esto ayuda a que su algoritmo sea «compatible con el modelo», ya que evita detener la ejecución de un algoritmo completo cuando se encuentra un error no fatal.

23.7.2.3. Documentación de las secuencias de comandos

Como en el caso de los modelos, puede crear documentación adicional para sus scripts, para explicar qué hacen y cómo usarlos.

QgsProcessingAlgorithm proporciona las funciones helpString(), shortHelpString() y helpUrl() para ese propósito. Especificar / suplantar estos para proporcionar mas ayuda al usuario.

shortDescription() se utiliza en la información sobre herramientas al pasar el cursor sobre el algoritmo en la caja de herramientas.

23.7.3. Pre y post-ejecución de la secuencia de comandos hooks

Los scripts también se pueden utilizar como ganchos previos y posteriores a la ejecución que se ejecutan antes y después de la ejecución de un algoritmo, respectivamente. Esto se puede utilizar para automatizar tareas que deben realizarse cada vez que se ejecuta un algoritmo.

La sintaxis es idéntica a la que se ha explicado anteriormente, pero una variable global adicional llamada alg está disponible, lo que representa el algoritmo que acaba de ser (o está a punto de ser) ejecutado.

En el grupo General del cuadro de diálogo de opciones de procesamiento, encontrará dos entradas denominadas Pre-execution script y Post-execution script donde se pueden introducir los nombres de archivo de los scripts a ejecutar en cada caso.