26.9. 将新的处理算法编写为Python脚本

使用Python编写处理算法有两种选择。

在QGIS中,您可以使用 Create new scriptScripts 菜单的顶部 Processing Toolbox 要打开 Processing Script Editor 您可以在其中编写代码。为了简化任务,您可以从脚本模板开始,方法是使用 Create new script from template 来自同一菜单的。这将打开一个扩展的模板 QgsProcessingAlgorithm

如果将脚本保存在 scripts (默认位置) .py 扩展后,该算法将在 Processing Toolbox

26.9.1. 扩展QgsProcessing算法

以下代码

  1. 将向量图层作为输入

  2. 统计要素的数量

  3. 是否执行缓冲操作

  4. 根据缓冲区操作的结果创建栅格图层

  5. 返回缓冲区图层、栅格图层和要素数

  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}

处理算法标准函数:

  • CreateInstance(必填)

    必须返回算法的新副本。如果您更改了类的名称,请确保您也更新了此处返回的值以匹配!

  • 名称(必填)

    返回唯一的算法名称,用于标识算法。

  • DisplayName(必填)

    返回转换后的算法名称。

  • 群组

    返回此算法所属的组的名称。

  • 组ID

    返回此算法所属组的唯一ID。

  • 短帮助字符串

    返回算法的本地化简短帮助字符串。

  • 初始算法(必需)

    这里我们定义了算法的输入和输出。

    INPUTOUTPUT 分别是主输入参数和主输出参数的推荐名称。

    如果一个参数依赖于另一个参数, parentParameterName 用于指定此关系(可以是层的字段/标注栏或层的距离单位)。

  • 处理算法(必需)

    这就是处理过程发生的地方。

    例如,使用特殊目的函数来检索参数 parameterAsSourceparameterAsDouble

    processing.run 可以用来从一个处理算法运行其他处理算法。第一个参数是算法的名称,第二个参数是算法参数的字典。 is_child_algorithm 通常设置为 True 当从另一个算法中运行一个算法时。 contextfeedback 告知算法要在其中运行的环境和与用户通信的通道(捕获取消请求、报告进度、提供文本反馈)。当使用(父)算法的参数作为“子”算法的参数时,应使用原始参数值(例如 parameters['OUTPUT'] )。

    尽可能多地检查反馈对象的取消是一种良好的做法!这样做允许响应取消,而不是强迫用户等待不需要的处理发生。

    该算法应该返回它定义为字典的所有输出参数的值。在本例中,这是缓冲区和栅格化输出图层,以及处理的要素计数。字典键必须与原始参数/输出名称匹配。

26.9.2. @alg装饰师

使用@alg修饰符,您可以通过编写Python代码并添加几行额外的代码来创建您自己的算法,以提供使其成为正确的处理算法所需的附加信息。这简化了算法的创建以及输入和输出的规范。

修饰器方法的一个重要限制是,以这种方式创建的算法将始终添加到用户的处理脚本提供程序中--不可能将这些算法添加到自定义提供程序中,例如用于插件中。

以下代码使用@alg修饰符

  1. 使用向量层作为输入

  2. 统计要素的数量

  3. 执行缓冲操作

  4. 根据缓冲区操作的结果创建栅格图层

  5. 返回缓冲区图层、栅格图层和要素数

 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}

如您所见,它涉及两种算法(‘Native:Buffer’和‘qgis:rasterize’)。最后一个(‘qgis:rasterize’)从第一个(‘ative:Buffer’)生成的缓冲层创建一个栅格层。

如果您已经阅读了上一章,那么代码中进行此处理的部分并不难理解。然而,第一行需要一些额外的解释。它们提供了将代码转换为算法所需的信息,该算法可以从任何图形用户界面组件(如工具箱或模型设计器)运行。

这些线路都是对 @alg 帮助简化算法编码的修饰符函数。

  • @alg修饰符用于定义算法在工具箱中的名称和位置。

  • @alg.input修饰符用于定义算法的输入。

  • @alg.out修饰符用于定义算法的输出。

26.9.3. 用于处理算法的输入和输出类型

以下是使用其对应的alg修饰符常量( algfactory.py 文件包含ALG常量的完整列表)。按类名排序。

