Skip to content

49_通过 Python 运行 QGIS3 处理算法

原文链接: https://www.qgistutorials.com/en/docs/3/processing_algorithms_pyqgis.html

通过 Python 运行处理算法 (QGIS3)

QGIS 中的“处理工具箱”包含一个不断增长的地理处理工具集。该工具箱提供了一个便捷的批量处理界面,可以对大量输入数据运行任何算法。请参阅使用处理框架进行批量处理 (QGIS3)。但在某些情况下,您需要在批量处理中加入一些自定义逻辑。由于所有处理算法都可以通过 Python API 以编程方式运行,因此您可以通过 Python 控制台来运行它们。本教程展示了如何通过 Python 控制台运行处理算法,仅用几行代码即可执行自定义的地理处理任务。请先查看Python 编程入门 (QGIS3)教程,以熟悉 QGIS 中 Python 脚本环境的基础知识。

任务概述

我们将使用代表一年中每个月的12个格网化栅格图层,并计算西雅图地区所有邮政编码的月平均降水量。

您将学到的其他技能

  • 从 Python 控制台访问所有图层(栅格和矢量)并打印其名称。
  • 使用 Python 脚本将不同图层合并为单个图层。

获取数据

PRISM 气候小组收集气候观测数据,并为美国本土提供历史和当前的气候数据。请访问近年数据页面,下载2017年 BIL 格式的月降水量数据。

../../_images/data119.png

西雅图市开放数据门户为该市提供免费的开放数据。搜索并下载 shapefile 格式的邮政编码数据。

为方便起见,您可以直接通过以下链接下载这两个数据集的副本:

PRISM_ppt_stable_4kmM3_2017_all_bil.zip

Zip_Codes.zip

数据来源 [PRISM] [CITYOFSEATTLE]

操作步骤

  1. 在 QGIS 浏览器中找到 PRISM_ppt_stable_4kmM3_2017_all_bil.zip 文件夹并展开它。该文件夹包含每个月的12个独立图层。按住 Ctrl 键并选择所有12个月的 .bil 文件。选中后,将它们拖到画布上。

../../_images/1140.png

注意

数据以BIL 格式提供。每个图层都包含一组文件:.bil 文件包含实际数据,.hdr 文件描述数据结构,.prj 文件包含投影信息。只要其他文件存在于同一目录中,QGIS 就可以加载 .bil 文件。

  1. 将会出现“选择 PRISM_ppt_stable_4kmM3_2017_all_bil 的转换”对话框,保留默认选择并点击确定。

../../_images/2109.png

  1. 接下来,找到 Zip_Codes.zip 文件夹并展开它。将 Zip_Codes.shp 文件拖到画布上。

../../_images/357.png

  1. 右键单击 Zip_Codes 图层并选择 缩放到图层。您将看到西雅图市及邻近地区的邮政编码多边形。

../../_images/429.png

  1. 转到 处理 -> 工具箱

../../_images/527.png

  1. 使用矢量多边形采样栅格层的算法被称为 分区统计。在“处理工具箱”中搜索该算法。选择该算法并将鼠标悬停在上面。您将看到一个工具提示,显示文本 算法 ID:‘native:zonalstatisticsfb’。请记下此 ID,因为需要通过 Python API 调用此算法。双击 分区统计 算法启动它。

../../_images/627.png

  1. 我们将对一个图层进行手动测试运行。这是一种有用的方法,可以检查算法是否按预期运行,也是在通过 Python 使用该算法时,找出如何传递相关参数的简便方法。在“分区统计”对话框中,选择 Zip_Codes 作为输入图层,PRISM_ppt_stable_4kmM3_201701_bil 作为栅格图层,其他参数保留默认值。点击 要计算的统计量 旁边的 … 按钮,仅选择 平均值。接下来,点击 分区统计 旁边的 … 按钮,将图层另存为 january_mean.gpkg。点击 运行

../../_images/726.png

  1. 算法完成后,切换到 日志 选项卡。记下传递给算法的输入参数。点击 关闭

