Important

翻译是一项社区工作 you can join。此页面目前翻译进度为 100.00%。

23.7. 从控制台使用处理算法

控制台允许高级用户提升工作效率,并执行处理框架其他 GUI 元素无法完成的复杂操作。通过命令行接口可定义包含多个算法的模型,并添加循环、条件语句等额外操作,以创建更灵活、更强大的工作流。

QGIS 中没有独立的处理控制台,但所有处理命令均可通过 QGIS 内置的 Python 控制台 使用。这意味着您可以将这些命令集成到控制台工作中,并将处理算法与该环境中所有其他功能(包括 QGIS API 的方法)连接起来。

您在 Python 控制台中执行的代码,即使未调用任何特定的处理方法,也可以转换为一个新算法,之后可像使用其他算法一样,从工具箱、图形建模器或其他组件中调用它。事实上,工具箱中的一些算法就是简单的脚本。

在本节中,我们将学习如何从 QGIS Python 控制台使用处理算法,以及如何使用 Python 编写算法。

23.7.1. 从 Python 控制台调用算法

首先,您需要使用以下语句导入处理函数:

>>> from qgis import processing

现在,从控制台基本只能做一件(有趣)的事:执行算法。这是通过 run() 方法完成的,该方法以要执行的算法名称作为第一个参数,随后是根据算法需求而定的若干附加参数。因此,您首先需要知道要执行的算法名称。这并非工具箱中显示的名称,而是唯一的命令行名称。要查找算法的正确名称,可使用 processingRegistry。在控制台中输入以下代码:

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

您将看到类似以下内容(为提高可读性已添加额外横线):

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

这是所有可用算法 ID 的列表,按提供者名称和算法名称排序,并附带对应的名称。

一旦知道了算法的命令行名称,下一步就是确定执行它的正确语法,即了解调用 run() 方法时所需的参数。

有一个方法可详细描述算法,用于获取算法所需参数及其生成输出的列表。要获取此信息,可使用 algorithmHelp(id_of_the_algorithm) 方法。请使用算法的 ID,而非完整的描述性名称。

native:buffer 作为参数调用该方法(qgis:buffernative:buffer 的别名,同样有效),您将获得如下描述:

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

现在您已具备运行任意算法所需的一切。如前所述,可使用 run() 来运行算法。其语法如下:

>>> processing.run(name_of_the_algorithm, parameters)

其中 parameters 是一个参数字典,具体内容取决于您要运行的算法,且与 algorithmHelp() 方法给出的列表完全一致。

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

如果某个参数是可选的且您不想使用它,则不要将其包含在字典中。

如果未指定某个参数,则将使用其默认值。