26.9.3.1. 输入类型

班级

ALG常量

描述

QgsProcessingParameterAnnotationLayer

alg.ANNOTATION_LAYER

注释层

QgsProcessingParameterAuthConfig

alg.AUTH_CFG

允许用户从可用的身份验证配置中进行选择或创建新的身份验证配置

QgsProcessingParameterBand

alg.BAND

栅格图层的波段

QgsProcessingParameterBoolean

alg.BOOL

布尔值

QgsProcessingParameterColor

alg.COLOR

一种颜色

QgsProcessingParameterCoordinateOperation

alg.COORDINATE_OPERATION

坐标操作(用于CRS转换)

QgsProcessingParameterCrs

alg.CRS

坐标参考系

QgsProcessingParameterDatabaseSchema

alg.DATABASE_SCHEMA

数据库架构

QgsProcessingParameterDatabaseTable

alg.DATABASE_TABLE

数据库表

QgsProcessingParameterDateTime

alg.DATETIME

日期时间(或纯日期或时间)

QgsProcessingParameterDistance

alg.DISTANCE

距离值的双精度数值参数

QgsProcessingParameterEnum

alg.ENUM

一个枚举,允许从一组预定义的值中进行选择

QgsProcessingParameterExpression

alg.EXPRESSION

一种表达

QgsProcessingParameterExtent

alg.EXTENT

由xmin、xmax、ymin、ymax定义的空间范围

QgsProcessingParameterField

alg.FIELD

矢量图层属性表中的字段

QgsProcessingParameterFile

alg.FILE

现有文件的文件名

QgsProcessingParameterFileDestination

alg.FILE_DEST

新创建的输出文件的文件名

QgsProcessingParameterFolderDestination

alg.FOLDER_DEST

文件夹(目标文件夹)

QgsProcessingParameterGeometry

alg.GEOMETRY

一个几何体

QgsProcessingParameterNumber

alg.INT

一个整数

QgsProcessingParameterLayout

alg.LAYOUT

一种布局

QgsProcessingParameterLayoutItem

alg.LAYOUT_ITEM

布局项目

QgsProcessingParameterMapLayer

alg.MAPLAYER

地图层

QgsProcessingParameterMapTheme

alg.MAP_THEME

项目地图主题

QgsProcessingParameterMatrix

alg.MATRIX

一个矩阵

QgsProcessingParameterMeshLayer

alg.MESH_LAYER

网格层

QgsProcessingParameterMultipleLayers

alg.MULTILAYER

一组层

QgsProcessingParameterNumber

alg.NUMBER

一个数值

QgsProcessingParameterPoint

alg.POINT

一分

QgsProcessingParameterPointCloudDestination

alg.POINTCLOUD_LAYER_DEST

点云图层目标参数,用于指定算法创建的点云图层的目标路径

QgsProcessingParameterPointCloudLayer

alg.POINTCLOUD_LAYER

点云图层

QgsProcessingParameterProviderConnection

alg.PROVIDER_CONNECTION

数据库提供程序的可用连接

QgsProcessingParameterRange

alg.RANGE

一个数字范围

QgsProcessingParameterRasterLayer

alg.RASTER_LAYER

栅格层

QgsProcessingParameterRasterDestination

alg.RASTER_LAYER_DEST

栅格图层目标参数,用于指定算法创建的栅格图层的目标路径

QgsProcessingParameterScale

alg.SCALE

地图比例尺

QgsProcessingParameterFeatureSink

alg.SINK

要素接收器

QgsProcessingParameterFeatureSource

alg.SOURCE

要素源

QgsProcessingParameterString

alg.STRING

文本字符串

QgsProcessingParameterVectorLayer

alg.VECTOR_LAYER

矢量层

QgsProcessingParameterVectorDestination

alg.VECTOR_LAYER_DEST

矢量图层目标参数,用于指定算法创建的矢量图层的目标路径

QgsProcessingParameterVectorTileDestination

矢量切片图层目标参数,用于指定算法创建的矢量切片图层的目标路径

26.9.3.2. 输出类型

班级

ALG常量

描述

QgsProcessingOutputBoolean