../../_images/826.png

  1. 现在,一个新图层 january_mean 将被添加到画布中。让我们检查结果,右键单击该图层并选择 打开属性表。此特定算法会原地修改输入的区域图层,并为每个选定的统计量添加一个新列。由于我们只选择了 平均值,因此表中添加了一个名为 _mean 的新列。_ 是默认前缀。当我们为每个月的图层运行算法时,指定一个带有月份编号的自定义前缀将很有用,这样我们可以轻松识别每个月的平均值(例如,01_mean,02_mean 等)。在 QGIS 的批量处理界面中无法指定此自定义前缀,如果我们使用该界面运行此命令,则必须为每个图层手动输入自定义前缀。如果您要处理大量图层,这可能非常繁琐。因此,我们可以使用 Python API 添加此自定义逻辑,并在 for 循环中为每个图层运行算法。

../../_images/926.png

  1. 回到主 QGIS 窗口,转到 插件 -> Python 控制台

../../_images/1034.png

  1. 点击显示编辑器按钮。这将打开 Python 编辑器,您可以在其中编写一串 Python 代码,并通过一次单击按钮来执行。

../../_images/1141.png

  1. 要通过 Python 运行处理算法,我们需要访问所有图层的名称。在编辑器中输入以下代码,然后点击 运行 按钮。您将在控制台中看到所有图层的名称被打印出来。

bash root = QgsProject.instance().layerTreeRoot() for layer in root.children(): print(layer.name())

../../_images/1235.png

  1. 现在,让我们计算一个月的 平均值 并创建一个输出图层。在下面的代码中,break 用于在第一次执行后退出循环,通过这样我们可以计算一月份的平均值。

```bash import re

root = QgsProject.instance().layerTreeRoot()

input_layer = 'Zip_Codes' unique_field = 'OBJECTID'

Iterate through all raster layers

for layer in root.children(): if layer.name().startswith('PRISM'): # Run Zonal Stats algorithm # Extract the YYYYMM part of the layer name pattern = r'(\d+)' matches = re.findall(pattern, layer.name()) # Use the month as the prefix prefix = matches[0][-2:] params = {'INPUT_RASTER': layer.name(), 'RASTER_BAND': 1, 'INPUT': input_layer, 'COLUMN_PREFIX': prefix+'_', 'STATISTICS': [2], 'OUTPUT': 'memory:' } result = processing.run("native:zonalstatisticsfb", params)

result_layer = result['OUTPUT']
QgsProject.instance().addMapLayer(result_layer)
# Breaking out of loop to demonstrate the
# zonalstatistics algorithm.
break

```

../../_images/1333.png

注意

您也可以通过 Python 运行 QGIS 处理算法,使用 processing.runAndLoadResults() 函数,而不是如上所示的 processing.run() —— 这将直接把结果加载到 QGIS 画布中。

  1. 一个新图层 output 将被添加到画布中,右键单击该图层并选择 打开属性表。01_mean 代表一月份的平均值,同样,如果不加 break 执行,上述算法将生成 12 个新图层。

../../_images/1431.png

  1. 现在让我们添加代码来合并所有月份的平均值,并从中创建单个输出图层。我们更新之前的代码,以迭代运行分区统计算法。我们定义一个新变量 result_layer,开始时将其设置为 Zip_Codes,但会在每次迭代中更新为输出图层。这将允许我们使用每次迭代的结果并向其添加新列。输入以下代码,迭代所有栅格图层并创建包含所有月份平均值的单个图层。

```bash import re

root = QgsProject.instance().layerTreeRoot()

input_layer = 'Zip_Codes' result_layer = input_layer unique_field = 'OBJECTID'

Iterate through all raster layers

for layer in root.children(): if layer.name().startswith('PRISM'): # Run Zonal Stats algorithm # Extract the YYYYMM part of the layer name pattern = r'(\d+)' matches = re.findall(pattern, layer.name()) # Use the month as the prefix prefix = matches[0][-2:] params = {'INPUT_RASTER': layer.name(), 'RASTER_BAND': 1, 'INPUT': result_layer, 'COLUMN_PREFIX': prefix+'_', 'STATISTICS': [2], 'OUTPUT': 'memory:' } result = processing.run("native:zonalstatisticsfb", params)

# Update the result_layer variable
# The result will be used as input for the next iteration
result_layer = result['OUTPUT']

QgsProject.instance().addMapLayer(result_layer) ```

../../_images/1526.png

  1. 处理完成后,一个新图层 output 将被添加到画布中,右键单击该图层并选择 打开属性表

../../_images/1624.png

  1. 您将看到表中添加了 12 个新列,这些列带有自定义前缀,并包含了从栅格图层中提取的平均降水量值。

../../_images/1726.png


如果您想对此教程提供反馈或分享您的经验,请在下方留言。(需要 GitHub 账户)