26.9. 将新的处理算法编写为Python脚本
使用Python编写处理算法有两种选择。
在QGIS中,您可以使用 Create new script 在 Scripts 菜单的顶部 Processing Toolbox 要打开 Processing Script Editor 您可以在其中编写代码。为了简化任务,您可以从脚本模板开始,方法是使用 Create new script from template 来自同一菜单的。这将打开一个扩展的模板 QgsProcessingAlgorithm
。
如果将脚本保存在 scripts
(默认位置) .py
扩展后,该算法将在 Processing Toolbox 。
26.9.1. 扩展QgsProcessing算法
以下代码
将向量图层作为输入
统计要素的数量
是否执行缓冲操作
根据缓冲区操作的结果创建栅格图层
返回缓冲区图层、栅格图层和要素数
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。
- 短帮助字符串
返回算法的本地化简短帮助字符串。
- 初始算法(必需)
这里我们定义了算法的输入和输出。
INPUT
和OUTPUT
分别是主输入参数和主输出参数的推荐名称。如果一个参数依赖于另一个参数,
parentParameterName
用于指定此关系(可以是层的字段/标注栏或层的距离单位)。
- 处理算法(必需)
这就是处理过程发生的地方。
例如,使用特殊目的函数来检索参数
parameterAsSource
和parameterAsDouble
。processing.run
可以用来从一个处理算法运行其他处理算法。第一个参数是算法的名称,第二个参数是算法参数的字典。is_child_algorithm
通常设置为True
当从另一个算法中运行一个算法时。context
和feedback
告知算法要在其中运行的环境和与用户通信的通道(捕获取消请求、报告进度、提供文本反馈)。当使用(父)算法的参数作为“子”算法的参数时,应使用原始参数值(例如parameters['OUTPUT']
)。尽可能多地检查反馈对象的取消是一种良好的做法!这样做允许响应取消,而不是强迫用户等待不需要的处理发生。
该算法应该返回它定义为字典的所有输出参数的值。在本例中,这是缓冲区和栅格化输出图层,以及处理的要素计数。字典键必须与原始参数/输出名称匹配。
26.9.2. @alg装饰师
使用@alg修饰符,您可以通过编写Python代码并添加几行额外的代码来创建您自己的算法,以提供使其成为正确的处理算法所需的附加信息。这简化了算法的创建以及输入和输出的规范。
修饰器方法的一个重要限制是,以这种方式创建的算法将始终添加到用户的处理脚本提供程序中--不可能将这些算法添加到自定义提供程序中,例如用于插件中。
以下代码使用@alg修饰符
使用向量层作为输入
统计要素的数量
执行缓冲操作
根据缓冲区操作的结果创建栅格图层
返回缓冲区图层、栅格图层和要素数
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常量 |
描述 |
---|---|---|
|
注释层 |
|
|
允许用户从可用的身份验证配置中进行选择或创建新的身份验证配置 |
|
|
栅格图层的波段 |
|
|
布尔值 |
|
|
一种颜色 |
|
|
坐标操作(用于CRS转换) |
|
|
坐标参考系 |
|
|
数据库架构 |
|
|
数据库表 |
|
|
日期时间(或纯日期或时间) |
|
|
距离值的双精度数值参数 |
|
|
一个枚举,允许从一组预定义的值中进行选择 |
|
|
一种表达 |
|
|
由xmin、xmax、ymin、ymax定义的空间范围 |
|
|
矢量图层属性表中的字段 |
|
|
现有文件的文件名 |
|
|
新创建的输出文件的文件名 |
|
|
文件夹(目标文件夹) |
|
|
一个几何体 |
|
|
一个整数 |
|
|
一种布局 |
|
|
布局项目 |
|
|
地图层 |
|
|
项目地图主题 |
|
|
一个矩阵 |
|
|
网格层 |
|
|
一组层 |
|
|
一个数值 |
|
|
一分 |
|
|
点云图层目标参数,用于指定算法创建的点云图层的目标路径 |
|
|
点云图层 |
|
|
数据库提供程序的可用连接 |
|
|
一个数字范围 |
|
|
栅格层 |
|
|
栅格图层目标参数,用于指定算法创建的栅格图层的目标路径 |
|
|
地图比例尺 |
|
|
要素接收器 |
|
|
要素源 |
|
|
文本字符串 |
|
|
矢量层 |
|
|
矢量图层目标参数,用于指定算法创建的矢量图层的目标路径 |
|
矢量切片图层目标参数,用于指定算法创建的矢量切片图层的目标路径 |
26.9.3.2. 输出类型
班级 |
ALG常量 |
描述 |
---|---|---|
|
布尔值 |
|
|
距离值的双精度数值参数 |
|
|
现有文件的文件名 |
|
|
一个文件夹 |
|
|
HTML |
|
|
一个整数 |
|
|
层定义 |
|
|
地图层 |
|
|
一组层 |
|
|
一个数值 |
|
|
点云图层 |
|
|
栅格层 |
|
|
文本字符串 |
|
|
矢量层 |
|
向量分片层 |
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 回购。