alg.BOOL

布尔值

QgsProcessingOutputNumber

alg.DISTANCE

距离值的双精度数值参数

QgsProcessingOutputFile

alg.FILE

现有文件的文件名

QgsProcessingOutputFolder

alg.FOLDER

一个文件夹

QgsProcessingOutputHtml

alg.HTML

HTML

QgsProcessingOutputNumber

alg.INT

一个整数

QgsProcessingOutputLayerDefinition

alg.LAYERDEF

层定义

QgsProcessingOutputMapLayer

alg.MAPLAYER

地图层

QgsProcessingOutputMultipleLayers

alg.MULTILAYER

一组层

QgsProcessingOutputNumber

alg.NUMBER

一个数值

QgsProcessingOutputPointCloudLayer

alg.POINTCLOUD_LAYER

点云图层

QgsProcessingOutputRasterLayer

alg.RASTER_LAYER

栅格层

QgsProcessingOutputString

alg.STRING

文本字符串

QgsProcessingOutputVectorLayer

alg.VECTOR_LAYER

矢量层

QgsProcessingOutputVectorTileLayer

向量分片层

26.9.4. 处理算法输出

当您声明表示层(栅格或矢量)的输出时,算法将尝试在完成后将其添加到QGIS中。

  • 栅格图层输出:QgsProcessing参数RasterDestination/alg.RASTER_LAYER_DEST。

  • 向量层输出:QgsProcessing参数向量目标/alg.VECTOR_LAYER_DEST。

因此,即使 processing.run() 方法不会将其创建的层添加到用户的当前项目中,则将加载两个输出层(缓冲区和栅格缓冲区),因为它们被保存到用户输入的目标(如果用户未指定目标,则保存到临时目标)。

如果层是作为算法的输出创建的,则应将其声明为输出。否则,您将无法在建模器中正确使用算法,因为声明的内容与算法实际创建的内容不匹配。

您可以通过在结果字典中指定字符串、数字等来返回它们(如“NUMBEROFFEATURES”所示),但它们应该始终被显式定义为您的算法的输出。我们鼓励算法输出尽可能多的有用的值,因为当您的算法用作模型的一部分时,这些值对于以后的算法很有价值。

26.9.5. 与用户通信

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.

可以使用两种方法更新进度文本和进度栏: setProgressText(text)setProgress(percent)

您可以使用以下命令提供更多信息 pushCommandInfo(text)pushDebugInfo(text)pushInfo(text)reportError(text)

如果您的脚本有问题,正确的处理方法是引发 QgsProcessingException 。您可以将消息作为参数传递给异常的构造函数。处理将负责处理它并与用户通信,具体取决于执行算法的位置(工具箱、建模器、Python控制台等)

26.9.6. 记录您的脚本

您可以通过重载 helpString()helpUrl() 方法: QgsProcessingAlgorithm

26.9.7. 旗子

您可以重写 flags() 方法论 QgsProcessingAlgorithm 告诉QGIS更多关于您的算法的信息。例如,您可以告诉QGIS,脚本应该对建模器隐藏,可以取消,它不是线程安全的,等等。

小技巧

默认情况下,处理在单独的线程中运行算法,以便在处理任务运行时保持QGIS响应。如果您的算法经常崩溃,您可能正在使用在后台线程中执行的不安全的API调用。尝试从您的算法标志()方法中返回QgsProcessingAlgorithm.FlagNoThread标志,以强制处理在主线程中运行您的算法。

26.9.8. 编写脚本算法的最佳实践

以下是创建脚本算法时需要考虑的想法的快速总结,特别是如果您想要与其他QGIS用户分享这些想法的话。遵循这些简单的规则将确保不同处理元素(如工具箱、建模器或批处理接口)之间的一致性。

  • 不加载生成的层。如果需要,让处理程序处理您的结果并加载您的层。

  • 始终声明您的算法创建的输出。

  • 不要显示消息框或使用脚本中的任何图形用户界面元素。如果要与用户通信,请使用反馈对象的方法 (QgsProcessingFeedback )或抛出 QgsProcessingException

QGIS中已经有了许多可用的处理算法。您可以在 QGIS 回购。