26.9. Escrevendo novos algoritmos de Processamento como scripts Python

Existem duas opções para escrever algoritmos de Processamento usando Python.

Within QGIS, you can use Create new script in the Scripts menu at the top of the Processing Toolbox to open the Processing Script Editor where you can write your code. To simplify the task, you can start with a script template by using Create new script from template from the same menu. This opens a template that extends QgsProcessingAlgorithm.

If you save the script in the scripts folder (the default location) with a .py extension, the algorithm will become available in the Processing Toolbox.

26.9.1. Extending QgsProcessingAlgorithm

O seguinte código

  1. recebe uma camada vetorial como entrada

  2. conta o número de feições

  3. faz uma operação de buffer

  4. cria uma camada raster a partir do resultado da operação do buffer

  5. retorna a camada de buffer, a camada raster e o número de feições

  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}

Funções padrão do algoritmo de processamento:

  • createInstance (mandatory)

    Deve retornar uma nova cópia do seu algoritmo. Se você alterar o nome da classe, certifique-se de atualizar também o valor retornado aqui para corresponder!

  • nome (obrigatório)

    Retorna o nome exclusivo do algoritmo, usado para identificar o algoritmo.

  • displayName (mandatory)

    Retorna o nome do algoritmo traduzido.

  • grupo

    Retorna o nome do grupo ao qual este algoritmo pertence.

  • groupId

    Retorna o ID único do grupo ao qual este algoritmo pertence.

  • shortHelpString

    Returns a localised short help string for the algorithm.

  • initAlgorithm (mandatory)

    Aqui definimos as entradas e saídas do algoritmo.

    INPUT and OUTPUT are recommended names for the main input and main output parameters, respectively.

    If a parameter depends on another parameter, parentParameterName is used to specify this relationship (could be the field / band of a layer or the distance units of a layer).

  • processAlgorithm (mandatory)

    É onde ocorre o processamento.

    Parameters are retrieved using special purpose functions, for instance parameterAsSource and parameterAsDouble.

    processing.run can be used to run other processing algorithms from a processing algorithm. The first parameter is the name of the algorithm, the second is a dictionary of the parameters to the algorithm. is_child_algorithm is normally set to True when running an algorithm from within another algorithm. context and feedback inform the algorithm about the environment to run in and the channel for communicating with the user (catching cancel request, reporting progress, providing textual feedback). When using the (parent) algorithm’s parameters as parameters to “child” algorithms, the original parameter values should be used (e.g. parameters['OUTPUT']).

    It is good practice to check the feedback object for cancelation as much as is sensibly possible! Doing so allows for responsive cancelation, instead of forcing users to wait for unwanted processing to occur.

    The algorithm should return values for all the output parameters it has defined as a dictionary. In this case, that’s the buffer and rasterized output layers, and the count of features processed. The dictionary keys must match the original parameter/output names.

26.9.2. The @alg decorator

Using the @alg decorator, you can create your own algorithms by writing the Python code and adding a few extra lines to supply additional information needed to make it a proper Processing algorithm. This simplifies the creation of algorithms and the specification of inputs and outputs.

One important limitation with the decorator approach is that algorithms created in this way will always be added to a user’s Processing Scripts provider – it is not possible to add these algorithms to a custom provider, e.g. for use in plugins.

The following code uses the @alg decorator to

  1. usar uma camada vetorial como entrada

  2. contar o número de feições

  3. fazer uma operação de buffer

  4. criar uma camada raster a partir do resultado da operação do buffer

  5. retorna a camada de buffer, a camada raster e o número de feições

 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}

As you can see, it involves two algorithms (‘native:buffer’ and ‘qgis:rasterize’). The last one (‘qgis:rasterize’) creates a raster layer from the buffer layer that was generated by the first one (‘native:buffer’).

The part of the code where this processing takes place is not difficult to understand if you have read the previous chapter. The first lines, however, need some additional explanation. They provide the information that is needed to turn your code into an algorithm that can be run from any of the GUI components, like the toolbox or the graphical modeler.

These lines are all calls to the @alg decorator functions that help simplify the coding of the algorithm.

  • The @alg decorator is used to define the name and location of the algorithm in the Toolbox.

  • The @alg.input decorator is used to define the inputs of the algorithm.

  • The @alg.output decorator is used to define the outputs of the algorithm.

26.9.3. Tipos de entrada e saída para Algoritmos de Processamento