根据参数类型不同,值的输入方式也不同。以下列表简要说明了各类输入参数的值输入方法:

  • 栅格图层、矢量图层或表:只需使用一个字符串,指定数据对象在 QGIS 图层面板中的名称,或使用文件路径(若对应图层未打开,将自动打开但不会添加到地图画布)。如果您已有代表该图层的 QGIS 对象实例,也可直接将其作为参数传入。

  • 枚举类型:若算法包含枚举参数,应使用整数值输入该参数。要了解可用选项,可使用上述的 algorithmHelp() 命令。例如,native:buffer 算法有一个名为 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
    

    本例中,该参数有三个选项。请注意,索引从 0 开始。

  • 布尔值:使用 TrueFalse

  • 多输入:值为一个字符串,各输入描述符以分号(;)分隔。与单图层或表类似,每个输入描述符可以是数据对象名称或其文件路径。

  • 来自 XXX 的表字段:使用字符串指定要使用的字段名称。此参数区分大小写。

  • 固定表格:输入所有表格值的列表,以逗号(,)分隔,并用引号(")括起。值从上行开始,从左到右排列。您也可以使用一个二维数组来表示该表格。

  • 坐标参考系(CRS):输入所需 CRS 的 EPSG 代码编号。

  • 范围(Extent):必须使用一个字符串,其中包含以逗号(,)分隔的 xminxmaxyminymax 值。

布尔值、文件、字符串和数值型参数无需额外说明。

字符串、布尔值或数值等输入参数具有默认值。若未提供相应参数,则使用默认值。

对于输出数据对象,请输入用于保存结果的文件路径,方式与工具箱中相同。若未指定输出对象,结果将保存到临时文件(若为可选输出则跳过)。文件扩展名决定文件格式。如果您输入了算法不支持的文件扩展名,将使用该输出类型的默认格式,并将对应扩展名附加到您提供的路径后。

与通过工具箱执行算法不同,若通过 Python 控制台使用 run() 方法执行算法,其输出不会自动添加到地图画布。该方法返回一个字典,键为一个或多个输出名称(即算法描述中所示名称),值为对应输出的文件路径:

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

随后,您可以像加载普通图层一样将输出加载到工程中:

1 >>> buffered_layer = myresult['OUTPUT']
2 >>> QgsProject.instance().addMapLayer(buffered_layer)

若要立即将处理结果加载到工程中,可使用 runAndLoadResults() 方法替代 run()

1 >>> processing.runAndLoadResults("native:buffer", {parameters:values})

若要从控制台打开算法对话框,可使用 createAlgorithmDialog 方法。唯一必需的参数是算法名称,但您也可以定义参数字典,以便自动填充对话框:

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

execAlgorithmDialog 方法会立即打开对话框:

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

23.7.2. 创建脚本并从工具箱运行

您可以通过编写 Python 代码创建自己的算法。处理脚本需继承 QgsProcessingAlgorithm,因此需添加若干额外代码以实现必需的函数。在 Processing 工具箱顶部的 Scripts 下拉菜单中,您可以找到 Create new script`(空白脚本)和 :guilabel:`Create New Script from Template`(包含 :class:`QgsProcessingAlgorithm <qgis.core.QgsProcessingAlgorithm> 必需函数代码的模板)。将打开 Processing 脚本编辑器,您应在其中编写代码。将脚本保存到 scripts 文件夹(打开保存文件对话框时的默认文件夹)并使用 .py 扩展名,即可生成对应的算法。

算法名称(即工具箱中显示的名称)需在代码中定义。

让我们看以下代码,它定义了一个处理算法:首先对用户指定的矢量图层进行平滑处理,然后以用户定义的缓冲距离执行缓冲操作。

 1from qgis.core import (QgsProcessingAlgorithm,
 2       QgsProcessingParameterNumber,
 3       QgsProcessingParameterFeatureSource,
 4       QgsProcessingParameterFeatureSink)
 5
 6from qgis import processing
 7
 8class algTest(QgsProcessingAlgorithm):
 9    INPUT_BUFFERDIST = 'BUFFERDIST'
10    OUTPUT_BUFFER = 'OUTPUT_BUFFER'
11    INPUT_VECTOR = 'INPUT_VECTOR'
12
13    def __init__(self):
14        super().__init__()
15
16    def name(self):
17        return "algTest"
18
19    def displayName(self):
20        return "algTest script"
21
22    def createInstance(self):
23        return type(self)()
24
25    def initAlgorithm(self, config=None):
26        self.addParameter(QgsProcessingParameterFeatureSource(
27            self.INPUT_VECTOR, "Input vector"))
28        self.addParameter(QgsProcessingParameterNumber(
29            self.INPUT_BUFFERDIST, "Buffer distance",
30            QgsProcessingParameterNumber.Double,
31            100.0))
32        self.addParameter(QgsProcessingParameterFeatureSink(
33            self.OUTPUT_BUFFER, "Output buffer"))
34
35    def processAlgorithm(self, parameters, context, feedback):
36        #DO SOMETHING
37        algresult = processing.run("native:smoothgeometry",
38            {'INPUT': parameters[self.INPUT_VECTOR],
39             'ITERATIONS':2,
40             'OFFSET':0.25,
41             'MAX_ANGLE':180,
42             'OUTPUT': 'memory:'},
43            context=context, feedback=feedback, is_child_algorithm=True)
44        smoothed = algresult['OUTPUT']
45        algresult = processing.run('native:buffer',
46            {'INPUT': smoothed,
47            'DISTANCE': parameters[self.INPUT_BUFFERDIST],
48            'SEGMENTS': 5,
49            'END_CAP_STYLE': 0,
50            'JOIN_STYLE': 0,
51            'MITER_LIMIT': 10,
52            'DISSOLVE': True,
53            'OUTPUT': parameters[self.OUTPUT_BUFFER]},
54            context=context, feedback=feedback, is_child_algorithm=True)
55        buffered = algresult['OUTPUT']
56        return {self.OUTPUT_BUFFER: buffered}

