跳到主要内容 QGIS Python 编程秘籍(一) | 极客日志
Python 算法
QGIS Python 编程秘籍(一) QGIS Python 编程涉及环境配置、自动化工作流、矢量与栅格数据处理、插件开发及调试技巧。内容涵盖 PyQGIS API 基础操作,包括数据加载、空间查询、几何编辑、投影转换、地图绘制及独立应用程序构建,通过代码示例展示地理空间任务的自动化实现方法。
QGIS Python 编程秘籍(一)
第一章:自动化 QGIS
本章将涵盖以下食谱:
为开发安装 QGIS
使用 QGIS Python 控制台
使用 Python 的 ScriptRunner 插件
设置您的 QGIS IDE
调试 QGIS Python 脚本
导航 PyQGIS API
创建 QGIS 插件
分发插件
构建独立应用程序
存储和读取全局首选项
存储和读取项目首选项
在您的脚本中访问脚本路径
简介
本章解释了如何使用 Python 配置 QGIS 以实现自动化。除了设置 QGIS 之外,我们还将配置带有 PyDev 插件的免费 Eclipse 集成开发环境(IDE),以便更容易地编写、编辑和调试脚本。我们还将通过 PyQGIS API 学习不同类型的 QGIS 自动化 Python 脚本的基础知识。最后,我们将检查一些核心的 QGIS 插件,这些插件显著扩展了 QGIS 的功能。
为开发安装 QGIS QGIS 有一套可以从 QGIS 中的 Python 控制台访问的 Python 模块和库。然而,它们也可以从 QGIS 外部访问以编写独立应用程序。首先,您必须确保为您的平台安装了 PyQGIS,然后设置一些必需的系统环境变量。
在这个菜谱中,我们将向您介绍在正常 QGIS 安装之外所需的额外步骤,以准备您的系统进行开发。每个平台的步骤都提供,其中包括不同的 Linux 包管理器样式。
准备工作 QGIS 针对 Windows、GNU/Linux 和 Mac OS X 使用略微不同的安装方法。Windows 安装程序安装了 Python 开发所需的所有内容,包括 Python 本身。
然而,在 Linux 发行版和 Mac OS X 上,您可能需要手动安装 Python 模块以进行系统 Python 安装。
如何操作 在 Linux 上,您可以选择从源代码编译,或者您可以通过包管理器指定要安装的 Python QGIS 接口。
使用 Debian 包管理器安装 PyQGIS 接下来,安装 QGIS、PyQGIS 和 QGIS GRASS 插件:
sudo apt-get install qgis python-qgis qgis-plugin-grass
对于基于 Debian Linux 包管理器的 Linux 发行版,包括 Ubuntu 和 Debian,请在 shell 中使用以下命令:
使用 RPM 包管理器安装 PyQGIS 然后,安装 QGIS、PyQGIS 和 QGIS GRASS 插件的包:
sudo yum install qgis qgis-python qgis-grass
对于基于 Red Hat 包管理器(RPM)的 Linux 发行版,首先更新包管理器,如下所示:
设置环境变量 现在,我们必须将 PYTHONPATH 设置为 PyQGIS 目录。同时,将此目录的路径追加到 PATH 变量中,以便您可以使用外部 IDE 使用 PyQGIS 模块。
在 Windows 上设置环境变量 接下来,将 QGIS 的 bin 目录追加到系统的 PATH 变量中:
set PATH="C:\Program Files\QGIS Brighton\bin" ;"C:\Program Files\QGIS Brighton\bin\apps\qgis\bin" ;%PATH%
在命令提示符中设置 PYTHONPATH 变量为 QGIS 安装的 bin 目录:
set PYTHONPATH="C:\Program Files\QGIS Brighton\bin"
在 Linux 上设置环境变量 现在,将 QGIS 共享库目录追加到运行时搜索路径中。请注意,此位置可能因您的特定系统配置而异:
export LD_LIBRARY_PATH=/usr/share/qgis/python
在命令提示符中设置 PYTHONPATH 变量为 QGIS 安装的 bin 目录:
export PYTHONPATH=/usr/share/qgis/python
它是如何工作的… QGIS 安装过程和包管理器在 QGIS 内部设置了 Python 模块的配置。当您在 QGIS 内部使用 Python 控制台时,它知道所有 PyQGIS 模块的位置。然而,如果您想在 QGIS 之外使用 PyQGIS API,在 Windows 或 Linux 上使用系统 Python 安装,则需要设置一些系统变量,以便 Python 可以找到所需的 PyQGIS 模块。
还有更多… 此配方使用每个平台的默认 QGIS 路径。如果您不确定哪个 PyQGIS 路径适用于您的系统,您可以从 QGIS 中的 Python 控制台找出这一点。
在 Windows 上查找 PyQGIS 路径 Windows 上的库存储位置与其他平台不同。要定位路径,您可以检查 Python 控制台当前的工作目录:
启动 QGIS。
从 QGIS 应用程序窗口的右下角出现的 插件 菜单中选择 Python 控制台 。
验证 Python 控制台当前的工作目录是否返回。
在其他平台上查找 QGIS Python 安装的位置 执行以下步骤以找到除 Windows 之外所有平台所需的路径:
启动 QGIS。
启动 QGIS Python 控制台 。
Python 将返回一个路径列表。
找到以 /python 结尾的路径,这是 QGIS 使用的 Python 安装位置
使用 QGIS Python 控制台进行交互式控制 QGIS Python 控制台允许您交互式地控制 QGIS。您可以测试想法或进行一些快速自动化。控制台是使用 QGIS Python API 的最简单方式。
如何操作… 在以下步骤中,我们将打开 QGIS Python 控制台,在内存中创建一个矢量图层,并在地图上显示它:
启动 QGIS。
从 插件 菜单中选择 Python 控制台 。
layer = QgsVectorLayer('Point?crs=epsg:4326' ,'MyPoint' ,'memory' )
pr = layer.dataProvider()
pt = QgsFeature()
point1 = QgsPoint(20 ,20 )
pt.setGeometry(QgsGeometry.fromPoint(point1))
pr.addFeatures([pt])
layer.updateExtents()
QgsMapLayerRegistry.instance().addMapLayers([layer])
它是如何工作的… 此示例使用一个 内存 图层来避免与磁盘或网络上的任何数据交互,以保持事情简单。请注意,当我们声明图层类型时,我们添加了 坐标参考系统 (CRS )参数为 EPSG:4326。如果没有这个声明,QGIS 将提示您选择一个。创建地图画布上的单个点甚至需要三个部分或抽象级别,如下所示:
首先,创建一个几何类型的图层。然后,设置一个数据提供者以接受数据源。
然后,创建一个通用的要素对象,接着是点几何。
接下来,将对象堆叠在一起并将它们添加到地图中。
图层类型是 内存,这意味着您可以在代码中而不是在外部数据源中内联定义几何形状和属性。在此配方中,我们只定义几何形状并跳过定义任何属性。
使用 Python ScriptRunner 插件 QGIS Python ScriptRunner 插件为 QGIS 自动化提供了一个中间地带,介于交互式控制台和插件开销之间。它提供了一个脚本管理对话框,允许您轻松加载、创建、编辑和运行脚本,以实现大规模的 QGIS 自动化。
准备工作 使用 QGIS 插件管理器安装 ScriptRunner 插件。然后,从 插件 菜单运行插件以打开 ScriptRunner 对话框。按照以下步骤配置默认编辑器以编辑脚本:
找到代表 ScriptRunner 首选设置 对话框的齿轮图标,并点击它。
在 常规选项 部分,勾选 使用以下方式编辑脚本 复选框。
点击 … 按钮浏览到您系统上的文本编辑器位置。
点击 打开 按钮。
在 首选项 对话框中点击 OK 按钮。
如何操作…
在 ScriptRunner 对话框中,点击下面的截图所示的 新建脚本 图标。
浏览到可以保存您的脚本的位置,命名脚本,并保存它。
验证新脚本是否已加载到 ScriptRunner 中。
在 ScriptRunner 中的脚本名称上右键单击(或在 Mac 上控制单击)并选择 在外部编辑器中编辑脚本 。
点击代表绿色箭头的运行脚本图标。
关闭 ScriptRunner 插件。
验证内存图层多边形是否已添加到 QGIS 地图中。
from PyQt4.QtCore import *
from PyQt4.QtGui import *
from qgis.core import *
from qgis.gui import *
def run_script (iface ):
layer = QgsVectorLayer('Polygon?crs=epsg:4326' ,'Mississippi' ,"memory" )
pr = layer.dataProvider()
poly = QgsFeature()
geom = QgsGeometry.fromWkt("POLYGON ((-88.82 34.99,-88.09 34.89,-88.39 30.34,-89.57 30.18,-89.73 31,-91.63 30.99,-90.87 32.37,-91.23 33.44,-90.93 34.23,-90.30 34.99,-88.82 34.99))" )
poly.setGeometry(geom)
pr.addFeatures([poly])
layer.updateExtents()
QgsMapLayerRegistry.instance().addMapLayers([layer])
它是如何工作的… ScriptRunner 是一个简单但强大的想法。它允许您构建自动化脚本库,并在 QGIS 内部使用它们,但无需构建插件或独立应用程序的开销。所有 Python 和系统路径变量都设置正确,并从 QGIS 继承;然而,您仍然必须导入 QGIS 和 Qt 库。
设置您的 QGIS IDE 配备 PyDev 插件的 Eclipse IDE 是跨平台的,具有高级调试工具,并且是免费的。
您可以参考 pydev.org/manual_101_install.html 以正确安装 PyDev。
此工具是一个出色的 PyQGIS IDE。Eclipse 允许您为不同的 Python 环境配置多个 Python 解释器。当您安装 PyDev 时,它将自动找到已安装的系统 Python 安装。在 Windows 上,您还必须添加与 PyQGIS 一起安装的 Python 解释器。在所有平台上,您都必须告诉 PyDev PyQGIS 库的位置。
准备工作 此配方使用 Eclipse 和 PyDev。您可以使用操作系统支持的最新版本的任一包。除了 Windows 之外的所有平台都依赖于系统 Python 解释器。因此,在 Windows 上添加 QGIS Python 解释器需要额外的一步。
如何操作… 以下步骤将指导您如何将 QGIS 特定的 Python 解释器添加到 Eclipse 中,以便支持运行独立的 QGIS 应用程序或调试 QGIS 插件。
在 Windows 上添加 QGIS Python 解释器 在 Windows 上添加 QGIS Python 解释器到 Eclipse 的过程与在 Linux 上使用的过程不同。以下步骤描述了如何在 Windows 版本的 Eclipse 上设置解释器:
打开 Eclipse。
从 窗口 菜单中选择 首选项 。在 OS X 上,您必须点击 Eclipse 菜单以找到首选项菜单。
在 首选项 窗口的左侧面板中,点击 PyDev 旁边的加号。
从 PyDev 首选项列表中选择 解释器 Python 。
在标记为 Python 解释器的面板中,点击 新建 按钮。
在 选择解释器 对话框中,将解释器命名为 PyQGIS。
浏览到 QGIS 程序文件夹中的 bin 文件夹内名为 python.exe 的 QGIS Python 解释器位置。在 OS X 和 Linux 上,您可以使用系统 Python 安装。在 Windows 上,Python 包含在 QGIS 中。
当您点击 确定 按钮时,Eclipse 将尝试自动将找到的每个 Python 库添加到该解释器配置的 Python 路径中。我们需要控制添加哪些库以防止冲突。点击 取消选择全部 按钮,然后点击 确定 。
Eclipse 将显示一个警告对话框,因为您尚未选择任何核心库。点击 继续 按钮。
将 PyQGIS 模块路径添加到解释器 除了添加 Python 解释器外,你还必须使用以下步骤添加 PyQGIS 需要的模块路径。这些步骤将需要你在 QGIS 和 Eclipse 之间来回切换:
启动 QGIS。
从 插件 菜单启动 QGIS Python 控制台 。
对于返回列表中的每个路径,在 Eclipse 的 QGIS 解释器 库 面板中点击 新建文件夹 按钮,浏览到该文件夹,直到所有路径都已添加。如果系统上不存在某个文件夹,只需忽略它。
在 首选项 对话框中点击 确定 按钮。
我们还希望添加 PyQGIS API。接下来,使用 QGIS Python 控制台 输入以下命令来查找该路径:
使用 sys 模块定位 PyQGIS Python 路径,如前一个食谱中所述,设置环境变量 :
将 PyQGIS API 添加到 IDE 为了充分利用 Eclipse 的功能,包括代码补全,我们将向 PyQGIS Eclipse 解释器首选项添加 QGIS 和 Qt4 模块。以下步骤将允许 Eclipse 在你输入时建议 QGIS 对象的可能方法和属性;这个功能被称为 自动完成 :
在 PyDev 的 PyQGIS 解释器首选项中,选择 强制内置 选项卡。
点击 新建 按钮。
在 内置要添加 对话框中,输入 qgis。
点击 确定 按钮。
添加环境变量 你还需要创建一个指向 QGIS 二进制库、Windows 上的 DLL 和所有平台在运行时所需的库的 PATH 变量。
在 PyDev 首选项 对话框中,确保在解释器列表中选择了 PyQGIS 解释器。
选择 环境 选项卡。
点击 新建 按钮。
在 值 字段中,添加 QGIS 程序目录和包含二进制的任何 QGIS 目录的路径,这些路径由分号分隔。以下是一个来自 Windows 机器的示例:
C:\Program Files\QGIS Brighton;C:\Program Files\QGIS Brighton\bin;C:\Program Files\QGIS Brighton\apps\qgis\bin;C:\Program Files\QGIS Brighton\apps\Python27\DLLs
它是如何工作的… Eclipse 和 PyDev 仅使用你提供的信息在 Eclipse 工作区中运行脚本。这种方法与流行的 Python 工具 virtualenv 非常相似,它提供了一个干净的环境,以确保你在编写和调试代码时不会浪费时间在调试由环境引起的问题上。
调试 QGIS Python 脚本 在本食谱中,我们将配置 Eclipse 以调试 QGIS Python 脚本。
如何操作… QGIS 和 Eclipse 都必须配置为调试,以便这两款软件能够通信。Eclipse 会 附加 到 QGIS 上,以便您了解在 QGIS 中运行的 Python 脚本。这种方法允许您以受控的方式运行脚本,可以在您监控程序以捕获错误时暂停执行。
配置 QGIS 以下步骤将为 QGIS 添加两个插件,这允许 Eclipse 与 QGIS 通信。一个插件是 插件重载器 ,允许您在不重启 QGIS 的情况下将 QGIS 插件重新加载到内存中,以便更快地进行测试。第二个插件是 远程调试 ,它将 QGIS 连接到 Eclipse。
远程调试 是一个实验性插件,因此您必须确保实验性插件在可用插件列表中可见,以便 QGIS 插件管理器可以访问。
启动 QGIS。
在 插件 菜单下,选择 管理并安装插件 …
在 插件 对话框的左侧面板中,选择 设置 选项卡。
在 设置 窗口中向下滚动,并确保已勾选 显示实验性插件 复选框。
点击 确定 按钮。
在 插件 窗口左侧的面板中选择标签为 所有 的选项卡。
在窗口顶部的 搜索 对话框中,搜索 插件重载器 。
从搜索结果中选择 插件重载器 ,然后点击 安装插件 按钮。
接下来,搜索 远程调试 插件并安装它。
最后,安装 HelloWorld 插件。
配置 Eclipse 现在 QGIS 已配置为在 Eclipse 中进行调试,我们将配置 Eclipse 以完成调试通信循环,具体步骤如下:
启动 Eclipse。
在 文件 菜单中,选择 新建 ,然后点击 项目 。
在 新建项目 对话框中,选择 通用 ,然后点击 项目 。
点击 下一步> 按钮。
给项目命名为 HelloWorldPlugin 。
点击 完成 按钮。
在项目资源管理器中选择新的 HelloWorldPlugin 项目,然后选择 新建 ;接着,从 文件 菜单中选择 文件夹 。
在 新建文件夹 对话框中,点击 高级>> 按钮。
选择 链接到备用位置(链接文件夹) 单选按钮。
点击 完成 按钮。
点击 浏览 按钮,浏览到 HelloWorldPlugin 文件夹的位置。
小贴士:您可以从 QGIS 插件管理器中找到 HelloWorld 插件的存放位置。
测试调试器 本食谱的前几部分配置了 Eclipse 和 QGIS 以协同工作以调试 QGIS 插件。在本节中,我们将使用最简单的插件 HelloWorld 来测试配置,使用 Debug Perspective 运行 Eclipse。我们将在插件中设置一个断点以暂停执行,然后在 Eclipse 内部监控插件执行,如下所示:
在 HelloWorld 文件夹下打开文件 HelloWorld.py。
从 Eclipse 窗口 菜单中选择 OpenPerspective ,然后点击 Other…
从 OpenPerspective 对话框中选择 调试 。
点击 OK 按钮。
滚动到 hello_world() 函数的第一行,并在行号左侧双击以设置断点,它显示为绿色图标。
从 Pydev 菜单中选择 Start Debug Server 。
切换到 QGIS。
从 QGIS 插件 菜单中选择 RemoteDebug ,然后选择 RemoteDebug 命令。
现在,从 QGIS 插件 菜单中选择 HelloWorld ,然后选择 HelloWorld 。
切换回 Eclipse。
验证 hello_world() 函数在断点处被突出显示。
从 运行 菜单中选择 继续 。
切换回 QGIS。
验证 HelloWorld 对话框已出现。
通过在窗口底部的调试控制台中查找类似以下的消息来验证服务器正在运行:
Debug Server at port:5678
它是如何工作的… RemoteDebug 插件作为 PyDev 调试服务器的客户端,用于将 QGIS 中的 Python 脚本执行状态发送到 Eclipse。尽管它已经伴随 QGIS 几个版本了,但仍被视为实验性的。
PluginReloader 插件可以重置在运行时维护状态的插件。HelloWorld 插件非常简单,因此不需要重新加载来重复测试。然而,当你调试更复杂的插件时,你需要在每次测试之前运行它以重置它。这种方法比关闭 QGIS、编辑插件代码然后重新启动要高效得多且易于使用。
注意:你可以在 docs.qgis.org/2.6/en/docs/pyqgis_developer_cookbook/ide_debugging.html 了解更多关于调试 QGIS 的信息,包括使用其他 IDE。
导航 PyQGIS API QGIS Python API,也称为 PyQGIS,允许你控制 QGIS 的几乎所有方面。找到 PyQGIS 对象以便访问 QGIS 的特定功能的能力对于自动化至关重要。
准备中 PyQGIS API 基于 QGIS C++ API。C++ API 在线保持最新,并且有很好的文档记录。
注意:QGIS API 的网页位于 qgis.org/api/2.6/modules.html。
注意 URL 中的版本号,2.2。您可以将此版本号更改为您正在使用的 QGIS 版本,以便找到适当的文档。
PyQGIS API 文档更新不频繁,因为它几乎与 C++ API 的结构相同。然而,github.com 上的 QGIS 项目维护了一个最新版本的 PyQGIS 类的列表。PyQGIS 2.6 API 位于 github.com/qgis/QGIS/blob/master/python/qsci_apis/Python-2.6.api。
您可以在主 C++ API 中找到已记录的类并了解它。然后,使用 PyQGIS API 列表查找相应的 Python 模块和类。在大多数情况下,类的 C++ API 名称与 Python 中的名称相同。
在本菜谱中,我们将定位控制 QGIS 标签的 PyQGIS 类。
如何操作… 我们将执行以下步骤,以查看 QGIS 标签对象和 QgsLabel 位于哪个 PyQGIS 模块中:
前往 QGIS API 页面 qgis.org/api/2.6/index.html。
点击 模块 标签。
点击链接 QGIS 核心库 。
按字母顺序滚动模块列表,直到您看到 QgsLabel 。
点击 QgsLabel 链接以访问标签对象文档。
现在,前往 PyQGIS API 列表 github.com/qgis/QGIS/blob/master/python/qsci_apis/Python-2.6.api。
按字母顺序滚动类列表,直到您看到 qgis.core.QgsLabel.LabelField。
工作原理… 大多数情况下,找到针对您所需功能的类很容易,因为 QGIS 的大部分功能都包含在通用的 核心 模块中。您使用 API 的次数越多,您就越快能找到您脚本所需的对象。
更多内容… 如果您在定位包含所需关键字的类时遇到困难,您可以使用 QGIS API 网站上的搜索引擎。
小贴士:然而,请注意,此搜索引擎返回的结果可能包含您不需要的项目,甚至可能因为不同模块中相似的关键词而将您引向错误的方向。
创建 QGIS 插件 插件是扩展 QGIS 的最佳方式,因为它们可以轻松更新并由其他人重用。
准备工作 创建插件的最简单方法就是使用 插件构建器 插件来快速启动开发。您可以在主 QGIS 插件仓库中找到它并进行安装。
如何操作… 执行以下步骤以创建一个显示自定义消息对话框的简单插件:
启动 QGIS。
从 插件 菜单中选择 插件构建器 ,然后在子菜单下点击 插件构建器 。
在 QGIS 插件构建器 对话框中,将类命名为 MyPlugin。
将插件命名为 My Plugin。
输入简短描述,例如 一个关于构建 QGIS 插件的演示。
将 模块 名称输入为 myplugin。
保持默认版本号不变。
在 菜单项文本 字段中输入 My Plugin。
输入您的姓名和电子邮件地址作为作者信息。
确保选中了标记为 将插件标记为实验性 的复选框。
点击 确定 按钮。
通过点击 确定 按钮关闭后续的 插件构建器 信息对话框。
使用命令提示符,导航到您的新插件模板文件夹。
在文本编辑器中,例如 Windows 记事本或 Linux 上的 vi,打开名为 myplugin_dialog_base.ui 的用户界面 XML 文件。
您的插件现在已准备就绪。重新启动 QGIS。
从 插件 菜单中选择 My Plugin ,然后从子菜单中选择 My Plugin ,以查看 QGIS 中创建的对话框。
pyuic4 –o ui_myplugin.py ui_myplugin.ui
在第 31 行附近,在最后一个 </widget> 标签之前插入以下 XML 以创建自定义标签。编辑后保存文件:
<widget class ="QLabel" name ="label" > <property name ="geometry" > <rect > <x > 120</x > <y > 80</y > <width > 201</width > <height > 20</height > </rect > </property > <property name ="font" > <font > <pointsize > 14</pointsize > </font > </property > <property name ="text" > <string > Geospatial Python Rocks!</string > </property > </widget >
pyrcc4 –o resources_rc.py resources.qrc
小贴士:如果您使用的是 Windows,则非常重要,需要使用与 QGIS 一起安装的 OSGEO4W shell,以确保 Qt 编译工具能够正常工作。
将会出现一个文件浏览器对话框;您可以选择一个文件夹来创建您的插件。在主用户目录或 QGIS 程序目录中的 python 文件夹中的 plugins 文件夹中选择一个文件夹。以下示例来自 Windows 机器。您应该使用用户目录中的文件夹,这是第三方插件的推荐位置。QGIS 标准插件位于主程序目录中:
C:\Documents and Settings\Joel\.qgis2\python\plugins
C:\Program Files\QGIS Brighton\apps\qgis\python\plugins
它是如何工作的… 此配方展示了制作一个工作插件所需的基本内容。尽管我们没有对其进行修改,但插件行为的代码包含在 myplugin.py 中。您可以更改图标和 GUI,并且随时重新编译。请注意,我们必须编译插件的 Qt4 部分,这会创建对话框。整个 QGIS GUI 都是建立在 Qt4 库之上的,因此 pyrrc4 编译器和 pyuic4 包含在内以编译 GUI 小部件。
注意:您可以在 QGIS 文档中找到更多关于 QGIS 插件的信息,包括目录中其他文件的目的,请参阅 docs.qgis.org/testing/en/docs/pyqgis_developer_cookbook/plugins.html。
更多信息… 我们已经手动编辑了 myplugin_dialog_base.ui XML 文件以进行一些小的修改。然而,使用 Qt Creator 有更好的方法。Qt Creator 是一个完整的开源 GUI 设计器,用于 Qt 框架。它是一个易于使用的所见即所得编辑器,用于 Qt Widgets,包括 PyQGIS 插件,它使用包含的 Qt Designer 接口。在 Windows 上,Qt Designer 可以在 QGIS 程序目录中的 bin 目录下找到。它被命名为 designer.exe。在其他平台上,Qt Designer 作为 qt4-devel 软件包的一部分提供。
注意事项:您还可以从 qt-project.org/downloads 下载 Qt Creator,其中包含 Qt Designer。
当您运行安装程序时,您可以取消选中所有安装选项,除了 工具 类别,以仅安装 IDE。
分发插件 分发 QGIS 插件意味着将文件集合作为一个 ZIP 文件放置在服务器上,并包含一个特殊的配置文件,以便 QGIS 插件管理器能够定位和安装插件。QGIS 项目有一个官方仓库,但也允许第三方仓库。官方仓库对插件的上传方式非常严格。因此,对于这个配方,我们将为示例插件设置一个简单的第三方仓库,并使用 QGIS 插件管理器进行测试,以避免将测试项目污染主 QGIS 仓库。
准备工作 为了完成这个配方,您需要一个示例插件和一个可公开访问的网络目录。您还需要一个 zip 工具,例如免费的 7-zip 程序 (www.7-zip.org/download.html)。您可以使用 Creating a QGIS plugin 配方中的 MyPlugin 示例作为要分发的插件。对于网络目录,您可以使用 Google Code 仓库、GitHub 仓库或您可以访问的其他在线目录。代码仓库工作得很好,因为它们是存储您正在开发的插件的好地方。
如何操作… 在以下步骤中,我们将打包我们的插件,为其创建一个服务器配置文件,并将其放置在服务器上以创建一个 QGIS 插件仓库:
首先,将插件目录压缩成 .ZIP 文件。
将此文件上传到公开可访问的网络目录。
将您的插件目录中的 icon.png 文件上传到网络目录。
将 plugins.xml 文件上传到您的网络目录。
现在,启动 QGIS 并通过访问 插件 菜单并选择 管理并安装插件… 来启动插件管理器。
在 插件设置 对话框的 设置 选项卡中,向下滚动并点击 添加… 按钮。
给插件起一个名字,然后在 URL 字段中添加您 plugins.xml 的完整 URL。
点击 确定 按钮。
为了使事情更简单,通过选择存储库名称,点击 编辑 按钮,并取消选择 启用 复选框来禁用其他存储库。
点击 确定 按钮。
点击 未安装 选项卡。
您的测试插件应该是列表中唯一的插件,因此从列表中选择它。
点击窗口右下角的 安装插件 按钮。
点击 关闭 按钮。
前往 插件 菜单并选择您的插件以确保它正常工作。
接下来,为您的插件自定义一个 plugins.xml 元数据文件。您需要的绝大多数数据都可以在插件目录中的 metatdata.txt 文件中找到。以下示例提供了一些指导:
<?xml version ='1.0' encoding ='UTF-8'?>
<?xml-stylesheet type="text/xsl" href="" ?>
<plugins >
<pyqgis_plugin name ="My Plugin" version ="0.1.0" plugin_id ="227" >
<description > <![CDATA[Demonstration of a QGIS Plugin]]></description >
<about > </about >
<version > 0.1.0</version >
<qgis_minimum_version > 1.8.0</qgis_minimum_version >
<qgis_maximum_version > 2.9.9</qgis_maximum_version >
<homepage > <![CDATA[https://code.google.com/p/geospatialpython]]></homepage >
<file_name > MyPlugin.0.1.0.zip</file_name >
<icon > http://geospatialpython.googlecode.com/svn/icon_227.png </icon >
<author_name > <![CDATA[Joel Lawhead]]></author_name >
<download_url > http://geospatialpython.googlecode.com/svn/MyPlugin.0.1.0.zip</download_url >
<uploaded_by > <![CDATA[jll]]></uploaded_by >
<create_date > 2014-05-16T15:31:19.824333</create_date >
<update_date > 2014-07-15T15:31:19.824333</update_date >
<experimental > True</experimental >
<deprecated > False</deprecated >
<tracker > <![CDATA[http://code.google.com/p/geospatialpython/issues]]></tracker >
<repository > <![CDATA[https://geospatialpython.googlecode.com/svn/]]></repository >
<tags > <![CDATA[development,debugging,tools]]></tags >
<downloads > 0</downloads >
<average_vote > 0</average_vote >
<rating_votes > 0</rating_votes >
</pyqgis_plugin >
</plugins >
它是如何工作的… QGIS 存储库的概念简单而有效。plugins.xml 文件包含一个指向同一服务器或不同服务器上 ZIP 文件插件的 download_url 标签。pyqgis_plugin 标签的 name 属性在 QGIS 插件管理器中显示。
创建独立应用程序 QGIS 是一个完整的桌面 GIS 应用程序。然而,通过 PyQGIS,它也可以成为一个全面的地理空间 Python 库,用于构建独立应用程序。在这个菜谱中,我们将构建一个简单的独立脚本,该脚本创建一个带有线条的地图。
准备工作 为了准备,您需要确保已经按照 设置您的 QGIS IDE 菜谱中描述的配置了 Eclipse 和 PyDev 以进行 PyQGIS 开发。
如何操作… 在 PyDev 中,创建一个名为 MyMap 的新项目,包含一个名为 MyMap.py 的 Python 脚本,如下所示:
在 Eclipse 的 文件 菜单中,选择 新建 然后点击 PyDev 项目 。
在 PyDev 项目的 名称 字段中,输入 MyMap。
然后,从 项目类型 列表中选择 Python 单选按钮。
从 解释器 下拉菜单中选择 PyQGIS 。
保持 将项目目录添加到 PYTHONPATH 单选按钮选中。
点击 完成 按钮。
现在,在 PyDev 包资源管理器中选择项目。
从 文件 菜单中选择 新建 ,然后点击 文件 。
将文件命名为 myMap.py。
点击 完成 按钮。
从 运行 菜单中选择 运行 。
确认独立的 QGIS 地图在新窗口中显示。
from qgis.core import *
from qgis.gui import *
from qgis.utils import *
from PyQt4.QtCore import *
from PyQt4.QtGui import *
app = QgsApplication([],True )
app.setPrefixPath("C:/Program Files/QGIS Brighton/apps/qgis" ,True )
app.initQgis()
canvas = QgsMapCanvas()
canvas.setWindowTitle("PyQGIS Standalone Application Example" )
canvas.setCanvasColor(Qt.white)
layer = QgsVectorLayer('LineString?crs=epsg:4326' ,'MyLine' ,"memory" )
pr = layer.dataProvider()
linstr = QgsFeature()
geom = QgsGeometry.fromWKT("LINESTRING (1 1, 10 15, 40 35)" )
linstr.setGeometry(geom)
pr.addFeatures([linstr])
layer.updateExtents()
QgsMapLayerRegistry.instance().addMapLayer(layer)
canvas.setExtent(layer.extent())
canvas.setLayerSet([QgsMapCanvasLayer(layer)])
canvas.zoomToFullExtent()
canvas.freeze(True )
canvas.show()
canvas.refresh()
canvas.freeze(False )
canvas.repaint()
exitcode = app._exec ()
QgsApplication.exitQgis()
sys.exit(exitcode)
它是如何工作的… 这个菜谱尽可能少地使用代码来创建地图画布并绘制线条,以展示独立应用程序的骨架,可以进一步构建以添加更多功能。
要创建线条几何形状,我们使用 已知文本 (WKT ),它提供了一种简单的方法来定义线条顶点,而无需创建大量对象。在这段代码的末尾,我们通过 冻结 画布来解决 QGIS 2.2 中的一个错误。当画布被冻结时,它不会响应用户事件,在这种情况下,这阻止了画布更新。一旦我们刷新画布,我们解冻它并重新绘制它以绘制线条。这个解决方案在 QGIS 2.4 和 2.6 中仍然有效,但不是必需的。
更多内容… 独立的应用程序可以编译成可执行文件,无需安装 QGIS,使用 py2exe 或 PyInstaller:
您可以在 github.com/pyinstaller/pyinstaller/wiki 了解更多关于 PyInstaller 的信息。
存储和读取全局首选项 PyQGIS 允许您存储应用程序级别的首选项并检索它们。
准备工作 此代码可以在任何类型的 PyQGIS 应用程序中运行。在这个例子中,我们将运行它以进行简单的演示。在这个例子中,我们将更改新项目的默认坐标参考系统(CRS),然后从全局设置中读取该值。
如何操作… 在这个食谱中,我们将使用 Python 控制台设置 QGIS 用于新项目的默认投影:
启动 QGIS。
从 插件 菜单中选择 Python 控制台 。
settings = QSettings(QSettings.NativeFormat, QSettings.UserScope,'QuantumGIS' ,'QGis' )
settings.setValue('/Projections/projectDefaultCrs' ,'EPSG:2278' )
settings.value('/Projections/projectDefaultCrs' )
from PyQt4.QtCore import *
工作原理… 此 API 实际上是 QGIS 依赖的 Qt API,用于设置。在 QSettings 对象中,我们指定存储的 NativeFormat,这是平台的默认格式。在 Windows 上,格式是注册表;在 OS X 上,是 plist 文件;在 Unix 上,是文本文件。其他 QSettings 参数是 组织 和 应用程序 ,通常用作存储信息的层次结构。请注意,即使更改了这些设置,QGIS GUI 中的某些属性也可能不会立即更改。在某些情况下,例如 Windows,必须重新启动系统才能使注册表更改生效。然而,一切都将通过编程方式工作。
更多内容… 如果您想查看可以更改的所有选项,请调用 QSettings 的 allKeys() 方法;这将返回所有设置名称的列表。
存储和读取项目首选项 QGIS 应用程序设置使用 Qt API 存储。然而,QGIS 项目设置有自己的对象。在这个食谱中,我们将设置和读取项目标题,然后设置和读取一个插件的自定义首选项。
准备工作 我们将使用之前创建的示例插件 创建 QGIS 插件 来设置插件首选项。您也可以替换您想要的任何插件名称。我们还将在这个 QGIS Python 控制台中运行此食谱以进行快速测试,但此代码通常用于插件中。
如何操作… 在这个食谱中,我们首先将写入并读取当前项目的标题。然后,我们将为名为 splash 的插件创建一个自定义值,如果需要,可以用于插件的启动动画屏幕。
启动 QGIS。
从 插件 菜单中选择 Python 控制台 。
proj = QgsProject.instance()
proj.title("My QGIS Project" )
proj.title()
proj.writeEntry("MyPlugin" ,"splash" ,"Geospatial Python Rocks!" )
proj.readEntry("MyPlugin" ,"splash" ,"Welcome!" )[0 ]
工作原理… 在前两行中,我们更改了当前活动项目的标题,然后将其回显。在下一组两行中,我们为插件设置了自定义设置并读取了它们。请注意,readEntry() 方法返回一个包含所需文本和布尔值的元组,确认该值已设置。因此,我们提取第一个索引以获取文本。读取方法还允许在属性未设置的情况下使用默认文本(而不是抛出必须处理的异常),以及布尔值 False 来通知你,由于属性未设置,使用了默认文本。使用此方法设置的值在保存项目时存储在项目的 XML 文件中。
更多内容… QgsProject 对象有多个方法和属性可能很有用。QGIS API 文档详细介绍了它们在 qgis.org/api/2.6/classQgsProject.html。
在你的脚本中访问脚本路径 有时候,你需要确切地知道当前的工作目录在哪里,这样你才能访问外部资源。
准备工作 此代码使用 Python 内置库,可以在任何上下文中使用。我们将在这个 QGIS Python 控制台中运行这个菜谱。
如何操作… 在这个菜谱中,我们将获取 Python 控制台当前的工作目录,它可能会随着配置而改变:
启动 QGIS。
从 插件 菜单中选择 Python 控制台 。
它是如何工作的… QGIS 严重依赖于文件系统路径来运行应用程序和管理外部数据。当编写跨平台的 QGIS 代码时,你不能假设你的脚本的工作目录。
更多内容… 在他的博客上,一位 QGIS 开发者有一篇关于 QGIS 中路径变量各个方面的优秀文章,而不仅仅是执行目录;你可以在 spatialgalaxy.net/2013/11/06/getting-paths-with-pyqgis/ 查看。
第二章:查询矢量数据
从文件加载矢量图层
从地理数据库中加载矢量图层
检查矢量图层要素
检查矢量图层属性
通过几何形状过滤图层
通过属性过滤图层
缓冲要素
测量两点之间的距离
沿着线测量距离
计算多边形的面积
创建空间索引
计算线的方位角
简介 本章演示了如何在 QGIS 中通过 Python 处理矢量数据。我们首先将加载不同来源的矢量数据。接下来,我们将检查数据的内容。然后,我们将在本章的剩余部分对矢量数据进行空间和数据库操作。
从文件样本中加载矢量图层 本食谱描述了 QGIS 中最常用的数据类型,即文件。在大多数情况下,您将通过加载 shapefile 来开始一个 QGIS 项目。
准备工作 为了便于跟随本书中的示例,建议你在根目录或用户目录中创建一个名为 qgis_data 的目录,这提供了一个简短的路径名。这种设置将有助于防止因特定系统上路径相关问题的出现而导致的任何令人沮丧的错误。在本食谱和其他食谱中,我们将使用纽约市博物馆的点要素图层。
解压此文件,并将 shapfile 的内容放置在 qgis_data 目录中名为 nyc 的目录内。
如何操作… 现在,我们将逐步说明加载 shapefile 并将其添加到地图中的步骤,如下所示:
启动 QGIS。
从 插件 菜单中选择 Python 控制台 。
QgsMapLayerRegistry.instance().addMapLayers([layer])
if not layer.isValid():
print "Layer %s did not load" % layer.name()
layer = QgsVectorLayer("/qgis_data/nyc/NYC_MUSEUMS_GEO.shp" ,"New York City Museums" ,"ogr" )
它是如何工作的… QgsVectorLayer 对象需要文件的位置、QGIS 中图层的名称以及提供正确解析器和为文件格式管理功能的提供者。大多数矢量图层都由 ogr 提供者覆盖,它试图从文件名扩展名中猜测格式,以便使用适当的驱动程序。此提供者可用的格式列在 www.gdal.org/ogr_formats.html。
一旦我们创建了 QgsVector 对象,我们使用 layer.isValid() 方法进行快速检查,以查看文件是否正确加载。我们不会在每一个菜谱中使用此方法以保持代码简短,但此方法通常非常重要。它通常是唯一表明出错的指示。如果您在文件名中输入了拼写错误,或者您尝试连接到在线数据源但没有网络连接,您将看不到任何错误。您的第一个指示将是代码中更远处的另一个方法失败,这将使追踪根本原因更加困难。
在最后一行,我们将矢量图层添加到 QgsMapLayerRegistry 中,使其在地图上可用。注册表跟踪项目中的所有图层。QGIS 以这种方式工作的原因是为了您可以在将图层暴露给地图上的用户之前,加载多个图层,对它们进行样式设置,过滤它们,并执行其他操作。
从空间数据库加载矢量图层 PostGIS 地理数据库基于开源的 Postgres 数据库。地理数据库提供了强大的地理空间数据管理和操作功能。PyQGIS 完全支持 PostGIS 作为数据源。在这个菜谱中,我们将从一个 PostGIS 数据库中添加一个图层。
准备工作
如何做… 执行以下步骤将 PostGIS 图层加载到 QGIS 地图中:
QgsMapLayerRegistry.instance().addMapLayers([layer])
if not layer.isValid():
print "Layer %s did not load" % layer.name()
layer = QgsVectorLayer(uri.uri(),"Islands" ,"postgres" )
uri.setDataSource("public" ,"islands" ,"wkb_geometry" ,"" )
uri.setConnection("spacialdb.com" ,"9999" ,"lzmjzm_hwpqlf" ,"lzmjzm_hwpqlf" ,"0e9fcc39" )
首先,创建一个新的 DataSourceURI 实例:
它是如何工作的… PyQGIS 在 API 中提供了一个对象,用于在 QgsDataSourceURI() 中创建 PostGIS 数据源。代码第二行的 connection 字符串参数是数据库服务器、端口、数据库名、用户和密码。在示例中,数据库、用户名和密码是随机生成的唯一名称。数据源参数是模式名称、表名称、几何列以及可选的 SQL WHERE 子句,根据需要子集图层。
检查矢量图层特征 一旦加载了矢量图层,您可能想调查数据。在这个菜谱中,我们将从一个 shapefile 中加载矢量点图层,并查看第一个点的 x 和 y 值。
准备工作 我们将使用本章中 从文件加载矢量图层 配方中的相同的纽约市博物馆图层。
解压该文件,并将 shapefile 的内容放置在你的根目录或主目录下的 qgis_data 目录中的 nyc 目录内。
如何操作… 在本配方中,我们将加载图层,获取特征,获取第一个特征,获取其几何形状,并查看第一个点的值:
确认 Python 控制台输出类似于以下 QgsPoint 对象:
features = layer.getFeatures()
layer = QgsVectorLayer("/qgis_data/nyc/NYC_MUSEUMS_GEO.shp" ,"New York City Museums" ,"ogr" )
工作原理… 当你使用之前演示的方法访问图层的特征或几何形状时,PyQGIS 返回一个 Python 迭代器。迭代器数据结构允许 Python 在不需要将整个数据集保留在内存中的情况下,高效地处理非常大的数据集。
检查矢量图层属性 一个真正的 GIS 图层包含空间几何和数据库属性。在本配方中,我们将使用 PyQGIS 访问矢量点图层的属性。我们将使用来自 shapefile 的基于文件的图层,但一旦图层在 QGIS 中加载,每个矢量图层的工作方式都是相同的。
准备工作 再次强调,我们将使用本章中 从文件加载矢量图层 配方中的相同的纽约市博物馆图层。
解压该文件,并将 shapefile 的内容放置在你的根目录或主目录下的 qgis_data 目录中的 nyc 目录内。
如何操作… 在以下步骤中,我们将加载图层,访问 features 迭代器,获取第一个特征,然后以 Python 列表的形式查看属性:
[u'Alexander Hamilton U.S. Custom House', u'(212) 514-3700', u'http://www.oldnycustomhouse.gov/', u'1 Bowling Grn', NULL, u'New York', 10004.0, -74.013756, 40.703817]
features = layer.getFeatures()
layer = QgsVectorLayer("/qgis_data/nyc/NYC_MUSEUMS_GEO.shp" ,"New York City Museums" ,"ogr" )
工作原理… 检查属性与访问图层几何形状的点值是一致的。请注意,所有字符串属性值都作为 unicode 字符串返回,这是所有 QGIS 字符串的情况。Unicode 允许 QGIS 除了英语以外的其他语言的国际化(即翻译)。
更多… 属性值如果没有了解这些值代表的意义,那么它们就没有太多意义。你还需要了解字段。你可以通过访问 fields 迭代器并调用每个字段的 name() 方法来获取字段列表。这个操作可以通过 Python 列表推导式轻松完成:
[c.name() for c in f.fields().toList()]
[u'NAME', u'TEL', u'URL', u'ADRESS1', u'ADDRESS2', u'CITY', u'ZIP', u'XCOORD', u'YCOORD']
通过几何形状过滤图层 在本配方中,我们将执行空间操作,根据重叠的多边形图层中的点选择点图层的一个子集。我们将在这两种情况下都使用 shapefiles,其中一个是点图层,另一个是多边形。这种子集是 GIS 操作中最常见的一种。
准备工作 我们需要两个新的 shapefiles,这些 shapefiles 在之前的配方中尚未使用。
解压这些 shapefiles 并将它们放置在你根目录或主目录下的 qgis_data 目录中的 ms 目录内。
如何操作… 在本配方中,我们将执行几个步骤来选择点图层中位于多边形图层内的要素,如下所示:
iface.zoomToActiveLayer()
iface.setActiveLayer(lyrPoly)
print featPnt.id ()
lyrPts.select(featPnt.id ())
for featPnt in featsPnt:
if featPnt.geometry().within(geomPoly):
featsPnt = lyrPts.getFeatures(QgsFeatureRequest().setFilterRect(geomPoly.boundingBox()))
geomPoly = feat.geometry()
ftsPoly = lyrPoly.getFeatures()
QgsMapLayerRegistry.instance().addMapLayers([lyrPts, lyrPoly])
lyrPoly = QgsVectorLayer("/qgis_data/ms/GIS_CensusTract_poly.shp" ,"GIS_CensusTract_poly" ,"ogr" )
lyrPts = QgsVectorLayer("/qgis_data/ms/MSCities_Geo_Pts.shp" ,"MSCities_Geo_Pts" ,"ogr" )
工作原理… 虽然 QGIS 提供了多种空间选择工具,但 PyQGIS 没有专门用于这些类型功能的 API。然而,由于底层 ogr/GEOS 库的存在,API 中有足够的方法,你可以轻松地为两层创建自己的空间过滤器。第 7 步并非完全必要,但使用多边形的边界框来限制我们检查的点特征数量可以提高一些效率。涉及矩形的计算比详细的点在多边形内查询要快得多。因此,我们快速减少需要迭代的点数量,以便进行更昂贵的空间操作。
通过属性过滤图层 除了前一个配方中概述的空间查询之外,我们还可以通过属性对图层进行子集划分。这种查询类似于更传统的数据库查询,实际上使用了 SQL 语句。在本配方中,我们将通过一个属性过滤基于点 shapefile 的图层。
准备工作 我们将使用本章中之前配方中使用的相同的纽约市博物馆层。
解压该文件,并将 shapefile 的内容放置在您的根目录或主目录中的 qgis_data 目录下的 nyc 目录中。
如何操作… 在此配方中,我们将通过属性过滤层,选择过滤后的要素,并缩放到它们,如下所示:
iface.mapCanvas().zoomToSelected()
然后,我们使用列表推导来创建一个特征 ID 列表,该列表被馈送到特征选择方法:
lyrPts.setSelectedFeatures([s.id () for s in selection])
selection = lyrPts.getFeatures(QgsFeatureRequest().setFilterExpression(u'"ZIP" = 10002' ))
QgsMapLayerRegistry.instance().addMapLayers([lyrPts])
lyrPts = QgsVectorLayer("/qgis_data/nyc/NYC_MUSEUMS_GEO.shp" ,"Museums" ,"ogr" )
它是如何工作的… 此配方利用 QGIS 过滤表达式,在第 3 步中突出显示。这些过滤表达式是 SQL 的一个子集。QgsFeatureRequest 将查询表达式作为可选参数处理,以返回仅包含您想要的要素的迭代器。这些查询还允许一些基本的几何操作。此配方还介绍了 mapCanvas().zoomToSelected() 方法,这是一种方便地将地图范围设置为感兴趣要素的方法。
缓冲要素的中间过程 缓冲一个要素会在要素周围创建一个多边形,作为选择几何或简单的可视化。在此配方中,我们将缓冲点要素中的点,并将返回的多边形几何添加到地图上。
准备工作 解压该文件,并将 shapefile 的内容放置在您的根目录或主目录中的 qgis_data 目录下的 nyc 目录中。
如何操作… 此配方涉及空间操作和多个可视化。为此,执行以下步骤:
QgsMapLayerRegistry.instance().addMapLayers([buffLyr])
buffLyr.setLayerTransparency(70 )
pr = buffLyr.dataProvider()
buffLyr = QgsVectorLayer('Polygon?crs=EPSG:4326' ,'Buffer' ,'memory' )
buff = ft.geometry().buffer(.2 ,8 )
lyr.setSelectedFeatures([ft.id ()])
QgsMapLayerRegistry.instance().addMapLayers([lyr])
lyr = QgsVectorLayer("/qgis_data/nyc/NYC_MUSEUMS_GEO.shp" ,"Museums" ,"ogr" )
它是如何工作的… 本菜谱的有趣部分从第 6 步开始,该步创建缓冲几何体。buffer() 方法的参数是缓冲区的地图单位距离,然后是用于近似曲线的直线段数。您指定的段数越多,缓冲区就越像圆形。然而,更多的段数意味着更大的几何复杂性,因此渲染速度和几何计算速度都会变慢。本菜谱的另一个有趣特性是第 13 步,其中我们将图层的透明度设置为 70%。我们还介绍了创建新图层的方法,这是在内存中完成的。后面的章节将更深入地介绍创建数据。
测量两点之间的距离 在 QgsDistanceArea 对象中,PyQGIS 具有出色的测量距离功能。我们将使用此对象进行多个菜谱,从测量两点之间的距离开始。
准备工作 如果您还没有本章之前菜谱中使用的纽约市博物馆图层。
解压该文件,并将 shapefile 的内容放置在您的根目录或主目录下的 qgis_data 目录中的名为 nyc 的目录内。
如何操作… 在以下步骤中,我们将提取图层点顺序中的第一个和最后一个点并测量它们之间的距离:
确保您的 Python 控制台输出类似于以下元组:
d.convertMeasurement(m,2 ,0 ,False )
m = d.measureLine(first.geometry().asPoint(), last.geometry().asPoint())
lyr = QgsVectorLayer("/qgis_data/nyc/NYC_MUSEUMS_GEO.shp" ,"Museums" ,"ogr" )
from qgis.core import QGis
它是如何工作的… QgsDistanceArea 对象接受不同类型的几何体作为输入。在这种情况下,我们使用两个点。该图层的地图单位是十进制度数,对于距离测量来说没有意义。因此,我们使用 QgsDistanceArea.convertMeasurement() 方法将输出转换为米。该方法参数包括测量输出、输入单位(十进制度数)、输出单位(米)以及一个布尔值,表示此转换是面积计算还是线性测量。
返回的元组是测量值和单位。值 0 告诉我们输出是在米。
沿线样测量距离
准备工作 对于本菜谱,我们将使用具有两个特征的线状 shapefile。
将 shapefile 解压到根目录或主目录下的 qgis_data/shapes 目录中。
如何操作… 此菜谱的步骤相当直接。我们将从第一行要素中提取几何形状,并将其传递给测量对象,如下所示:
d.convertMeasurement(m, QGis.Meters, QGis.NauticalMiles,False )
将行的几何形状传递给 measureLine 方法:
m = d.measureLine(route.geometry().asPolyline())
然后,我们必须配置 QgsDistanceArea 对象以使用椭圆模式进行米级的精确测量:
d.setEllipsoidalMode(True )
lyr = QgsVectorLayer("/qgis_data/shapes/paths.shp" ,"Route" ,"ogr" )
from qgis.core import QGis
作用原理… QgsDistanceArea 对象可以根据你调用的方法执行任何类型的测量。当你将测量值从米(用 0 表示)转换为英里(用数字 7 表示)时,你将得到一个包含测量值和单位标识符的元组。QGIS API 文档显示了所有单位常量的值 (qgis.org/api/classQGis.html).
计算多边形的面积
准备工作 对于此菜谱,我们将使用单个要素的多边形 shapefile。
解压 shapefile 并将其放入根目录或主目录下的 qgis_data/ms 目录中。
如何操作… d.convertMeasurement(m, QGis.Degrees, QGis.NauticalMiles,True )
将多边形列表传递给 measureArea() 方法:
m = d.measurePolygon(boundary.geometry().asPolygon()[0 ])
lyr = QgsVectorLayer("/qgis_data/ms/mississippi.shp" ,"Mississippi" ,"ogr" )
from qgis.core import QGis
作用原理… PyQIS 没有提供 measureArea() 方法,但在 QgsDistanceArea 对象中有一个 measurePolygon() 方法。该方法接受一个点列表。在这种情况下,当我们从十进制度数转换为英里时,我们还在 convertMeasurement() 方法中指定 True,这样 QGIS 就知道这是一个面积计算。请注意,当我们获取边界几何形状作为多边形时,我们使用索引 0,这表明存在多个多边形。多边形几何形状可以具有内环,这些内环被指定为额外的多边形。最外层的环,在这种情况下是唯一的环,是第一个多边形。
创建空间索引 到目前为止,本书中的食谱使用了每个操作层的原始几何形状。在本食谱中,我们将采取不同的方法,在运行操作之前为图层创建空间索引。空间索引通过创建额外的、更简单的几何形状来优化图层,这些几何形状可以用来缩小复杂几何形状中的可能性范围。
准备工作 如果你还没有在本书前面的食谱中使用的纽约市博物馆图层。
解压缩该文件,并将形状文件的内容放置在根目录或主目录中的 qgis_data 目录下的 nyc 目录中。
如何操作… 在本食谱中,我们将为点图层创建空间索引,然后我们将使用它来执行空间查询,如下所示:
现在,选择距离第一个点最近的 3 个点的 ID。我们使用数字 4,因为起始点包含在输出中:
hood = index.nearestNeighbor(first.geometry().asPoint(),4 )
for f in fts: index.insertFeature(f)
index.insertFeature(first)
index = QgsSpatialIndex()
lyr = QgsVectorLayer("/qgis_data/nyc/NYC_MUSEUMS_GEO.shp" ,"Museums" ,"ogr" )
工作原理… 索引可以加快空间操作的速度。但是,你必须逐个添加每个特征。此外,请注意,nearestNeighbor() 方法将起始点的 ID 作为输出的一部分返回。因此,如果你想获取 4 个点,你必须指定 5。
计算线的方位角 有时,你需要知道线的罗盘方位角来创建专门的符号或将其用作空间计算中的输入。尽管其名称只提到距离和面积,但多功能的 QgsDistanceArea 对象也包括这个功能。在本食谱中,我们将计算线的端点的方位角。然而,这个食谱可以适用于任何两个点。
准备工作 将形状文件解压缩到根目录或主目录中的 qgis_data/shapes 目录下。
如何操作… 要执行的操作步骤与获取所需的两个点并将它们通过方位角函数运行一样简单,从弧度转换为度数,然后转换为正罗盘方位角:
r = d.bearing(first, last)
points = route.geometry().asPolyline()
你必须将椭球模式设置为 True,以便在计算方位角之前投影数据:
d.setEllipsoidalMode(True )
lyr = QgsVectorLayer("/qgis_data/shapes/paths.shp" ,"Route" ,"ogr" )
它是如何工作的… 磁方位角计算默认输出为弧度。然而,Python 的 math 模块使得转换变得轻而易举。如果度数的转换结果为负数,大多数情况下我们都会想将这个数加到 360 上,以得到罗盘方位角,就像我们在这里做的那样。
从电子表格加载数据 电子表格是收集和存储简单地理数据最常用的方法之一。QGIS 可以处理称为 CSV 或逗号分隔值文件的文本文件。任何电子表格都可以使用电子表格程序转换为 CSV。只要 CSV 数据有一个表示 x 值的列,一个表示 y 值的列,以及其他包含第一行字段名的数据列,QGIS 就可以导入它。许多组织以 CSV 的形式分发地理信息,所以迟早您会发现自己正在导入 CSV。此外,PyQGIS 允许您以编程方式完成此操作。请注意,只要一致,CSV 可以由任何字符分隔。此外,CSV 文件的文件扩展名并不重要,只要您为 QGIS 指定文件类型即可。
准备工作 我们将使用一个包含点特征的样本 CSV 文件,这些特征代表一个区域内感兴趣点的位置。
将其保存到您的根目录或主目录下的 qgis_data/ms 目录中。
如何操作… 我们将构建一个用于将 CSV 作为矢量图层加载的 URI 字符串。描述 CSV 结构的所有参数都包含在以下 URI 中:
QgsMapLayerRegistry.instance().addMapLayers([layer])
我们使用 delimitedtext 数据提供者加载图层:
layer = QgsVectorLayer(uri,"MS Features" ,"delimitedtext" )
最后,我们使用图层的坐标参考系统(CRS)完成 uri:
uri += """crs=epsg:4326"""
uri += """watchFile=no&"""
uri += """subsetIndex=no&"""
uri += """spatialIndex=no&"""
uri += """yField=PRIM_LAT_DEC&"""
uri += """xField=PRIM_LONG_DEC&"""
接下来,我们告诉 QGIS 去除字段两端的任何空格:
uri += """trimFields=Yes&"""
现在,我们指定我们的分隔符,它是一个管道('|' ),作为一个 URL 编码值:
uri += """delimiter=%7C&"""
接下来,我们告诉 QGIS 该文件是 CSV 文件:
uri = """file:///qgis_data/ms/MS_Features.txt?"""
它是如何工作的… URI 非常详细,但这是必要的,以便 QGIS 获取足够的信息来正确加载图层。在这个简单的例子中,我们使用了字符串,但使用 QUrl 对象更安全,因为它为您处理编码。QUrl 类的文档在 Qt 文档中,网址为 qt-project.org/doc/qt-4.8/qurl.html。
注意,在 URI 中,我们告诉 QGIS 类型是 CSV ,但当我们加载图层时,类型是 delimitedtext 。只要所有列都平衡,QGIS 会忽略空字段。
还有更多… 如果你在加载图层时遇到困难,可以使用 QGIS 添加分隔文本图层…对话框,在图层 菜单下找出正确的参数。一旦图层加载成功,你可以查看其元数据以了解 QGIS 构建的用于加载它的 URI。你也可以通过使用 layer.source() 方法程序化地从已加载的分隔文本图层中获取正确的参数。当然,这两种方法都适用于任何类型的图层,而不仅仅是分隔文本图层。然而,与其他图层类型不同,你无法在 QGIS 中编辑分隔文本图层。
第三章。编辑向量数据
在内存中创建向量层
向向量层添加点要素
向向量层添加线要素
向向量层添加多边形要素
向向量层添加一组属性
向向量层添加字段
将 shapefile 属性表连接到 CSV 文件
移动向量层几何形状
修改向量层属性
删除向量层几何形状
删除向量层字段
删除向量层属性
重投影向量层
将 shapefile 转换为 Keyhole 标记语言 (KML)
合并 shapefile
分割 shapefile
通用化向量层
溶解向量形状
在向量形状上执行联合操作
向量层栅格化
简介 本章详细介绍了如何使用 Python API 编辑 QGIS 向量数据。QgsVectorLayer 对象包含了添加、编辑和删除要素的基本功能。所有其他地理空间操作都可以通过 处理工具箱 或甚至通过自定义脚本来访问。
在内存中创建向量层 有时,你需要创建一个临时数据集以快速输出,或者在更复杂的操作中作为中间步骤,而不需要实际将文件写入磁盘。PyQGIS 使用 内存层 允许你创建一个完整的向量数据集,包括几何形状、字段和属性,虚拟地。一旦创建了内存层,你就可以像处理从磁盘加载的向量层一样处理它。
准备工作 此配方完全在 PyQGIS 控制台中运行,因此不需要准备或外部资源。
如何做到… 我们将创建一个名为 Layer 1 的 Point 向量层,包含一些字段,然后验证它:
启动 QGIS。
从 插件 菜单中选择 Python 控制台 。
在 Python 控制台中创建一个 QgsVectorLayer,包括字段,并将其指定为内存数据提供者:
vectorLyr = QgsVectorLayer('Point?crs=epsg:4326&field=city:string(25)&field=population:nt' ,'Layer 1' ,"memory" )
它是如何工作的… QgsVectorLayer 需要三个参数。最后一个参数指定类型,在这种情况下是 memory。第二个参数指定图层名称。通常,第一个参数是磁盘上文件的路径,用于创建图层。在内存层的情况下,第一个参数成为图层的构建字符串。该格式使用遵循 key = value 约定的查询参数。我们首先指定坐标参考系统,然后指定我们想要的字段。在这种情况下,我们指定第一个字段,一个用于城市名称的字符串字段,然后是一个用于人口的整数字段。
更多内容… 你可以很容易地看到如何用字符串描述图层属性表结构可能会变得难以管理。你还可以使用 Python-有序字典动态构建字符串,如下面的步骤所示。
vectorLyr = QgsVectorLayer('Point?crs=epsg:4326&' + path,'Layer 1' ,"memory" )
接下来,通过连接一个 Python 列表推导式的输出构建一个字符串,该列表推导式遍历有序字典:
path = '&' .join(['field={}:{}' .format (k,v) for k,v in fields.items()])
fields = OrderedDict([('city' ,'str(25)' ), ('population' ,'int' )])
首先,你需要导入 OrderedDict 容器,它记得键插入的顺序:
from collections import OrderedDict
向矢量图层添加点要素 此食谱执行了从 shapefile 实例化的矢量图层可能的最简单编辑。我们将向现有的点图层添加一个点。
准备工作 对于这个食谱,请从压缩包中下载 shapefile。
将 .shp、.shx 和 .dbf 文件提取到 /qgis_data/nyc 目录。
如何操作… 我们将从 shapefile 加载矢量图层,创建一个新的点几何对象,创建一个新的要素,设置几何形状,并将其添加到图层的数据提供者。最后,我们将更新图层的范围,以确保图层的边界框包含新的点:
启动 QGIS。
从 插件 菜单中选择 Python 控制台 。
vectorLyr.updateExtents()
现在,将创建一个新的 QgsFeature 对象来存放几何形状:
接下来,使用 QgsGeometry 对象创建一个新的点:
pnt = QgsGeometry.fromPoint(QgsPoint(-74.80 ,40.549 ))
vpr = vectorLyr.dataProvider()
vectorLyr = QgsVectorLayer('/qgis_data/nyc/NYC_MUSEUMS_GEO.shp' ,'Museums' ,"ogr" )
它是如何工作的… PyQGIS 将图层内的点抽象为四个级别。最低级别是 QgsPoint 对象,它包含的不仅仅是点的坐标。此对象被添加到一个抽象的 QgsGeometry 对象中。此对象成为 QgsFeature 对象的几何部分,该对象还具有存储和管理属性的能力。所有要素都由 QgsDataProvider 对象管理。数据提供者管理图层的地理空间方面,以将其与样式和其他与呈现相关的部分分开。QGIS 在 Python 中还有另一种编辑方法,称为 编辑缓冲区 。当你使用编辑缓冲区时,可以显示更改,但除非你提交它们,否则这些更改不是永久的。这种编辑方法最常见的使用场景是在 GUI 应用程序中,用户可能会选择通过取消编辑会话来回滚更改。"PyQGIS 开发者食谱"中有一个使用和编辑缓冲区的 Python 示例,可在 docs.qgis.org/2.6/en/docs/pyqgis_developer_cookbook/vector.html 找到。
向矢量图层添加线要素 在 QGIS 中向矢量图层添加一行与添加单个点相同,但在这里你只需向 QgsGeometry 对象添加更多点。
准备工作 对于这个配方,您需要下载一个包含两个线特征的压缩线形状文件。
将 ZIP 文件解压到您 /qgis_data 目录中名为 paths 的目录中。
如何操作… 在这个配方中,我们将从形状文件中加载线图层,构建点列表,创建一个新的几何对象,并将点作为线添加。我们还将创建一个新的特征,设置几何形状,并将其添加到图层的数据提供者。最后,我们将更新图层的范围,以确保图层的边界框包含新的特征:
启动 QGIS。
从 插件 菜单中选择 Python 控制台 。
vpr.addFeatures([f])
vectorLyr.updateExtents()
f = QgsFeature()
f.setGeometry(line)
line = QgsGeometry.fromPolyline(points)
points = []
points.append(QgsPoint(430841 ,5589485 ))
points.append(QgsPoint(432438 ,5575114 ))
points.append(QgsPoint(447252 ,5567663 ))
vpr = vectorLyr.dataProvider()
vectorLyr = QgsVectorLayer('/qgis_data/paths/paths.shp' ,'Paths' ,"ogr" )
vectorLyr.isValid()
它是如何工作的… 与 QGIS 中的所有几何形状一样,我们使用构建点、几何、特征和数据提供者的四步流程来添加线。有趣的是,QgsGeometry 对象接受 Python 列表作为点的集合,而不是像 QgsPoint 对象那样创建正式的对象。
向矢量层添加多边形特征 在这个配方中,我们将向图层添加一个多边形。多边形是最复杂的几何形状之一。然而,在 QGIS 中,API 与线非常相似。
准备工作 对于这个配方,我们将使用一个简单的多边形形状文件。
将此形状文件解压到您 /qgis_data 目录中名为 polygon 的文件夹中。
如何操作… 此配方将遵循标准的 PyQGIS 流程,加载图层、构建特征并将其添加到图层的数据提供者,如下所示:
启动 QGIS。
从 插件 菜单中选择 Python 控制台 。
f = QgsFeature()
f.setGeometry(poly)
接下来,创建一个几何对象并将点作为多边形导入。我们将在另一个列表中嵌套我们的点列表,因为多边形可以有内环,这些内环将包含添加到该列表的附加点列表:
poly = QgsGeometry.fromPolygon([points])
points = []
points.append(QgsPoint(-123.26 ,49.06 ))
points.append(QgsPoint(-127.19 ,43.07 ))
points.append(QgsPoint(-120.70 ,35.21 ))
points.append(QgsPoint(-115.89 ,40.02 ))
points.append(QgsPoint(-113.04 ,48.47 ))
points.append(QgsPoint(-123.26 ,49.06 ))
vpr = vectorLyr.dataProvider()
vectorLyr = QgsVectorLayer('/qgis_data/polygon/polygon.shp' ,'Polygon' ,"ogr" )
vectorLyr.isValid()
它是如何工作的… 添加多边形与添加线非常相似,有一个关键的区别是一个常见的陷阱。最后一个点必须与第一个点相同,以便闭合多边形。如果您不重复第一个点,您不会收到任何错误,但多边形将不会在 QGIS 中显示,这可能会很难调试。
向矢量层添加一组属性 每个 QGIS 特征有两个部分,几何形状和属性。在这个菜谱中,我们将为现有数据集的图层添加一个属性。
准备工作 我们将使用纽约市博物馆数据的点 shapefile。
将此 shapefile 提取到 /qgis_data/nyc 目录。
如何做… 一个特征必须有几何形状,但不需要属性。因此,我们将创建一个新特征,添加一些属性,然后将所有内容添加到图层中,如下所示:
启动 QGIS。
从 插件 菜单中选择 Python 控制台 。
vpr.addFeatures([f])
vectorLyr.updateExtents()
现在,我们能够添加一个新属性。添加属性类似于更新 Python 字典,如下所示:
f['NAME' ]='Python Museum'
接下来,获取我们将需要创建新特征的图层的 fields 对象:
现在,创建一个点几何形状,在这个例子中是一个新的博物馆:
pnt = QgsGeometry.fromPoint(QgsPoint(-74.13401 ,40.62148 ))
接下来,访问图层的数据提供者,以便我们可以获取字段列表:
vpr = vectorLyr.dataProvider()
vectorLyr = QgsVectorLayer('/qgis_data/nyc/NYC_MUSEUMS_GEO.shp' ,'Museums' ,"ogr" )
vectorLyr.isValid()
它是如何工作的… PyQGIS 属性定义为有序的 array。引用字段的语法类似于 Python 字典的语法。我们使用图层的数据提供者对象来执行实际的编辑。当我们使用这种方法时,在图层对象级别不会触发任何信号。如果我们只是尝试在文件系统上编辑数据,那是可以的,但如果图层将被添加到地图画布以显示或用户交互,那么你应该使用 QgsVectorLayer 对象中的编辑缓冲区。这个编辑缓冲区允许你提交或回滚更改,并跟踪更改时的图层状态。
向矢量图层添加字段 这个菜谱演示了如何向图层添加新字段。每个字段代表数据集中新列的一个新属性。当你添加一个新属性时,所有特征都将该字段的索引设置为 NULL。
准备工作 我们将使用其他菜谱中使用的纽约市博物馆的 shapefile。
将此 shapefile 提取到 /qgis_data/nyc。
如何做… 图层的所有数据管理都通过图层的数据提供者来处理,字段也不例外。我们将加载图层,访问数据提供者,定义新字段,并最终完成更改,如下所示:
启动 QGIS。
从 插件 菜单中选择 Python 控制台 。
现在,添加一个 QgsField 对象的 Python 列表,它定义了字段名称和类型。在这种情况下,我们将添加一个名为 Admission 的字段,类型为 Double:
vpr.addAttributes([QgsField("Admission" , QVariant.Double)])
vpr = vectorLyr.dataProvider()
vectorLyr = QgsVectorLayer('/qgis_data/nyc/NYC_MUSEUMS_GEO.shp' ,'Museums' ,"ogr" )
vectorLyr.isValid()
首先,你必须导入 Qt 库的数据类型,PyQGIS 使用这些数据类型来指定图层字段的类型:
from PyQt4.QtCore import QVariant
它是如何工作的… QGIS 中 fields 和 attributes 使用的命名约定有些不一致,如果您使用过其他 GIS 软件包,可能会感到困惑。在 QGIS 中,一列是一个具有名称和类型的 field。attribute table 为每个 field 列和每个 feature 行保存一个值。然而,在 QgsVectorDataProvider 对象中,您使用 addAttributes() 方法添加一个新的 field 列。在其他 GIS 软件中,您可能会看到 field 和 attribute 的使用颠倒。
将 shapefile 属性表连接到 CSV 文件 将属性表与其他数据库表连接允许您使用空间数据集来引用没有几何形状的数据集,使用数据表之间的公共键。这种用例的一个非常常见的例子是将人口普查属性向量的数据集与更详细的人口普查属性数据集连接起来。在这里,我们将演示如何将美国人口普查跟踪文件与包含更深入信息的详细 CSV 文件连接起来。
准备工作 对于这个配方,您需要一个包含适当人口普查数据的 tract shapefile 和一个 CSV 文件。
将这些数据提取到名为 /qgis_data/census 的目录中。
如何操作… 连接操作相当复杂。我们将执行此操作,并将具有连接属性的图层保存为新的 shapefile。然后我们将加载新的图层,并将字段计数与原始图层进行比较,以确保连接发生。我们将使用术语 目标图层 和 连接图层。目标图层 将是 shapefile,而 连接图层 将是一个 CSV 文件,其中包含我们想要添加到 shapefile 的一些额外字段。为此,请执行以下步骤:
启动 QGIS。
从 插件 菜单中选择 Python 控制台 。
joinedLyr.dataProvider().fields().count()
vectorLyr.dataProvider().fields().count()
现在,将新的 shapefile 重新加载为图层以进行验证:
joinedLyr = QgsVectorLayer('/qgis_data/census/joined.shp' ,'Joined' ,"ogr" )
接下来,将连接的 shapefile 写入磁盘上的新文件:
QgsVectorFileWriter.writeAsVectorFormat(vectorLyr,"/qgis_data/census/joined.shp" ,"CP120" ,None ,"ESRI Shapefile" )
将 memoryCache 属性设置为 True 以加快对连接数据的访问:
info.targetFieldName = "GEOID"
接下来,指定 CSV 文件中的关键字段,其值与 shapefile 中的值相对应:
info.joinFieldName = "GEOid2"
info.joinLayerId = infoLyr.id ()
info = QgsVectorJoinInfo()
完成此操作后,您必须将两个图层添加到地图注册表中,以便两个图层可以交互进行连接。但是,将可见性设置为 False,以便图层不在地图上显示:
QgsMapLayerRegistry.instance().addMapLayers([vectorLyr, infoLyr], False )
infoLyr = QgsVectorLayer('/qgis_data/census/ACS_12_5YR_S1901_with_ann.csv' ,'Census' ,"ogr" )
infoLyr.isValid()
vectorLyr = QgsVectorLayer('/qgis_data/census/hancock_tracts.shp' ,'Hancock' ,"ogr" )
vectorLyr.isValid()
它是如何工作的… 这个菜谱触及了 PyQGIS API 的边缘,迫使你使用一些变通方法。大多数数据操作菜谱可以通过编程方式执行,而无需将数据写入磁盘或加载图层到地图上,但连接操作不同。因为 QgsVectorJoinInfo 对象需要 CSV 图层的图层 ID,我们必须将两个图层都添加到地图图层注册表中。幸运的是,如果我们只是尝试编写数据操作脚本,我们可以不使它们可见。连接 操作被设计为查询数据集的临时操作。奇怪的是,PyQGIS 允许你创建 连接,但你不能查询它。这种限制是如果你想要处理连接数据,你必须将其写入新的 shapefile 并重新加载的原因。幸运的是,PyQGIS 允许你这样做。
更多内容… 你可以在处理工具箱脚本中找到一个绕过 PyQGIS 限制的替代方法,该脚本在 Python 中手动匹配连接数据,在 github.com/rldhont/Quantum-GIS/blob/master/python/plugins/processing/algs/qgis/JoinAttributes.py。
移动矢量图层几何形状 有时,你需要更改特征的位置。你可以通过删除和重新添加特征来完成此操作,但 PyQGIS 提供了一个简单的方法来更改几何形状。
准备工作 将此 shapefile 提取到 /qgis_data/nyc.。
如何操作… 我们将加载 shapefile 作为矢量图层,验证它,定义我们想要更改的特征 ID,创建新的几何形状,并在图层中更改特征。为此,执行以下步骤:
启动 QGIS。
从 插件 菜单中选择 Python 控制台 。
最后,更改几何形状并用我们的新几何形状替换它,指定特征 ID:
vectorLyr.dataProvider().changeGeometryValues({feat_id : geom})
geom = QgsGeometry.fromPoint(QgsPoint(-74.20378 ,40.89642 ))
vectorLyr = QgsVectorLayer('/qgis_data/nyc/NYC_MUSEUMS_GEO.shp' ,'Museums' ,"ogr" )
vectorLyr.isValid()
它是如何工作的… changeGeometryValues() 方法使得编辑变得轻而易举。如果我们不得不删除并重新添加特征,我们就必须经历读取属性、保留它们,然后使用新特征重新添加它们的麻烦。你必须当然知道你想要更改的特征 ID。你如何确定这个 ID 取决于你的应用程序。通常,你会查询属性以找到特定的值,或者你可以执行某种空间操作。
更改矢量图层特征的属性 在特征中更改属性的过程简单明了,并且得到了 PyQGIS API 的良好支持。在这个菜谱中,我们将更改单个属性,但您可以一次性更改特征的多个属性。
准备工作 您需要使用其他菜谱中使用的纽约市博物馆的 shapefile。
将此 shapefile 提取到 /qgis_data/nyc。
如何操作… 我们将加载 shapefile 作为矢量图层,验证它,定义我们想要更改的字段的特征 ID,获取我们将更改的字段名称的索引,定义新的属性值作为属性索引和值,并在图层中更改特征。为此,我们需要执行以下步骤:
启动 QGIS。
从 插件 菜单中选择 Python 控制台 。
vectorLyr.dataProvider().changeAttributeValues({fid1:attr1, fid2:attr2})
现在,创建属性索引和新值的 Python 字典,在这个例子中是一个虚构的电话号码:
attr1 = {tel:"(555) 555-1111" , city:"NYC" }
attr2 = {tel:"(555) 555-2222" , city:"NYC" }
然后,获取您想要更改的字段的索引,即电话号码和城市名称:
tel = vectorLyr.fieldNameIndex("TEL" )
city = vectorLyr.fieldNameIndex("CITY" )
vectorLyr = QgsVectorLayer('/qgis_data/nyc/NYC_MUSEUMS_GEO.shp' ,'Museums' ,"ogr" )
vectorLyr.isValid()
它是如何工作的… 修改属性与在特征内修改几何形状非常相似。在这个例子中,我们明确命名了特征 ID,但在实际程序中,您会收集这些 ID 作为其他过程输出的部分,例如空间选择。这种类型空间选择的例子可以在第二章的 通过几何形状过滤图层 菜谱中找到,在 查询矢量数据 部分。
删除矢量图层特征 在这个菜谱中,我们将完全从图层中删除一个特征,包括几何形状和属性。
准备工作 您需要使用其他菜谱中使用的纽约市博物馆的 shapefile。
将此 shapefile 提取到 /qgis_data/nyc。
如何操作… 我们需要做的只是加载图层,然后通过 ID 删除所需的特征,使用图层的数据提供者:
启动 QGIS。
从 插件 菜单中选择 Python 控制台 。
接下来,指定一个包含特征 ID 的 Python 列表。在这种情况下,我们有两个:
vectorLyr.dataProvider().deleteFeatures([22 ,95 ])
vectorLyr = QgsVectorLayer('/qgis_data/nyc/NYC_MUSEUMS_GEO.shp' ,'Museums' ,"ogr" )
vectorLyr.isValid()
它是如何工作的… 此操作无法更简单或设计得更好。我们可以以多种方式编程地将特征 ID 填充到 Python 列表中。例如,我们可以使用这个菜谱中的第二章的 通过属性过滤图层 。然后,我们只需将此列表传递给图层的数据提供者,任务就完成了。
删除矢量图层属性 在这个菜谱中,我们将删除一个矢量层的整个属性以及所有特征字段。
准备工作 将此形状文件解压到 /qgis_data/nyc。
如何操作… 这个操作很简单。我们将加载和验证图层,使用图层的数据提供者通过索引删除属性,最后,我们将更新所有字段以删除孤立值。为此,我们需要执行以下步骤:
启动 QGIS。
从 插件 菜单中选择 Python 控制台 。
vectorLyr.dataProvider().deleteAttributes([1 ])
vectorLyr = QgsVectorLayer('/qgis_data/nyc/NYC_MUSEUMS_GEO.shp' ,'Museums' ,"ogr" )
vectorLyr.isValid()
工作原理… 由于我们正在更改图层数据的实际结构,我们必须调用图层的 updateFields() 方法来删除不再具有属性的字段值。
重新投影矢量层 我们将使用 QGIS 的处理工具箱来将一个图层重新投影到不同的坐标系。
准备工作 对于这个菜谱,我们需要密西西比州城市在密西西比州横墨卡托投影(EPSG 3814)中的形状文件。
将压缩的形状文件解压到名为 /qgis_data/ms 的目录中。
如何操作… 要重新投影图层,我们将简单地调用 qgis:reprojectlayer 处理算法,指定输入形状文件、新投影和输出文件名。为此,请执行以下步骤:
启动 QGIS。
从 插件 菜单中选择 Python 控制台 。
processing.runalg("qgis:reprojectlayer" ,"/qgis_data/ms/MSCities_MSTM.shp" ,"epsg:4326" ,"/qgis_data/ms/MSCities_MSTM_4326.shp" )
工作原理… 源数据最初在 EPSG 3814 中,但我们希望将其投影到 WGS 84 地理坐标系,这通常用于处理全球数据集,并且通常是 GPS 设备的默认坐标参考系统。目标 EPSG 代码是 4326。处理地图投影可能相当复杂。这个 QGIS 教程有一些更多示例,并解释了更多关于地图投影的信息,请参阅 manual.linfiniti.com/en/vector_analysis/reproject_transform.html。
将形状文件转换为 KML 在这个菜谱中,我们将把一个图层转换为 KML。KML 是 开放地理空间联盟 (OGC ) 标准,并且由 QGIS 所使用的底层 OGR 库支持。
准备工作 对于这个菜谱,下载以下压缩形状文件并将其解压到名为 /qgis_data/hancock 的目录中:
如何操作… 要将 shapefile 转换为 KML XML 格式,我们将加载图层,然后使用 QgsVectorFileWriter 对象将其保存为 KML:
启动 QGIS。
从 插件 菜单中选择 Python 控制台 。
接下来,使用文件写入器将其保存为 KML 文件,指定文件类型为 KML:
QgsVectorFileWriter.writeAsVectorFormat(vectorLyr,"/qgis_data/hancock/hancock.kml" ,"utf-8" , dest_crs,"KML" )
然后,建立目标坐标参考系统。KML 始终应在 EPS:4326:
dest_crs = QgsCoordinateReferenceSystem(4326 )
vectorLyr = QgsVectorLayer('/qgis_data/hancock/hancock.shp' ,'Hancock' ,"ogr" )
vectorLyr.isValid()
它是如何工作的… 你将在你的 shapefile 旁边的目录中结束,得到一个 KML 文件。KML 支持样式信息。QGIS 使用一些默认的样式信息,你可以通过手动使用文本编辑器或使用 Python 的 ElementTree 等 XML 库编程方式来更改它们。KML 是你可以使用此方法导出的许多标准矢量格式之一。
合并 shapefile 将具有匹配投影和属性结构的 shapefile 合并是一个非常常见的操作。在 QGIS 中,合并矢量数据集的最佳方式是使用 Windows 和 OSX 上包含的另一个 GIS 系统 SAGA 。在其他平台上,你必须单独安装 SAGA 并在处理工具箱配置中激活它。在 PyQGIS 中,你可以通过处理工具箱访问 SAGA 函数。SAGA 是另一个与 QGIS 类似的开源 GIS。然而,这两个包都有优点和缺点。通过处理工具箱使用 SAGA,你可以拥有两个系统的最佳之处。
准备工作 在这个菜谱中,我们将合并相邻区域的几个建筑足迹 shapefile 到一个单独的 shapefile 中。
将压缩的 shapefile 解压到名为 /qgis_data/tiled_footprints 的目录中。
如何做… 我们将在数据目录中定位所有 .shp 文件,并将它们交给 saga:mergeshapeslayers 对象以进行合并。
启动 QGIS。
从 插件 菜单中选择 Python 控制台 。
最后,运行将合并的 shapefile 加载到地图上的算法:
processing.runandload("saga:mergeshapeslayers" ,files.pop(0 ),";" .join(files),out)
然后,指定合并的 shapefile 的输出名称:
files = glob.glob(pth + "*.shp" )
pth = "/qgis_data/tiled_footprints/"
导入 Python 的 glob 模块以进行通配符文件匹配:
它是如何工作的… 该算法接受一个基础文件,然后是一个分号分隔的附加文件列表,最后接受输出文件名。glob 模块创建一个文件列表。为了获取基础文件,我们使用列表的 pop() 方法获取第一个文件名。然后,我们使用 Python 字符串的 join() 方法来创建所需的分隔列表。
还有更多… QGIS 通过 processing 模块提供自己的合并方法,称为 qgis:mergevectorlayers,但它有限,因为它只能合并两个文件。SAGA 方法允许合并任意数量的文件。
分割 shapefile 有时,您需要分割 shapefile,以便将较大的数据集分解成更易于管理的尺寸,或者隔离特定的感兴趣区域。Processing 工具箱中有一个脚本可以按属性分割 shapefile。尽管它作为编写处理脚本的示例提供,但它非常有用。
准备工作
将压缩的 shapefile 提取到名为 /qgis_data/census 的目录中。
接下来,使用以下步骤将脚本添加到 Processing 工具箱中:
将脚本下载到您的 /qgis_data/ 目录中。
在 QGIS Processing 工具箱 中,打开 脚本 树菜单,然后转到 工具 子菜单。
然后,双击 从文件添加脚本 命令。
在 文件 对话框中,导航到脚本。选择 脚本 并点击 打开 按钮。
您还需要以下脚本用于 Processing 工具箱:
https://geospatialpython.googlecode.com/svn/Split_vector_layer_by_attribute.py
现在舞台已经搭建好。执行下一节中的步骤以分割 shapefile。
如何操作… 此菜谱与运行算法并指定文件名和数据属性一样简单。执行以下步骤:
启动 QGIS。
从 插件 菜单,选择 Python 控制台 。
processing.runalg("script:splitvectorlayerbyattribute" ,pth + "GIS_CensusTract_poly.shp" ,"COUNTY_8" ,pth + "split" )
pth = "/qgis_data/census/"
它是如何工作的…
泛化矢量层 泛化几何形状,也称为简化,通过从矢量层中删除点来减少存储在磁盘上的数据所需的空间、在网络中移动它所需的带宽以及使用它进行分析或显示在 QGIS 中所需的处理能力。在许多情况下,层的几何形状包含冗余点以及可以删除而不改变层空间属性的直线,除了拓扑约束之外。
准备工作 将压缩的 shapefile 提取到名为 /qgis_data/ms 的目录中。
如何操作… 在 QGIS 中,泛化是固有的,但我们将通过 Processing 工具箱使用 qgis:simplifygeometries 算法在 PyQGIS 中访问它,如下所示:
启动 QGIS。
从 插件 菜单,选择 Python 控制台 。
现在,运行 processing 算法,指定算法名称、输入数据、容差值、点之间的间距——这定义了在删除一个点之前两个点在地图单位中的接近程度——以及输出数据集的名称:
processing.runandload("qgis:simplifygeometries" ,"/qgis_data/ms/mississippi.shp" ,0.3 ,"/qgis_data/ms/generalize.shp" )
它是如何工作的… simplifygeometries 命令的简单性使得操作看起来很简单。然而,简化本身相当复杂。相同的设置很少能在多个数据集中产生理想的结果。
在以下可视化中,可以看到这个菜谱中的 shapefile 最初非常复杂,有数百个点:
溶解矢量形状 溶解形状可以有两种不同的形式。您可以通过整个数据集的外部边界合并一组相邻的形状,或者您也可以通过具有相同属性值的相邻形状进行分组。
准备工作 从 GIS 人口普查区 shapefile,其中包含几个县的人口普查区。
将其提取到 /qgis_data 目录下的一个名为 census 的目录中。
如何操作… 我们将使用处理工具箱来完成这个菜谱,并特别使用一个本地 QGIS 算法 dissolve,如下所示:
启动 QGIS。
从 插件 菜单中选择 Python 控制台 。
接下来,运行 dissolve 算法,指定输入数据——False 表示我们不想将所有形状溶解为一个,而是使用属性——我们想要使用的属性,以及输出文件名:
processing.runandload("qgis:dissolve" ,"/qgis_data/census/GIS_CensusTract_poly.shp" ,False ,"COUNTY_8" ,"/qgis_data/census/dissovle.shp" )
如何工作… 通过仅将语句中的布尔值更改为 True,我们可以将所有相邻的形状溶解为一个。还重要的是要注意,QGIS 将每个组中遇到的第一个形状的字段分配给最终形状。在大多数情况下,这将使属性几乎无用。这项操作主要是空间任务。
你可以看到,在原始层中,每个县边界都有若干个人口普查区,如下图所示:
对矢量形状执行并操作 并联将两个重叠的形状合并为一个。这个任务可以通过处理工具箱轻松完成。在这个菜谱中,我们将合并覆盖建筑的轮廓与主建筑的足迹。
准备工作 您可以从建筑文件,并将其提取到名为 /qgis_data/union 的目录中。
如何操作… 我们需要做的只是运行 qgis:union 算法,如下所示:
启动 QGIS。
从 插件 菜单中选择 Python 控制台 。
现在,通过指定两个输入形状和一个输出文件来运行算法:
processing.runandload("qgis:union" ,"/qgis_data/union/building.shp" ,"/qgis_data/union/walkway.shp" ,"/qgis_data/union/union.shp" )
如何工作… 如您从命令的结构中可以看出,此工具一次只能合并两个形状。它找到两个形状相交的地方,然后移除重叠部分,在交点处将它们连接起来。
在原始数据中,形状文件最初是两个不同的形状,如图所示:
一旦合并完成,形状现在是一个形状文件,重叠部分是一个单独的特征,如图所示:
栅格化矢量层 有时,栅格数据集是显示复杂矢量数据(在地图中仅作为背景)的最有效方式。在这些情况下,你可以栅格化矢量层将其转换为图像。
准备工作 我们将演示如何使用以下等高线形状文件栅格化矢量层。
将其提取到您的 /qgis_data/rasters 目录中。
如何操作… 我们将运行 gdalogr:rasterize 算法将此矢量数据转换为栅格,如下所示:
启动 QGIS。
从 插件 菜单中选择 Python 控制台 。
运行算法,指定输入数据、需要绘制栅格值的属性、0 以指定输出像素维度而不是地图维度、宽度和高度,以及最终的输出栅格名称:
processing.runalg("gdalogr:rasterize" ,"/qgis_data/rasters/contour.shp" ,"ELEV" ,0 ,1000 ,1000 ,"/qgis_data/rasters/contour.tif" )
它是如何工作的… 如果您想以地图单位指定输出维度,请使用 1 代替 0。请注意,一旦您将其转换为栅格,该层的符号就会变得固定。栅格也不再是动态可缩放的。
微信扫一扫,关注极客日志 微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
相关免费在线工具 加密/解密文本 使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
curl 转代码 解析常见 curl 参数并生成 fetch、axios、PHP curl 或 Python requests 示例代码。 在线工具,curl 转代码在线工具,online
Base64 字符串编码/解码 将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
Base64 文件转换器 将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
Markdown转HTML 将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online
HTML转Markdown 将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online