Aqui está a lista dos tipos de entrada e saída que são suportados no processamento com suas constantes de decoração de algoritmos (o arquivo :fonte:`algfactory.py <python/processing/algfactory.py>` contém a lista completa de constantes de algoritmos). Classificado no nome da classe.

26.9.3.1. Tipos de entrada

Classes

Alg constant

Descrição

QgsProcessingParameterAnnotationLayer

alg.CAMADA_ANOTACAO`

Uma camada de texto

QgsProcessingParameterAuthConfig

alg.AUTH_CFG

Permite que os usuários selecionem entre as configurações de autenticação disponíveis ou criem novas configurações de autenticação

QgsProcessingParameterBand

alg.BAND

Uma banda de uma camada raster

QgsProcessingParameterBoolean

alg.BOOL

Um valor booleano

QgsProcessingParameterColor

alg.COLOR

Uma cor

QgsProcessingParameterCoordinateOperation

alg.COORDINATE_OPERATION

Uma operação de coordenadas (para transformações SRC)

QgsProcessingParameterCrs

alg.CRS

Um Sistema de Referência de Coordenadas

QgsProcessingParameterDatabaseSchema

alg.DATABASE_SCHEMA

A database schema

QgsProcessingParameterDatabaseTable

alg.DATABASE_TABLE

A database table

QgsProcessingParameterDateTime

alg.DATETIME

A datetime (or a pure date or time)

QgsProcessingParameterDistance

alg.DISTANCE

Um parâmetro numérico duplo para valores de distância

QgsProcessingParameterEnum

alg.ENUM

Uma enumeração, permitindo a seleção de um conjunto de valores predefinidos

QgsProcessingParameterExpression

alg.EXPRESSÃO

Uma expressão

QgsProcessingParameterExtent

alg.EXTENSÃO

Uma extensão espacial definida por xmin, xmax, ymin, ymax

QgsProcessingParameterField

alg.CAMPO

Um campo na tabela de atributos de uma camada vetorial

QgsProcessingParameterFile

alg.FILE

Um nome de arquivo de um arquivo existente

QgsProcessingParameterFileDestination

alg.FILE_DEST

Um nome de arquivo para um arquivo de saída recém-criado

QgsProcessingParameterFolderDestination

alg.FOLDER_DEST

Uma pasta (pasta de destino)

QgsProcessingParameterGeometry

alg.GEOMETRIA

Uma geometria

QgsProcessingParameterNumber

alg.INT

Um número inteiro

QgsProcessingParameterLayout

alg.LAYOUT

Um layout

QgsProcessingParameterLayoutItem

alg.LAYOUT_ITEM

Um item de layout

QgsProcessingParameterMapLayer

alg.MAPLAYER

Uma camada do mapa

QgsProcessingParameterMapTheme

alg.MAP_THEME

A project map theme

QgsProcessingParameterMatrix

alg.MATRIX

Uma matriz

QgsProcessingParameterMeshLayer

alg.MESH_LAYER

Uma camada de malha

QgsProcessingParameterMultipleLayers

alg.MULTILAYER

A set of layers

QgsProcessingParameterNumber

alg.NUMBER

Um valor numérico

QgsProcessingParameterPoint

alg.POINT

Um ponto

QgsProcessingParameterPointCloudDestination

alg.POINTCLOUD_LAYER_DEST

A point cloud layer destination parameter, for specifying the destination path for a point cloud layer created by the algorithm

QgsProcessingParameterPointCloudLayer

alg.POINTCLOUD_LAYER

Uma camada de nuvens de pontos

QgsProcessingParameterProviderConnection

alg.PROVIDER_CONNECTION

An available connection for a database provider

QgsProcessingParameterRange

alg.RANGE

Um intervalo de números

QgsProcessingParameterRasterLayer

alg.RASTER_LAYER

Uma camada raster

QgsProcessingParameterRasterDestination

alg.RASTER_LAYER_DEST

A raster layer destination parameter, for specifying the destination path for a raster layer created by the algorithm

QgsProcessingParameterScale

alg.SCALE

Uma escala do mapa

QgsProcessingParameterFeatureSink

alg.SINK

A feature sink

QgsProcessingParameterFeatureSource

alg.SOURCE

A feature source

QgsProcessingParameterString

alg.STRING

A text string

QgsProcessingParameterVectorLayer

alg.VECTOR_LAYER

Uma camada vetorial

QgsProcessingParameterVectorDestination

alg.VECTOR_LAYER_DEST

A vector layer destination parameter, for specifying the destination path for a vector layer created by the algorithm

26.9.3.2. Tipos de saída

Classes

Alg constant

Descrição

QgsProcessingOutputBoolean

alg.BOOL

Um valor booleano

QgsProcessingOutputNumber

alg.DISTANCE

Um parâmetro numérico duplo para valores de distância

QgsProcessingOutputFile

alg.FILE

Um nome de arquivo de um arquivo existente

QgsProcessingOutputFolder

alg.FOLDER

Uma pasta

QgsProcessingOutputHtml

alg.HTML

HTML

QgsProcessingOutputNumber

alg.INT

Um número inteiro

QgsProcessingOutputLayerDefinition

alg.LAYERDEF

Uma definição de camada

QgsProcessingOutputMapLayer

alg.MAPLAYER

Uma camada do mapa

QgsProcessingOutputMultipleLayers

alg.MULTILAYER

A set of layers

QgsProcessingOutputNumber

alg.NUMBER

Um valor numérico

QgsProcessingOutputPointCloudLayer

alg.POINTCLOUD_LAYER

Uma camada de nuvens de pontos

QgsProcessingOutputRasterLayer

alg.RASTER_LAYER

Uma camada raster

QgsProcessingOutputString

alg.STRING

A text string

QgsProcessingOutputVectorLayer

alg.VECTOR_LAYER

Uma camada vetorial

26.9.4. Handing algorithm output

Quando você declara uma saída representando uma camada (raster ou vetor), o algoritmo tentará adicioná-la ao QGIS assim que terminar.

  • Raster layer output: QgsProcessingParameterRasterDestination / alg.RASTER_LAYER_DEST.

  • Vector layer output: QgsProcessingParameterVectorDestination / alg.VECTOR_LAYER_DEST.

So even if the processing.run() method does not add the layers it creates to the user’s current project, the two output layers (buffer and raster buffer) will be loaded, since they are saved to the destinations entered by the user (or to temporary destinations if the user does not specify destinations).

If a layer is created as output of an algorithm, it should be declared as such. Otherwise, you will not be able to properly use the algorithm in the modeler, since what is declared will not match what the algorithm really creates.

You can return strings, numbers and more by specifying them in the result dictionary (as demonstrated for “NUMBEROFFEATURES”), but they should always be explicitly defined as outputs from your algorithm. We encourage algorithms to output as many useful values as possible, since these can be valuable for use in later algorithms when your algorithm is used as part of a model.

26.9.5. Comunicação com o usuário

If your algorithm takes a long time to process, it is a good idea to inform the user about the progress. You can use feedback (QgsProcessingFeedback) for this.

The progress text and progressbar can be updated using two methods: setProgressText(text) and setProgress(percent).

You can provide more information by using pushCommandInfo(text), pushDebugInfo(text), pushInfo(text) and reportError(text).

If your script has a problem, the correct way of handling it is to raise a QgsProcessingException. You can pass a message as an argument to the constructor of the exception. Processing will take care of handling it and communicating with the user, depending on where the algorithm is being executed from (toolbox, modeler, Python console, …)

26.9.6. Documentando seus scripts

You can document your scripts by overloading the helpString() and helpUrl() methods of QgsProcessingAlgorithm.

26.9.7. Bandeiras

You can override the flags() method of QgsProcessingAlgorithm to tell QGIS more about your algorithm. You can for instance tell QGIS that the script shall be hidden from the modeler, that it can be canceled, that it is not thread safe, and more.

Dica

By default, Processing runs algorithms in a separate thread in order to keep QGIS responsive while the processing task runs. If your algorithm is regularly crashing, you are probably using API calls which are not safe to do in a background thread. Try returning the QgsProcessingAlgorithm.FlagNoThreading flag from your algorithm’s flags() method to force Processing to run your algorithm in the main thread instead.

26.9.8. Melhores práticas para algoritmos de script escrito

Here’s a quick summary of ideas to consider when creating your script algorithms and, especially, if you want to share them with other QGIS users. Following these simple rules will ensure consistency across the different Processing elements such as the toolbox, the modeler or the batch processing interface.

  • Não coloque resultados das camadas. Vamos trabalhar o Processamento com seus resultados e carregar suas camadas se necessárias.

  • Sempre declare as saídas que seu algoritmo cria.

  • Do not show message boxes or use any GUI element from the script. If you want to communicate with the user, use the methods of the feedback object (QgsProcessingFeedback) or throw a QgsProcessingException.

There are already many processing algorithms available in QGIS. You can find code on the QGIS repo.