完成必要导入后,需指定以下 QgsProcessingAlgorithm 函数:

  • name():算法的 ID(小写)。

  • displayName():算法的人类可读名称。

  • createInstance():创建算法类的新实例。

  • initAlgorithm():配置参数定义和输出定义。

    在此描述算法的参数和输出。本例中包括:输入的要素源、结果的要素接收器(sink),以及缓冲距离的数值。

  • processAlgorithm():执行实际工作。

    此处我们首先运行 smoothgeometry 算法对几何进行平滑处理,然后在其平滑后的输出上运行 buffer 算法。要在算法内部运行其他算法,必须将 is_child_algorithm 参数设为 True。您可以看到输入和输出参数是如何作为参数传递给 smoothgeometrybuffer 算法的。

输入和输出有多种参数类型可用。完整列表请参见 处理算法的输入与输出

构造函数的第一个参数是参数名称,第二个是参数描述(用于用户界面)。其余参数则根据具体参数类型而定。

可使用 QgsProcessingAlgorithmparameterAs 函数将输入转换为 QGIS 类。例如,要将缓冲距离数值作为双精度浮点数获取::

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

processAlgorithm 函数应返回一个字典,包含算法定义的每个输出的值。这使得其他算法(包括同一模型中的其他算法)能够访问这些输出。

良好的算法应定义并返回尽可能多的有意义输出。非要素类输出(如数字和字符串)在将算法作为更大模型的一部分运行时非常有用,因为这些值可用作模型中后续算法的输入参数。建议添加诸如处理的要素数量、遇到的无效要素数量、输出的要素数量等数值型输出。返回的输出越多,您的算法就越有用!

23.7.2.1. 反馈机制

应使用传递给 processAlgorithm()feedback 对象向用户提供反馈或交互。您可以使用该对象的 setProgress() 方法更新进度条(0 到 100),以告知用户算法的执行进度。当算法耗时较长时,这非常有用。

feedback 对象提供 isCanceled() 方法,应持续监控以支持用户取消算法执行。其 pushInfo() 方法可用于向用户发送信息,而 reportError() 则便于向用户报告非致命错误。

算法应避免使用其他用户反馈形式(如 print 语句或记录到 QgsMessageLog),而应始终使用 feedback 对象。这既支持详细日志记录,又具备线程安全性(鉴于算法通常在后台线程中运行,这一点尤为重要)。

23.7.2.2. 错误处理

如果您的算法遇到阻止其执行的错误(如无效输入值或其他无法或不应恢复的情况),则应抛出 QgsProcessingException。例如::

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

应尽量避免对非致命错误(例如要素几何为空)抛出 QgsProcessingException,而应通过 feedback.reportError() 报告错误并跳过该要素。这有助于使您的算法“模型友好”——当遇到非致命错误时,不会导致整个算法执行中断。

23.7.2.3. 为脚本编写文档

与模型类似,您可以为脚本创建额外文档,以说明其功能及使用方法。

QgsProcessingAlgorithm 提供了 helpString()shortHelpString()helpUrl() 函数用于此目的。请指定或重写这些方法以向用户提供更多帮助。

shortDescription() 用于在工具箱中悬停于算法上时显示的工具提示。

23.7.3. 执行前与执行后脚本钩子

脚本也可用作执行前和执行后钩子,分别在算法运行前和运行后执行。这可用于自动化每次执行算法时都应完成的任务。

语法与上述完全相同,但额外提供一个名为 alg 的全局变量,代表刚刚执行(或即将执行)的算法。

在处理选项对话框的 General 组中,您会找到两个条目:Pre-execution scriptPost-execution script,可在其中分别输入要运行的脚本文件名。