ArcGIS-Python-编程秘籍-全-

ArcGIS Python 编程秘籍(全)

原文:zh.annas-archive.org/md5/9943ade5326208736a99f19021697ccc

译者:飞龙

协议:CC BY-NC-SA 4.0

前言

ArcGIS 是 Esri 提供的行业标准地理信息系统。

本书将向你展示如何使用 Python 编程语言为 ArcGIS for Desktop 环境创建地理处理脚本、工具和快捷方式。

通过展示如何使用 Python 编程语言与 ArcGIS for Desktop 一起自动化地理处理任务、管理地图文档和图层、查找和修复损坏的数据链接、编辑要素类和表格中的数据等,本书将使你成为一个更有效率和高效的 GIS 专业人士。

《使用 Python 编程 ArcGIS 第二版 Cookbook*》,首先在 ArcGIS for Desktop 环境下介绍基本的 Python 编程概念。采用如何操作的指导风格,接下来你将学习如何使用 Python 来自动化常见的 ArcGIS 地理处理任务。

在这本书中,你还将涵盖一些特定的 ArcGIS 脚本主题,这些主题将帮助你在使用 ArcGIS 时节省时间和精力。这些主题包括管理地图文档文件、自动化地图制作和打印、查找和修复损坏的数据源、创建自定义地理处理工具,以及处理要素类和表格等。

在《使用 Python 编程 ArcGIS 第二版 Cookbook*》中,你将学习如何使用一种以实现特定任务为中心的实用方法,以烹饪书风格的格式编写地理处理脚本。

本书涵盖的内容

第一章, ArcGIS 的 Python 语言基础,将涵盖 Python 中许多基本语言结构。最初,你将学习如何创建新的 Python 脚本或编辑现有脚本。从那里,你将了解语言特性,如给你的代码添加注释、变量和内置的打字系统,这些使得使用 Python 编程变得简单和紧凑。此外,我们将探讨 Python 提供的各种内置数据类型,如字符串、数字、列表和字典。除此之外,我们还将涵盖语句,包括决策支持和循环结构,用于在代码中做出决策,以及/或多次遍历代码块。

第二章, 管理地图文档和图层,将使用 ArcPy 映射模块来管理地图文档和图层文件。你将学习如何从地图文档文件中添加和删除地理图层,将图层插入到数据框架中,以及在地图文档中移动图层。你还将学习如何更新图层属性和符号。

第三章, 查找和修复损坏的数据链接,将教你如何在地图文档文件中生成损坏数据源列表,并应用各种 ArcPy 映射函数来修复这些数据源。你将学习如何自动化修复多个地图文档中数据源的过程。

第四章, 自动化地图制作和打印,将教会你如何自动化创建生产质量地图的过程。这些地图可以打印出来,导出为图像文件格式,或导出为 PDF 文件,以便包含在地图集中。

第五章, 从脚本中执行地理处理工具,将教会你如何编写脚本,访问并运行 ArcGIS 提供的地理处理工具。

第六章, 创建自定义地理处理工具,将教会你如何创建可以添加到 ArcGIS 并与其他用户共享的自定义地理处理工具。自定义地理处理工具附加到一个 Python 脚本上,该脚本以某种方式处理或分析地理数据。

第七章, 查询和选择数据,将教会你如何从脚本中执行“按属性选择”和“按位置选择”地理处理工具以选择要素和记录。你将学习如何构建为“按属性选择”工具提供可选的 WHERE 子句的查询。还将介绍使用要素层和表格视图作为临时数据集。

第八章, 使用 ArcPy 数据访问模块与要素类和表格,将教会你如何创建地理处理脚本,从地理数据层和表格中选择、插入或更新数据。使用新的 ArcGIS 10.1 数据访问模块,地理处理脚本可以从要素类和表格创建内存中的数据表,称为游标。你将学习如何创建各种类型的游标,包括搜索、插入和更新。

第九章, 列出和描述 GIS 数据,将教会你如何通过使用 ArcPy Describe 函数来获取关于地理数据集的描述性信息。作为多步骤过程的第一步,地理处理脚本通常需要生成地理数据列表,然后对这些数据集执行各种地理处理操作。

第十章, 使用插件自定义 ArcGIS 界面,将教会你如何通过创建 Python 插件来自定义 ArcGIS 界面。插件提供了一种通过模块化代码库执行特定操作的方式,将用户界面元素添加到 ArcGIS 桌面中。界面组件可以包括按钮、工具、工具栏、菜单、组合框、工具面板和应用扩展。插件使用 Python 脚本和一个 XML 文件创建,该文件定义了用户界面应该如何显示。

第十一章,错误处理和故障排除,将向您介绍如何在地理处理脚本执行过程中优雅地处理发生的错误和异常。ArcPy 和 Python 错误可以使用 Python 的 try/except 结构捕获并相应处理。

第十二章,使用 Python 进行高级 ArcGIS,涵盖了使用 Python 的 ArcGIS REST API 访问由 ArcGIS Server 和 ArcGIS Online 公开的服务。您将学习如何进行 HTTP 请求并解析响应、导出地图、查询地图服务、执行地理编码等。本章还涉及一些与 ArcPy FieldMap 和 FieldMappings 相关以及与 ValueTables 一起工作的杂项主题。

第十三章,在 ArcGIS Pro 中使用 Python,涵盖了新 ArcGIS Pro 环境与 ArcGIS for Desktop 在 Python 方面的某些区别,特别是用于编写和执行代码的 Python 窗口。

附录 A,自动化 Python 脚本,将教会您如何安排地理处理脚本在指定时间运行。许多地理处理脚本需要很长时间才能完全执行,需要定期在工作时间之外安排运行。您将学习如何创建包含地理处理脚本的批处理文件,并在指定时间执行这些文件。

附录 B,每个 GIS 程序员都应该知道的五个 Python 食谱,将教会您如何编写使用 Python 执行各种通用任务的脚本。这些任务,如读取和写入定界文本文件、发送电子邮件、与 FTP 服务器交互、创建 ZIP 文件以及读取和写入 JSON 和 XML 文件,都是常见的。每个 GIS 程序员都应该知道如何编写包含这些功能的 Python 脚本。

您需要为本书准备的材料

要完成本书中的练习,您需要安装 ArcGIS for Desktop 10.3,许可证级别为基本、标准或高级。安装 ArcGIS for Desktop 10.3 还将安装 Python 2.7 以及 IDLE Python 代码编辑器。文本也适用于使用 ArcGIS for Desktop 10.2 或 10.1 的用户。第十三章,在 ArcGIS Pro 中使用 Python,需要 ArcGIS Pro 版本 1.0。

本书面向的对象

《使用 Python 编程 ArcGIS 烹饪书,第二版》是为希望用 Python 革新其 ArcGIS 工作流程的 GIS 专业人员编写的。无论您是 ArcGIS 的新手还是经验丰富的专业人士,您几乎每天都会花时间执行各种地理处理任务。本书将教会您如何使用 Python 编程语言来自动化这些地理处理任务,并使您成为一个更高效、更有效的 GIS 专业人员。

部分

在本书中,您将找到几个频繁出现的标题(准备工作、如何操作、工作原理、更多内容、相关内容)。

为了清楚地说明如何完成食谱,我们使用以下这些部分:

准备工作

本节告诉您在食谱中可以期待什么,并描述了如何设置任何软件或任何为食谱所需的初步设置。

如何操作…

本节包含遵循食谱所需的步骤。

工作原理…

本节通常包含对前一个章节发生情况的详细解释。

更多内容…

本节包含有关食谱的附加信息,以便使读者对食谱有更深入的了解。

相关内容

本节提供了对其他有用信息的链接,以帮助读者了解食谱。

惯例

在本书中,您将找到多种文本样式,用于区分不同类型的信息。以下是一些这些样式的示例及其含义的解释。

文本中的代码词汇如下显示:“我们已使用 IDLE 加载了 ListFeatureClasses.py 脚本。”

代码块设置如下:

   import arcpy
   fc = "c:/ArcpyBook/data/TravisCounty/TravisCounty.shp"
   # Fetch each feature from the cursor and examine the extent # properties and spatial reference
   for row in arcpy.da.SearchCursor(fc, ["SHAPE@"]):
     # get the extent of the county boundary
     ext = row[0].extent
     # print out the bounding coordinates and spatial reference
     print("XMin: " + ext.XMin)
     print("XMax: " + ext.XMax)
     print("YMin: " + ext.YMin)
     print("YMax: " + ext.YMax)
     print("Spatial Reference: " + ext.spatialReference.name)

当我们希望您注意代码块中的特定部分时,相关的行或项目将以粗体显示:

   import arcpy
   fc = "c:/data/city.gdb/streets"
   # For each row print the Object ID field, and use the SHAPE@AREA
   # token to access geometry properties
   with arcpy.da.SearchCursor(fc, ("OID@", "SHAPE@AREA")) as cursor:
     for row in cursor:
       print("Feature {0} has an area of {1}".format(row[0], row[1]))

任何命令行输入或输出都应如下编写:

[<map layer u'City of Austin Bldg Permits'>, <map layer u'Hospitals'>, <map layer u'Schools'>, <map layer u'Streams'>, <map layer u'Streets'>, <map layer u'Streams_Buff'>, <map layer u'Floodplains'>, <map layeru'2000 Census Tracts'>, <map layer u'City Limits'>, <map layer u'Travis County'>]

新术语重要词汇以粗体显示。屏幕上显示的词汇,例如在菜单或对话框中,在文本中如下显示:“转到开始 | 所有程序 | ArcGIS | Python 2.7 | IDLE”。

注意

警告或重要注意事项以如下框的形式出现。

小贴士

小贴士和技巧看起来像这样。

读者反馈

我们读者的反馈总是受欢迎的。请告诉我们您对这本书的看法——您喜欢或不喜欢什么。读者反馈对我们很重要,因为它帮助我们开发出您真正能从中获得最大收益的标题。

要向我们发送一般反馈,只需发送电子邮件至 <feedback@packtpub.com>,并在邮件主题中提及本书的标题。

如果您在某个主题上具有专业知识,并且您有兴趣撰写或为书籍做出贡献,请参阅我们的作者指南,网址为 www.packtpub.com/authors

客户支持

现在,您已经成为 Packt 书籍的骄傲拥有者,我们有一些事情可以帮助您从购买中获得最大收益。

下载示例代码

您可以从您在www.packtpub.com的账户下载示例代码文件,适用于您购买的所有 Packt Publishing 书籍。如果您在其他地方购买了这本书,您可以访问www.packtpub.com/support并注册,以便将文件直接通过电子邮件发送给您。

勘误

尽管我们已经尽最大努力确保内容的准确性,但错误仍然可能发生。如果您在我们的某本书中发现错误——可能是文本或代码中的错误——如果您能向我们报告这一点,我们将不胜感激。通过这样做,您可以避免其他读者的挫败感,并帮助我们改进本书的后续版本。如果您发现任何勘误,请通过访问www.packtpub.com/submit-errata,选择您的书籍,点击勘误提交表单链接,并输入您的勘误详情来报告它们。一旦您的勘误得到验证,您的提交将被接受,勘误将被上传到我们的网站或添加到该标题的勘误部分下的现有勘误列表中。

要查看之前提交的勘误表,请访问www.packtpub.com/books/content/support,并在搜索字段中输入书籍名称。所需信息将出现在勘误部分。

盗版

互联网上版权材料的盗版是一个跨所有媒体的持续问题。在 Packt,我们非常重视我们版权和许可证的保护。如果您在互联网上发现我们作品的任何非法副本,请立即提供位置地址或网站名称,以便我们可以寻求补救措施。

请通过发送链接到疑似盗版材料至 <copyright@packtpub.com> 来与我们联系。

我们感谢您在保护我们的作者和我们为您提供有价值内容的能力方面的帮助。

问题

如果您对本书的任何方面有问题,您可以通过发送邮件至 <questions@packtpub.com> 来联系我们,我们将尽力解决问题。

第一章:ArcGIS 的 Python 语言基础

Python 支持许多在其他语言中找到的编程结构。在本章中,我们将介绍 Python 中许多基本语言结构。最初,我们将介绍如何创建新的 Python 脚本和编辑现有脚本。从那里,我们将深入研究语言特性,例如在您的代码中添加注释,创建和分配数据到变量,以及 Python 的内置变量类型,这使得使用 Python 编码变得简单且紧凑。

接下来,我们将查看 Python 提供的各种内置数据类型,例如字符串、数字、列表和字典。类和对象是面向对象编程和 Python 语言中的基本概念。我们将向您介绍这些复杂的数据结构,您将在使用 ArcGIS 编写地理处理脚本时广泛使用它们。

除了这些,我们还将涵盖语句,包括决策支持和循环结构,以便在您的代码中做出决策,以及/或使用 with 语句多次遍历代码块,with 语句与 ArcPy 数据访问模块中的 cursor 对象广泛使用,这些对象用于插入、搜索和更新数据。最后,您将学习如何访问为 Python 语言提供额外功能的模块。到本章结束时,您将学习以下内容:

  • 如何在 IDLE 中创建和编辑新的 Python 脚本

  • 如何在 ArcGIS Python 窗口中创建和编辑脚本

  • Python 的语言特性

  • 注释和数据变量

  • 内置数据类型(字符串、数字、列表和字典)

  • 复杂数据结构

  • 循环结构

  • 额外的 Python 功能

使用 IDLE 进行 Python 脚本开发

如前言所述,当您安装 ArcGIS for Desktop 时,Python 也会安装,并附带一个名为 IDLE 的工具,允许您编写自己的代码。IDLE 代表 Integrated DeveLopment Environment。由于它与每个 ArcGIS for Desktop 安装一起提供,因此我们将使用 IDLE 来编写本书中的许多脚本,以及 ArcGIS for Desktop 中嵌入的 Python 窗口。随着您作为程序员的进步,您可能会发现比 IDLE 更喜欢的其他开发工具。还有许多其他开发环境可以考虑,包括 PyScripter、Wingware、Komodo 等。您选择哪种开发环境完全是个人喜好问题。您可以使用这些工具中的任何一个来编写代码。

Python 命令行窗口

要启动 Python 开发环境,您可以导航到 开始 | 所有程序 | ArcGIS | Python 2.7 | IDLE。请注意,ArcGIS 安装的 Python 版本将根据您安装的 ArcGIS 版本而有所不同。例如,ArcGIS 10.3 使用 Python 2.7,而 ArcGIS 10.0 使用 Python 2.6 版本。

将显示与以下截图类似的 Python 命令行窗口:

Python 外壳窗口

Python 外壳窗口用于显示脚本生成的输出和错误消息。初学者常见的错误是假设地理处理脚本将写入此外壳窗口。这不是事实。您需要创建一个单独的代码窗口来保存您的脚本。

虽然外壳窗口不用于编写整个脚本,但它可以用于交互式编写代码并立即获得反馈。ArcGIS 有一个内置的 Python 外壳窗口,您可以使用类似的方式使用它。我们将在下一章中检查 ArcGIS Python 窗口。

Python 脚本窗口

您的脚本将写入 IDLE 中的单独窗口,称为 Python 脚本窗口。要创建新的代码窗口,从 IDLE 壳窗口导航到 文件 | 新建窗口。将显示类似以下窗口:

Python 脚本窗口

您的 Python 脚本将写入这个新的代码窗口。每个脚本都需要保存到本地或网络驱动器。默认情况下,脚本以 .py 文件扩展名保存,以表示它是一个 Python 脚本。

编辑现有的 Python 脚本

可以通过从 IDLE 壳窗口选择 文件 | 打开 来打开现有的 Python 脚本文件。此外,您还可以通过在 Windows 资源管理器中右键单击文件并选择 使用 IDLE 编辑 来打开 Python 脚本,这将打开一个新的外壳窗口以及加载到 Python 脚本编辑器中的脚本。您可以在下面的屏幕截图中看到示例:

编辑现有的 Python 脚本

在这种情况下,我们已使用 IDLE 加载了 ListFeatureClasses.py 脚本。代码加载在脚本窗口中:

编辑现有的 Python 脚本

现在代码窗口已打开,您可以从头开始编写或编辑代码。您还可以使用 IDLE 界面进行一些基本的脚本调试。调试是识别和修复代码中错误的过程。

从 IDLE 执行脚本

一旦您在 IDLE 代码窗口中编写了地理处理脚本或打开了现有脚本,您就可以从界面中执行代码。IDLE 提供了允许您在运行脚本之前检查代码语法的功能。在代码窗口中,导航到 运行 | 检查模块 来执行代码的语法检查。

任何语法错误都会在外壳窗口中显示。如果没有语法错误,您应该只看到外壳窗口中的提示。虽然 IDLE 界面可以用来检查语法错误,但它不提供检查代码中逻辑错误的方法,也不提供其他开发环境中找到的更高级的调试工具,例如 PyScripter 或 Wingware。

一旦您确认代码中没有语法错误,您就可以运行脚本。导航到 运行 | 运行模块 来执行脚本:

从 IDLE 执行脚本

任何错误信息都将写入壳窗口,与 print 语句的输出和系统生成的消息一起。print 语句只是将文本输出到壳窗口。它通常用于更新正在运行的脚本的状态或用于调试代码。

使用 ArcGIS Python 窗口

在本教程中,您将学习如何使用 ArcGIS Python 窗口。在上一个部分,您学习了如何使用 Python 的 IDLE 开发环境,因此本部分将为您提供另一种编写地理处理脚本的替代方法。两种开发环境都可以使用,但人们通常会在 ArcGIS for Desktop Python 窗口中开始编写脚本,然后在脚本变得复杂时转向 IDLE 或其他开发环境。

ArcGIS Python 窗口

ArcGIS Python 窗口是 ArcGIS for Desktop 10.x 中嵌入的交互式 Python 窗口。它较新,非常适合测试小块代码、学习 Python 基础知识、构建快速简便的工作流程以及执行地理处理工具。对于新手程序员来说,ArcGIS Python 窗口是一个很好的起点!

除了是编写代码的位置之外,ArcGIS Python 窗口还具有许多功能。您可以将窗口的内容保存到磁盘上的 Python 脚本文件中,或者将现有的 Python 脚本加载到窗口中。窗口可以是固定的或浮动的。在浮动状态下,窗口可以按您的意愿扩展或收缩。窗口还可以固定在 ArcGIS 显示的各个部分。您还可以通过右键单击窗口并选择 格式 来格式化窗口中显示的字体和文本颜色。

显示 ArcGIS Python 窗口

可以通过点击标准 ArcGIS for Desktop 工具栏上的 Python 窗口按钮来打开 Python 窗口,如图所示。这是一个浮动窗口,因此您可以按需调整大小,也可以将其停靠在 ArcMap 界面的各个位置:

显示 ArcGIS Python 窗口

Python 窗口本质上是一个允许您逐行输入语句的壳窗口,就在 >>> 行输入字符之后。在分隔符的右侧,您将找到一个帮助窗口。

您可以通过在 Python 窗口内部右键单击并从菜单中选择 加载… 来加载现有的脚本。您还可以通过右键单击窗口并选择 格式 来格式化窗口中显示的字体和文本颜色。您将提供白色和黑色主题;您可以单独选择字体和颜色:

显示 ArcGIS Python 窗口

点击 设置黑色主题 按钮查看示例。如果您花很多时间编写代码,您可能会发现较暗的主题对眼睛更容易接受:

显示 ArcGIS Python 窗口

ArcGIS Python 窗口还提供了代码自动补全功能,这使程序员的编程生活变得更加容易。你可以通过打开 ArcGIS Python 窗口,在第一行输入 arcpy 后跟一个点来尝试这个功能。ArcPy 是一个面向模块的包,这意味着你使用点符号来访问对象的属性和方法。注意,提供了一个可下拉的物品列表。这些是可用于特定对象的工具、函数、类和扩展。所有对象都有它们自己的相关物品,因此展示的物品列表将根据你当前选择的对象而有所不同:

显示 ArcGIS Python 窗口

这是一个自动过滤的列表,所以当你开始输入工具、函数、类或扩展的名称时,列表将根据你输入的内容进行过滤:

显示 ArcGIS Python 窗口

你可以选择让 Python 窗口自动为你补全文本,通过使用鼠标从列表中选择一个项目,或者使用箭头键突出显示你的选择,然后使用 Tab 键输入命令。这个自动补全功能使你成为一个更快、更高效的程序员。这不仅易于使用,而且还能显著减少你代码中的错误。

Python 语言基础

为了有效地编写 ArcGIS 的地理处理脚本,你需要至少了解 Python 语言的基本结构。Python 语言比大多数其他编程语言更容易学习,但学习并有效使用它仍需要一些时间。本节将教会你如何创建变量,将各种数据类型分配给变量,理解可以分配给变量的不同类型的数据,使用不同类型的语句,使用对象,读写文件,以及导入第三方 Python 模块。

注释代码

Python 脚本应遵循一个常见的结构。通常的做法是,每个脚本的开始部分应作为文档,详细说明脚本名称、作者以及脚本提供的处理功能的一般描述。这份介绍性文档将帮助您和其他未来的程序员快速扫描脚本的细节和目的。这份文档通过在 Python 中使用注释来完成。注释是您添加到脚本中的代码行,用作脚本提供的功能的文档。这些代码行以单个井号(#)或双井号(##)开头,后面跟着您需要用来记录代码的任何文本。Python 解释器不会执行这些代码行。它们只是用来记录您的代码。在下一张屏幕截图中,带有单个井号的注释代码行显示了代码行。您还应该努力在脚本中包含注释,以描述脚本的重要部分。当您需要更新脚本时,这对您(或另一位程序员)将非常有用:

注释代码

小贴士

下载示例代码

您可以从您在 www.PacktPub.com 的账户中下载您购买的所有 Packt 书籍的示例代码文件。如果您在其他地方购买了这本书,您可以访问 www.PacktPub.com/support 并注册,以便将文件直接通过电子邮件发送给您。

导入模块

虽然 Python 包含许多内置函数,但您将经常需要访问存储在外部模块中的特定功能包。例如,Math 模块存储与处理数值相关的特定函数,而 R 模块提供统计分析函数。我们尚未讨论函数的话题,但基本上函数是在调用时执行的命名代码块。模块通过使用 import 语句导入。当使用 ArcGIS 编写地理处理脚本时,您始终需要导入 arcpy 模块,这是用于访问 ArcGIS 提供的 GIS 工具和函数的 Python 包。import 语句将是您脚本中的第一行代码(不包括注释)。以下代码行导入了 arcpyos 模块。Python 的 os 模块提供了一种与底层操作系统的接口方式:

import arcpy
import os

变量

从高层次来看,你可以将变量视为在脚本运行期间为存储值而保留的计算机内存区域。在 Python 中定义的变量被赋予一个名称和一个值。分配给变量的值可以通过引用变量名来访问脚本的不同部分。例如,你可能创建一个包含要素类名称的变量,然后由 Buffer 工具使用该变量创建新的输出数据集。要创建变量,只需给它一个名称,后跟赋值运算符(即等号 =),然后是一个值:

fcParcels = "Parcels"
fcStreets = "Streets"

以下表格展示了使用前面的代码示例中变量名和分配给变量的值:

变量名 变量值
fcParcels Parcels
fcStreets Streets

在创建变量时,你必须遵循某些命名规则,包括以下内容:

  • 它可以包含字母、数字和下划线

  • 第一个字符必须是一个字母

  • 变量名中除了下划线外不能使用特殊字符

  • Python 关键字和空格是不允许的

有一些 Python 关键字必须避免,包括 classifforwhile 以及其他一些。这些关键字通常与其他 Python 语句使用不同的字体颜色突出显示。

以下是一些 Python 中合法变量名的示例:

  • featureClassParcel

  • fieldPopulation

  • field2

  • ssn

  • my_name

这些是 Python 中非法变量名的示例:

  • class(Python 关键字)

  • return(Python 关键字)

  • $featureClass(非法字符,必须以字母开头)

  • 2fields(必须以字母开头)

  • parcels&Streets(非法字符)

Python 是一种区分大小写的语言,因此在脚本中注意变量的大小写和命名非常重要。区分大小写的问题可能是新 Python 程序员最常见的错误来源,因此在遇到代码中的错误时,始终考虑这一点作为可能性。让我们看一个例子。以下是一个包含三个变量的列表;请注意,尽管每个变量名相同,但大小写不同,因此产生了三个不同的变量:

  • mapsize = "22x34"

  • MapSize = "8x11"

  • Mapsize = "36x48"

如果你打印这些变量,你将得到以下输出:

print(mapsize)
>>> 22x34

print(MapSize)
>>> 8x11  #output from print statement

print(Mapsize)
>>>36x48  #output from print statement

Python 变量名在整个脚本中需要保持一致。最佳实践是使用驼峰命名法,即变量名的第一个单词全部小写,然后每个后续单词以大写字母开头。以下示例中的 fieldOwnerName 变量名展示了这一概念:第一个单词(field)全部小写,第二个单词(Owner)和第三个单词(Name)以大写字母开头:

fieldOwnerName

在 Python 中,变量是动态类型的。动态类型意味着你可以定义一个变量并给它分配数据,而不必明确指定变量名将包含特定类型的数据。可以分配给变量的常用数据类型包括以下几种:

数据类型 示例值 代码示例
字符串 "Streets" fcName = "Streets"
数字 3.14 percChange = 3.14
布尔值 True ftrChanged = True
列表 "Streets", "Parcels", "Streams" lstFC = ["Streets", "Parcels", "Streams"]
字典 '0':Streets,'1':Parcels dictFC = {'0':Streets,'1':Parcels}
对象 Extent spatialExt = map.extent

我们将在接下来的章节中更详细地讨论这些数据类型。

例如,在 C# 中,在使用变量之前,你需要定义变量的名称和类型。在 Python 中这不是必需的。要使用变量,只需给它一个名称和值,你就可以立即开始使用它。Python 会幕后工作以确定变量中存储的数据类型。

在下面的 C# 代码示例中,我们创建了一个名为 aTouchdown 的新变量,它被定义为整数变量,这意味着它只能包含整数数据。然后我们将 6 的值分配给这个变量:

int aTouchdown;
aTouchdown = 6;

在 Python 中,可以通过动态类型创建和分配数据。Python 解释器负责动态确定分配给变量的数据类型:

aTouchdown = 6

有时候,你可能知道你的脚本将需要一个变量,但事先并不一定知道将分配什么数据给这个变量。在这些情况下,你可以简单地定义一个变量而不给它分配数据。在这里,你将找到一个代码示例,展示了如何创建一个未分配数据的变量:

aVariable = ''
aVariable = NULL

在脚本运行时,分配给变量的数据也可以更改。

变量可以存储许多不同类型的数据,包括原始数据类型,如字符串和数字,以及更复杂的数据,如列表、字典甚至对象。我们将检查可以分配给变量的不同数据类型,以及 Python 提供的用于操作数据的各种函数。

内置数据类型

Python 有许多内置数据类型。我们将首先讨论的内置类型是 string 数据类型。我们已经看到了几个 string 变量的例子,但这类变量可以以多种方式操作,所以让我们更仔细地看看这个数据类型。

字符串

字符串是有序字符集合,用于存储和表示基于文本的信息。这可以说是一种相当枯燥的说法,即字符串变量持有文本。当将文本赋给变量时,字符串变量被单引号或双引号包围。示例可能包括姓名、要素类名称、Where子句或任何可以编码为文本的内容。

字符串操作

在 Python 中,字符串可以通过多种方式进行操作。字符串连接是更常用的函数之一,并且实现简单。使用+运算符与操作符两边的string变量一起使用,以产生一个新的string变量,将两个字符串变量连接在一起:

shpStreets = "c:\\GISData\\Streets" + ".shp"
print(shpStreets)

运行此代码示例会产生以下结果:

>>>c:\GISData\Streets.shp

可以使用 Python 的==运算符测试字符串的相等性,该运算符简单地放置了两个等号。不要将相等运算符与赋值运算符混淆,赋值运算符是一个单独的等号。相等运算符测试两个变量是否相等,而赋值运算符将值赋给变量:

firstName = "Eric"
lastName = "Pimpler"
firstName == lastName

运行此代码示例会产生以下结果,因为firstNamelastName变量不相等:

>>>False

可以使用in运算符测试字符串是否包含,如果第一个操作数包含在第二个操作数中,则返回True

fcName = "Floodplain.shp"
print(".shp" in fcName)
>>>True

我简要地提到过字符串是一个有序字符集合。这意味着什么?这仅仅意味着我们可以从字符串中访问单个字符或一系列字符,并且字符的顺序将保持不变,直到我们改变它们。某些集合,如字典,不保持一定的顺序。在 Python 中,这种情况被称为访问单个字符时的索引,以及访问一系列字符时的切片

通过在字符串后提供方括号内的数字偏移量,可以获取字符串中的字符。例如,您可以使用fc[0]语法获取fc变量中的第一个字符串字符。Python 是一种零基语言,意味着列表中的第一个项是0。可以使用负偏移量从字符串的末尾向前搜索。在这种情况下,字符串中的最后一个字符存储在-1索引处。索引始终创建一个新的变量来保存字符:

fc = "Floodplain.shp"
print(fc[0])
>>>'F'
print(fc[10])
>>>'.'
print(fc[13])
>>>'p'

以下图像说明了字符串是有序字符集合,第一个字符占据0位置,第二个字符占据1位置,每个后续字符占据下一个索引号:

字符串操作

虽然字符串索引允许您从string变量中获取单个字符,但字符串切片允许您提取连续的字符串序列。其格式和语法与索引类似,但增加了第二个偏移量,用于告诉 Python 返回哪些字符。

以下代码示例提供了一个字符串切片的例子。theString变量已被分配值为Floodplain.shp。要获取包含 Flood 内容的切片变量,您可以使用theString[0:5]语法:

theString = "Floodplain.shp"
print(theString[0:5])
>>>Flood

注意

Python 的切片操作返回从第一个偏移量开始的字符,直到但不包括第二个偏移量。这对新 Python 程序员来说可能特别令人困惑,并且是错误的一个常见来源。在我们的示例中,返回的变量将包含 Flood 字符。第一个字符,占据 0 位置,是 F。返回的最后一个字符是 4 索引,对应于 d 字符。请注意,5 索引号不包括在内,因为 Python 的切片操作只返回到但不包括第二个偏移量的字符。

可以省略任一偏移量。这实际上创建了一个通配符。在 theString[1:] 的情况下,您告诉 Python 返回从第二个字符开始到字符串末尾的所有字符。在第二种情况下,theString[:-1],您告诉 Python 从字符零开始,返回除了最后一个字符之外的所有字符。

Python 是一种非常出色的字符串操作语言,并且有许多额外的函数可以用来处理这类数据。大多数这些函数超出了本文的范围,但一般来说,以下所有的字符串操作函数都是可用的:

  • 字符串长度

  • 大小写转换函数

  • 移除前导和尾随空白

  • 在字符串中查找字符

  • 文本替换

  • 根据分隔符分割成单词列表

  • 格式化

您的 ArcGIS Python 地理处理脚本通常会需要引用您计算机上或可能是一个共享服务器上的数据集位置。对这些数据集的引用通常由存储在变量中的路径组成。在 Python 中,路径名是一个特殊情况,值得特别提及。Python 中的反斜杠字符是一个保留的转义字符和行续行字符,因此需要使用两个反斜杠、一个正斜杠或以 r 前缀的常规单个反斜杠来定义路径。这些路径名在 Python 中始终以字符串的形式存储。您将在下一节中看到一个示例。

非法路径引用的示例如下:

fcParcels = "c:\Data\Parcels.shp"

合法路径引用的示例如下:

fcParcels = "c:/Data/Parcels.shp"
fcParcels = "c:\\Data\\Parcels.shp"
fcParcels = r"c:\Data\Parcels.shp"

数字

Python 还内置了对数值数据类型(包括 intlongfloatcomplex)的支持。数值的赋值方式与字符串类似,只是不需要在值周围加上引号,并且显然它必须是一个数值。

Python 支持所有常用的数值运算符,包括加法、减法、乘法、除法和取模或余数。除此之外,还有用于返回绝对值、将字符串转换为数值数据类型和四舍五入的函数。

虽然 Python 提供了一些内置的数学函数,但可以使用 math 模块来访问更多高级的 math 函数。要使用这些函数,您必须按照以下方式明确导入 math 模块:

import math

math 模块提供的函数包括返回数字的上限和下限、绝对值、三角函数、对数函数、角度转换和双曲函数。值得注意的是,没有简单的函数可以计算平均值或平均数,这些必须编写代码来计算。有关 math 模块的更多详细信息,可以通过导航到 所有程序 | ArcGIS | Python 2.7 | Python 手册 来找到。在打开 Python 手册后,导航到 Python 标准库 | 数值和数学模块。你也可以参考这个来了解任何数据类型、语法、内置函数以及其他你希望详细了解的内容,其中有很多内容无法在此处涵盖。

列表

Python 提供的第三种内置数据类型是列表。列表是有序元素集合,可以存储 Python 支持的任何类型的数据,同时还能同时存储多种数据类型。这可以包括数字、字符串、其他列表、字典或对象。例如,一个列表变量可以同时存储数字和字符串数据。列表是基于零的,列表中的第一个元素占据0的位置。这一点在此处得到了说明:

列表

列表中的每个后续对象都会增加一个。此外,列表还具有动态增长和收缩的特殊能力。

列表是通过分配一系列括号内的值来创建的。要从列表中提取值,只需在变量名旁边使用括号内的整数值即可。以下代码示例提供了这一点的说明:

fcList = ["Hydrants", "Water Mains", "Valves", "Wells"]
fc = fcList[0] ##first item in the list - Hydrants
print(fc)
>>>Hydrants
fc = fcList[3]  ##fourth item in the list - Wells
print(fc)
>>>Wells

你可以通过使用 append() 方法向现有列表中添加新项目,如下面的代码示例所示:

fcList.append("Sewer Pipes")
print(fcList)
>> Hydrants, Water Mains, Valves, Wells, Sewer Pipes

你还可以使用切片与列表来返回多个值。要切片一个列表,你可以提供两个由冒号分隔的偏移量值,如下面的代码示例所示。第一个偏移量表示起始索引号,第二个表示停止点。第二个索引号将不会返回。切片列表始终返回一个新的列表:

fcList = ["Hydrants", "Water Mains", "Valves", "Wells"]
fc = fcList[0:2] ##get the first two items – Hydrants, Water Mains

列表本质上是动态的,这意味着你可以向现有列表中添加和删除项目,以及更改现有内容,而无需创建列表的新副本。在列表中更改值可以通过索引或切片完成。索引允许你更改单个值,而切片允许你更改多个列表项。

列表有许多方法可以让你操作列表中的值。你可以通过使用sort()方法以升序或降序对列表的内容进行排序。你可以使用append()方法向列表中添加项,该方法将对象添加到列表的末尾,以及使用insert()方法在列表中的某个位置插入对象。你可以使用remove()方法从列表中删除项,该方法从列表中删除第一个出现的值,或者使用pop()方法删除并返回列表末尾的对象。你还可以使用reverse()方法反转列表的内容。

元组

元组与列表类似,但有一些重要的区别。就像列表一样,元组包含一系列值。元组的内容可以包括任何类型的数据,就像列表一样。然而,与列表不同,元组的内容是静态的。一旦创建了元组,你就不能更改值的序列,也不能添加或删除值。这在需要数据始终占据特定位置的情况下可能是个好事。创建元组就像在圆括号内放置一些用逗号分隔的值一样简单,如下面的代码示例所示:

fcTuples = ("Hydrants", "Water Mains", "Valves", "Wells")

你可能已经注意到创建元组与创建列表非常相似。唯一的区别是,在值周围使用圆括号而不是方括号。

与列表类似,元组的索引从0开始。访问存储在元组中的值的方式与列表相同。这将在下面的代码示例中说明:

fcTuples = ("Hydrants", "Water Mains", "Valves", "Wells")
print(fcTuples[1])
>>>Water Mains

当结构的内容需要是静态的时候,通常使用元组来代替列表。你不能通过列表来确保这一点,但你可以通过元组来确保。

字典

字典是 Python 中的第二种集合对象类型。它们与列表类似,但字典是一个无序的对象集合。不是通过使用偏移量从集合中检索对象,而是通过键来存储和检索字典中的项。每个字典中的键都有一个关联的值,如下所示:

字典

与列表类似,字典可以通过使用dictionary上的方法在原地增长和缩小。在下面的代码示例中,你将学习如何创建和填充字典,并看到如何通过使用键来访问值。字典是通过使用花括号创建的。在这些括号内,每个键后面跟着一个冒号,然后与键关联一个值。这些键/值对由逗号分隔:

##create the dictionary
dictLayers = {'Roads': 0, 'Airports': 1, 'Rail': 2}

##access the dictionary by key
print(dictLayers['Airports'])
>>>1
print(dictLayers['Rail'])
>>>2

基本的字典操作包括获取字典中的项目数量、使用键获取值、确定键是否存在、将键转换为列表以及获取值的列表。字典对象可以在原地更改、扩展和缩小。这意味着 Python 不需要创建一个新的字典对象来保存字典的更改版本。通过在方括号中声明键值并将其设置为某个值,可以完成对字典键的赋值。

小贴士

与列表不同,由于字典的内容是无序的,因此不能进行切片。如果你需要遍历字典中的所有值,只需使用keys()方法,它返回字典中所有键的集合,然后可以单独使用它们来设置或获取它们的值。

类和对象

类和对象是面向对象编程的基本概念。虽然 Python 更偏向于过程式语言,但它也支持面向对象编程。在面向对象编程中,类用于创建对象实例。你可以把类看作是创建一个或多个对象的蓝图。每个对象实例都有相同的属性和方法,但对象中包含的数据可以并且通常会有所不同。对象是 Python 中的复杂数据类型,由属性和方法组成,可以像任何其他数据类型一样分配给变量。属性包含与对象相关的数据,而方法则是对象可以执行的操作。

这些概念最好通过一个例子来解释。在 ArcPy 中,extent类是通过提供地图单位中左下角和右上角的坐标来指定矩形的类。extent类包含许多属性和方法。属性包括XMinXMaxYMinYMaxspatialReference等。xy属性的极大值提供了范围矩形的坐标。spatialReference属性持有extentspatialReference对象的引用。extent类的对象实例既可以用来设置也可以用来通过点表示法获取这些属性的值。以下代码示例展示了这一点:

# get the extent of the county boundary
ext = row[0].extent
# print out the bounding coordinates and spatial reference
print("XMin: " + str(ext.XMin))
print("XMax: " + str(ext.XMax))
print("YMin: " + str(ext.YMin))
print("YMax: " + str(ext.YMax))
print("Spatial Reference: " + ext.spatialReference.name)

运行此脚本会产生以下输出:

XMin: 2977896.74002
XMax: 3230651.20622
YMin: 9981999.27708
YMax:10200100.7854
Spatial Reference: NAD_1983_StatePlane_Texas_Central_FIPS_4203_Feet

extent类也有许多方法,这些是对象可以执行的操作。对于这个特定的对象,大多数方法都与在extent对象和另一个几何体之间执行某种几何测试相关。例如包括contains()crosses()disjoint()equals()overlaps()touches()within()

你需要理解的一个额外的面向对象的概念是点表示法。点表示法提供了一种访问对象属性和方法的方式。它用于表示一个属性或方法属于特定的类。

使用点符号的语法包括一个对象实例,后面跟着一个点,然后是属性或方法。无论您是访问属性还是方法,语法都是相同的。在点后面的单词末尾的括号和零个或多个参数表示正在访问一个方法。以下是一些示例,以更好地说明这一概念:

Property: extent.XMin
Method: extent.touches()

语句

您用 Python 编写的每一行代码都称为语句。有各种不同类型的语句,包括创建和分配数据到变量的语句、基于测试分支代码的决策支持语句、执行代码块多次的循环语句等。在创建脚本中的语句时,您的代码需要遵循各种规则。您已经遇到了一种类型的语句:变量创建和赋值。

决策支持语句

if/elif/else语句是 Python 中的主要决策语句,用于测试True/False条件。决策语句使您能够控制程序的流程。以下是一些您可以在代码中做出的决策示例:如果变量包含点要素类,获取XY坐标;如果要素类名称等于Roads,则获取Name字段。

决策语句,如if/elif/else,测试True/False条件。在 Python 中,True值表示任何非零数字或非空对象。False值表示not true,在 Python 中用零数字或空对象表示。比较测试返回一个或零(真或假)的值。布尔和/or 运算符返回真或假的操作数值:

if fcName == 'Roads':
  arcpy.Buffer_analysis(fc, "c:\\temp\\roads.shp", 100)
elif fcName == 'Rail':
  arcpy.Buffer_analysis(fc, "c:\\temp\\rail.shp", 50)
else:
  print("Can't buffer this layer")

Python 代码必须遵循某些语法规则。语句依次执行,直到您的代码分支。分支通常通过使用if/elif/else来实现。此外,使用循环结构,如forwhile,可以改变语句流程。Python 自动检测语句和代码块边界,因此不需要在代码块周围使用大括号或分隔符。相反,缩进用于将语句分组到代码块中。许多语言使用分号来终止语句,但 Python 只是使用行尾字符来标记语句的结束。复合语句包括一个":"字符。复合语句遵循以下模式,即以冒号结束的标题。然后,代码块作为单个语句编写,并缩进在标题下方。

循环语句

循环语句允许你的程序根据需要重复执行代码行。while循环会重复执行循环顶部的测试评估为True的语句块。当条件测试评估为False时,Python 开始立即解释while循环之后的代码。在下一个代码示例中,10的值已被分配给x变量。while循环的测试检查x是否小于100。如果x小于100,则将x的当前值打印到屏幕上,并将x的值增加10。然后,处理继续进行while循环测试。第二次,x的值将是20;因此,测试再次评估为True。这个过程会一直持续到x等于或大于100。此时,测试将评估为False,处理将停止。非常重要的一点是while语句必须有一种方法跳出循环。否则,你将陷入无限循环。无限循环是计算机程序中的一系列指令,它无限循环,要么是因为循环没有终止条件,要么是因为有一个永远无法满足的条件,或者是因为它导致循环重新开始:

x = 10
while x < 100:
     print(x)
     x = x + 10

for循环执行一个预定的次数的语句块。它们有两种类型——一个计数循环,用于执行固定次数的代码块,和一个列表循环,它允许你遍历列表中的所有对象。以下示例中的列表循环对字典中的每个值执行一次,然后停止循环:

dictLayers = {"Roads":"Line","Rail":"Line","Parks":"Polygon"}
for key in dictLayers:
  print(dictLayers[key])

有时候,你可能需要从循环的执行中跳出。breakcontinue语句可以用来做到这一点。break跳出最近的封闭循环,而continue跳回到最近的封闭循环的顶部。这些语句可以出现在代码块中的任何位置。

尝试语句

try语句是一个完整的、复合语句,用于处理异常。异常是一种高级控制设备,主要用于错误拦截或触发。Python 中的异常可以被拦截或触发。当你的代码中出现错误条件时,Python 会自动触发一个异常,这个异常可能或可能不会被你的代码处理。作为程序员,你有责任捕获自动触发的异常。异常也可以通过你的代码手动触发。在这种情况下,你还需要提供一个异常处理例程来捕获这些手动触发的异常。

try语句有两种基本类型:try/except/elsetry/finally。基本的try语句从try标题行开始,后面跟着一个缩进的语句块。然后,这后面跟着一个或多个可选的except子句,这些子句命名了要捕获的异常。之后,你将在末尾找到一个可选的else子句:

import arcpy
import sys

inFeatureClass = arcpy.GetParameterAsText(0)
outFeatureClass = arcpy.GetParameterAsText(1)

try:
  # If the output feature class exists, raise an error

  if arcpy.Exists(inFeatureClass):
    raise overwriteError(outFeatureClass)
  else:
    # Additional processing steps
    print("Additional processing steps")

except overwriteError as e:
  # Use message ID 12, and provide the output feature class
  #  to complete the message.

  arcpy.AddIDMessage("Error", 12, str(e))

try/except/else 语句的工作原理如下。一旦进入 try 语句块,Python 会标记你处于 try 块中,并且知道在此点发生的任何异常条件都将被发送到各个 except 语句进行处理。如果找到匹配的异常,则执行 except 块内的代码块。然后代码会继续执行完整的 try 语句,这将在稍后提到。在这种情况下,else 语句不会执行。try 块内的每个语句都会执行。假设没有发生异常条件,代码指针将跳转到 else 语句并执行 else 语句包含的代码块,然后再移动到 try 块之后的下一行代码。

另一种类型的 try 语句是 try/finally 语句,它允许执行最终化操作。当在 try 语句中使用 finally 子句时,其语句块总是在最后执行,无论是否发生错误条件。

下面是 try/finally 语句的工作方式:如果发生异常,Python 会运行 try 块,然后是 except 块,接着是 finally 块,然后继续执行 try 语句之后的代码。如果在执行过程中没有发生异常,Python 会运行 try 块,然后是 finally 块。这在你想要确保代码块运行后发生某个动作时很有用,无论是否发生错误条件。清理操作,如关闭文件或数据库连接,通常放置在 finally 块中,以确保无论代码中是否发生异常都会执行:

import arcpy

try:
  if arcpy.CheckExtension("3D") == "Available":
    arcpy.CheckOutExtension("3D")
  else:
    # Raise a custom exception
    raise LicenseError

  arcpy.env.workspace = "D:/GrosMorne"
  arcpy.HillShade_3d("WesternBrook", "westbrook_hill", 300)
  arcpy.Aspect_3d("WesternBrook", "westbrook_aspect")

except LicenseError:
  print("3D Analyst license is unavailable")
except:
  print(arcpy.GetMessages(2))
finally:
  # Check in the 3D Analyst extension
  arcpy.CheckInExtension("3D")

with 语句

当你有两个相关的操作需要作为一个代码块中的配对执行时,with 语句就很有用。使用 with 语句的常见场景是打开、读取和关闭文件。打开和关闭文件是相关操作,而读取文件和对其内容进行处理是中间的代码块。在编写 ArcGIS 的地理处理脚本时,使用 ArcGIS 10.1 版本引入的新 cursor 对象非常适合使用 with 语句。我们将在稍后的章节中详细讨论 cursor 对象,但现在我将简要描述这些对象。游标是特征类或表属性表的记录的内存副本。游标有多种类型。插入游标允许你插入新记录,搜索游标是记录的只读副本,而更新游标允许你编辑或删除记录。使用 with 语句可以自动打开、以某种方式处理并关闭游标对象。

文件或游标对象的关闭由 with 语句自动处理,从而实现更简洁、更高效的编码。这基本上就像使用 try/finally 块,但代码行数更少。在下面的代码示例中,with 块用于创建一个新的搜索游标,从游标中读取信息,并隐式关闭游标:

import arcpy

fc = "c:/data/city.gdb/streets"

# For each row print the Object ID field, and use the SHAPE@AREA
# token to access geometry properties

with arcpy.da.SearchCursor(fc, ("OID@", "SHAPE@AREA")) as cursor:
  for row in cursor:
    print("Feature {0} has an area of {1}".format(row[0], row[1]))

语句缩进

语句缩进值得特别提及,因为它对于 Python 解释代码的方式至关重要。Python 中的复合语句使用缩进来创建一组语句。这包括 if/thenforwhiletrywith 语句。Python 解释器使用缩进来检测这些代码块。复合语句的开始是通过冒号的使用来定义的。所有跟在复合语句开始之后的行都应该缩进相同的距离。你可以使用任意数量的空格来定义缩进,但你应该为每个语句使用相同的缩进级别。一个常见的做法是通过使用制表符来定义缩进。当 Python 解释器遇到一个缩进较少的行时,它将假设代码块已结束。以下代码通过使用 try 语句说明了这个概念。注意,在 try 语句之后有一个冒号。这表示随后的语句是复合语句的一部分,应该缩进。这些语句将形成一个代码块。

此外,一个 if 语句位于 try 语句内部。这也被视为一个复合语句,这是通过语句末尾的冒号定义的。因此,任何属于 if 语句的语句都应该进一步缩进。你也应该注意到,if 语句内部有一个没有缩进的语句,但它处于同一级别。这个 statement4try 代码块的一部分,但不是 if 代码块的一部分:

try:
  if <statement1>:
    <statement2>
    <statement3>
  <statement4> <………..>
except:
  <statement>
  <………..>
except:
  <statement>
  <…………>

许多语言,包括 JavaScript、Java 和 .NET,使用花括号来表示一组语句。Python 通过使用缩进来代替花括号,试图减少你不得不编写的代码量,并使代码更易于阅读。任何使用过这些其他语言的人都可以证实,阅读包含许多花括号的代码是多么困难。然而,缩进确实需要一些习惯,并且对于 Python 执行代码行的方式至关重要。

文件输入输出

你经常会发现需要从你的计算机上的文件中检索或写入信息。Python 有一个内置的对象类型,它提供了一种访问文件以执行许多任务的方法。我们只将涵盖文件操作功能的一小部分,但我们将涉及最常用的函数,包括打开和关闭文件,以及将数据读取和写入文件。

Python 的 open() 函数创建一个文件对象,该对象作为你电脑上文件的一个链接。在读取和/或写入文件数据之前,必须在文件上调用 open() 函数。open() 函数的第一个参数是你想要打开的文件的路径。第二个参数对应于一个模式,通常是读取(r)、写入(w)或追加(a)。r 的值表示你想要以只读方式打开文件,而 w 的值表示你想要以写入方式打开文件。如果你以写入方式打开一个已存在的文件,这将覆盖文件中现有的任何数据,所以你必须小心使用写入模式。追加模式(a)将以写入方式打开文件,但不会覆盖任何现有数据,而是将新数据追加到文件末尾。以下代码示例展示了如何使用 open() 函数以只读模式打开一个文本文件:

with open('Wildfires.txt','r') as f:

注意,我们同样使用了 with 关键字来打开文件,确保在使用该文件的代码执行完毕后,文件资源将被 清理

文件打开后,可以使用多种方式和多种方法从中读取数据。最典型的情况是使用 readline() 方法逐行从文件中读取数据。readline() 函数可以将文件逐行读入一个字符串变量中。你需要在 Python 代码中创建一个循环机制来逐行读取整个文件。如果你希望将整个文件读入一个变量中,可以使用 read() 方法,该方法将读取文件直到 文件结束标记 (EOF)。你也可以使用 readlines() 方法来读取文件的全部内容,将每一行分割成单独的字符串,直到找到 EOF。

在以下代码示例中,我们以只读模式打开了一个名为 Wildfires.txt 的文本文件,并使用 readlines() 方法将文件的全部内容读入一个名为 lstFires 的变量中,该变量是一个 Python 列表,包含文件中的每一行作为一个单独的字符串值。在这种情况下,Wildfire.txt 文件是一个以逗号分隔的文本文件,包含火灾的纬度和经度以及每个火灾的置信度值。然后我们遍历 lstFires 中的每一行文本,并使用 split() 函数根据逗号作为分隔符提取值,包括纬度、经度和置信度值。纬度和经度值用于创建一个新的 Point 对象,然后使用插入游标将其插入到要素类中:

import arcpy, os
try:

  arcpy.env.workspace = "C:/data/WildlandFires.mdb"
  # open the file to read
  with open('Wildfires.txt','r') as f:   #open the file

    lstFires = f.readlines() #read the file into a list
    cur = arcpy.InsertCursor("FireIncidents")

    for fire in lstFires: #loop through each line
      if 'Latitude' in fire: #skip the header
        continue
      vals = fire.split(",") #split the values based on comma
      latitude = float(vals[0]) #get latitude
      longitude = float(vals[1]) #get longitude
      confid = int(vals[2]) #get confidence value
      #create new Point and set values
      pnt = arcpy.Point(longitude,latitude) 
      feat = cur.newRow()
      feat.shape = pnt
      feat.setValue("CONFIDENCEVALUE", confid)
      cur.insertRow(feat) #insert the row into featureclass
except:
    print(arcpy.GetMessages()) #print out any errors
finally:
  del cur
  f.close()

就像读取文件一样,有几种方法可以将数据写入文件。write() 函数可能是最容易使用的,它接受一个字符串参数并将其写入文件。writelines() 函数可以用来将列表结构的内容写入文件。在下面的代码示例中,我们创建了一个名为 fcList 的列表结构,其中包含一系列要素类。我们可以使用 writelines() 方法将此列表写入文件:

outfile = open('c:\\temp\\data.txt','w')
fcList = ["Streams", "Roads", "Counties"]
outfile.writelines(fcList)

摘要

在本章中,我们介绍了一些基本的 Python 编程概念,这些概念是在你能够编写有效的地理处理脚本之前需要理解的。我们以 IDLE 开发环境的概述开始本章,用于编写和调试 Python 脚本。你学习了如何创建新脚本、编辑现有脚本、检查语法错误以及执行脚本。我们还涵盖了基本语言结构,包括导入模块、创建和分配变量、if/else 语句、循环语句以及各种数据类型,包括字符串、数字、布尔值、列表、字典和对象。你还学习了如何读取和写入文本文件。

第二章:管理地图文档和图层

在本章中,我们将介绍以下菜谱:

  • 引用当前地图文档

  • 在磁盘上引用地图文档

  • 获取地图文档中的图层列表

  • 限制图层列表

  • 缩放到选定的要素

  • 改变地图范围

  • 将图层添加到地图文档

  • 将图层插入到地图文档中

  • 更新图层符号

  • 更新图层属性

  • 在数据框架中处理具有时间功能的图层

简介

ArcPy 映射模块为地图自动化提供了许多令人兴奋的功能,包括管理地图文档和图层文件以及这些文件中的数据的能力。支持自动化地图导出和打印、创建 PDF 地图集以及将地图文档发布到 ArcGIS Server 地图服务。这是一个极其有用的模块,可以完成 GIS 分析师日常执行的大多数任务。

在本章中,您将学习如何使用 ArcPy 映射模块来管理地图文档和图层文件。您还将学习如何从地图文档文件中添加和删除地理图层和表格,将图层插入到数据框架中,以及在地图文档中移动图层。最后,您将学习如何更新图层属性和符号。

引用当前地图文档

当从 ArcGIS Python 窗口或自定义脚本工具运行地理处理脚本时,您通常会需要引用当前加载在 ArcMap 中的地图文档。在您对地图文档中的图层和表执行地理处理操作之前,这是脚本中的第一步。在本菜谱中,您将学习如何从您的 Python 地理处理脚本中引用当前地图文档。

准备工作

在您实际上对地图文档文件执行任何操作之前,您需要在您的 Python 脚本中引用它。这是通过在arcpy.mapping模块上调用MapDocument()方法来完成的。您可以引用当前正在运行的文档或磁盘上特定位置的文档。要引用当前活动文档,您只需将关键字CURRENT作为参数提供给MapDocument()函数。这将加载 ArcMap 中当前活动的文档。以下代码示例显示了如何获取当前活动文档的引用:

mxd = mapping.MapDocument("CURRENT")

注意

您只能在从 ArcGIS Python 窗口或 ArcToolbox 中的自定义脚本工具运行脚本时使用CURRENT关键字。如果您尝试从 IDLE 或任何其他开发环境运行脚本时使用此关键字,它将无法访问当前加载在 ArcGIS 中的地图文档文件。我还应该指出,CURRENT关键字不区分大小写。您也可以简单地使用"current"

要引用本地或远程驱动器上的地图文档,只需提供地图文档的路径以及地图文档名称作为MapDocument()参数即可。例如,您将使用以下引用引用c:\data文件夹中的crime.mxd文件:arcpy.mapping.MapDocument("C:/data/crime.mxd")

如何操作…

按照以下步骤学习如何在 ArcMap 中访问当前活动地图文档:

  1. 使用 ArcMap 打开c:\ArcpyBook\Ch2\Crime_Ch2.mxd

  2. 点击位于主 ArcMap 工具栏上的 Python 窗口按钮。

  3. 通过在 Python 窗口中输入以下内容来导入arcpy.mapping模块。在这里,以及未来的菜谱中,我们将arcpy.mapping模块分配给一个名为mapping的变量。这将使您的代码更容易阅读,并减少您需要编写的代码量。您不需要在所有代码前都加上arcpy.mapping前缀,您只需将其称为mapping即可。虽然这不是强制性的,但它确实使您的代码更整洁,编写起来更快。此外,您可以按自己的意愿命名变量。例如,您不必将其称为mapping,您也可以将其称为MAPmp或任何有意义的名称。

    import arcpy.mapping as mapping
    
  4. 通过在 Python 窗口中输入以下内容,引用当前活动文档(Crime_Ch2.mxd)并将引用分配给变量:

    mxd = mapping.MapDocument("CURRENT")
    
  5. 为地图文档设置标题:

    mxd.title = "Crime Project"
    
  6. 使用saveACopy()方法保存地图文档文件的副本:

    mxd.saveACopy("c:/ArcpyBook/Ch2/crime_copy.mxd")
    
  7. 导航到文件 | 地图文档属性,以查看您为地图文档设置的新标题。

  8. 您可以通过检查c:\ArcpyBook\code\Ch2\ReferenceCurrentMapDocument.py解决方案文件来检查您的工作。

它是如何工作的…

MapDocument类有一个构造函数,用于创建此类的一个实例。在面向对象的编程中,一个实例也称为对象MapDocument的构造函数可以接受CURRENT关键字或本地或远程驱动器上地图文档文件的路径。构造函数创建一个对象并将其分配给变量mxd。然后,您可以使用点符号访问此对象上可用的属性和方法。在这种情况下,我们使用MapDocument.title属性打印出地图文档文件的标题,我们还使用了MapDocument.saveACopy()方法来保存地图文档文件的副本。

在磁盘上引用地图文档

除了能够在 ArcMap 中引用当前活动地图文档文件外,您还可以通过使用MapDocument()构造函数访问存储在本地或远程驱动器上的地图文档文件。在本菜谱中,您将学习如何访问这些地图文档。

准备工作

如我之前提到的,您还可以引用存储在您的计算机或共享服务器上的地图文档文件。这只需提供文件的路径即可完成。这是一种更灵活的获取地图文档引用的方法,因为它可以在 ArcGIS Python 窗口之外运行。稍后,当我们讨论脚本中的参数时,您将理解您可以使此路径成为参数,从而使脚本更加灵活,每次需要时都能输入新的路径。

如何操作...

按照以下步骤学习如何访问存储在本地或远程驱动器上的地图文档:

  1. 开始 | 所有程序 | ArcGIS | Python 2.7 | IDLE打开 IDLE 开发环境。

  2. 通过导航到 IDLE 壳窗口中的文件 | 新建窗口创建一个新的 IDLE 脚本窗口。

  3. 导入arcpy.mapping

    import arcpy.mapping as mapping
    
  4. 引用您在最后一个配方中创建的crime地图文档副本:

    mxd = mapping.MapDocument("c:/ArcpyBook/Ch2/crime_copy.mxd")
    
  5. 打印地图文档的标题:

    print(mxd.title)
    
  6. 运行脚本,您将看到以下输出:

    Crime Project
    
    
  7. 您可以通过检查c:\ArcpyBook\code\Ch2\ReferenceMapDocumentOnDisk.py解决方案文件来检查您的工作。

它是如何工作的...

与上一个配方相比,唯一的区别在于我们提供了一个指向本地或远程驱动器上的地图文档文件的引用,而不是使用CURRENT关键字。除非您确信您的地处理脚本将在 ArcGIS 内运行,无论是 Python 窗口还是自定义脚本工具,否则这是引用地图文档文件的推荐方式。

获取地图文档中的图层列表

通常,地处理脚本中的第一步是获取地图文档中的图层列表。一旦获取,您的脚本可以遍历每个图层并执行某种类型的处理。映射模块包含一个ListLayers()函数,它提供了获取此图层列表的能力。在本配方中,您将学习如何获取地图文档中包含的图层列表。

准备工作

arcpy.mapping模块包含各种列表函数,用于返回图层、数据框架、损坏的数据源、表视图和布局元素的列表。这些列表函数通常作为多步骤过程中的第一步,其中脚本需要从列表中获取一个或多个项目以进行进一步处理。每个这些列表函数都返回一个 Python 列表,正如您在本书前面的内容中所知,这是一个用于存储信息的高度功能性的数据结构。

通常,列表函数作为多步骤过程的一部分使用,其中创建列表只是第一步。脚本中的后续处理将遍历列表中的一个或多个项目。例如,您可能从地图文档中获取图层列表,然后遍历每个图层以查找特定的图层名称,然后对其进行进一步的地处理。

在本教程中,你将学习如何从地图文档文件中获取图层列表。

如何操作...

按照以下步骤学习如何从地图文档中获取图层列表:

  1. 使用 ArcMap 打开 c:\ArcpyBook\Ch2\Crime_Ch2.mxd

  2. 从 ArcMap 主工具栏中点击 Python 窗口按钮。

  3. 导入 arcpy.mapping 模块:

    import arcpy.mapping as mapping
    
  4. 引用当前活动文档(Crime_Ch2.mxd)并将引用分配给一个变量:

    mxd = mapping.MapDocument("CURRENT")
    
  5. 调用 ListLayers() 函数并传递地图文档的引用:

    layers = mapping.ListLayers(mxd)
    
  6. 开始一个 for 循环并打印出地图文档中每个图层的名称:

    for lyr in layers:
        print(lyr.name)
    
  7. 运行脚本以查看以下输出(你可以通过检查 c:\ArcpyBook\code\Ch2\GetListLayers.py 解决方案文件来验证你的工作):

    Burglaries in 2009
    Crime Density by School District
    Bexar County Boundary
    Test Performance by School District
    Bexar County Boundary
    Bexar County Boundary
    Texas Counties
    School_Districts
    Crime Surface
    Bexar County Boundary
    
    

工作原理...

ListLayers() 函数检索地图文档、特定数据框架或图层文件中的图层列表。在这种情况下,我们将当前地图文档的引用传递给 ListLayers() 函数,它应该检索地图文档中所有图层的列表。结果存储在一个名为 layers 的变量中,这是一个可以由 for 循环迭代的 Python 列表。这个 Python 列表包含一个或多个 Layer 对象。

更多内容…

ListLayers() 函数是 arcpy.mapping 模块提供的许多列表函数之一。这些函数中的每一个都返回一个包含某种类型数据的 Python 列表。其他一些列表函数包括 ListTableViews(),它返回一个 Table 对象的列表;ListDataFrames(),它返回一个 DataFrame 对象的列表;以及 ListBookmarks(),它返回地图文档中的书签列表。还有其他一些列表函数,其中许多我们将在本书的后续章节中介绍。

限制图层列表

在前面的教程中,你学习了如何使用 ListLayers() 函数获取图层列表。有时你可能不希望获取地图文档中所有图层的列表,而只想获取图层的一个子集。ListLayers() 函数允许你限制生成的图层列表。在本教程中,你将学习如何通过通配符和特定的数据框架从 ArcMap 内容表中限制返回的图层。

准备工作

默认情况下,如果你只传递地图文档或图层文件的引用,ListLayers() 函数将返回这些文件中所有图层的列表。然而,你可以通过使用可选的通配符参数或传递特定数据框架的引用来限制该函数返回的图层列表。通配符是一个字符,它将匹配搜索中的任何字符或字符序列。这将在本教程中演示。

注意

如果你正在处理图层文件(.lyr),则不能使用数据框架来限制图层。图层文件不支持数据框架。

在本教程中,你将学习如何通过使用通配符和数据框架来限制 ListLayers() 返回的图层列表。

如何操作...

按照以下步骤学习如何从一个地图文档中限制图层列表:

  1. 使用 ArcMap 打开c:\ArcpyBook\Ch2\Crime_Ch2.mxd

  2. 从主 ArcMap 工具栏中点击 Python 窗口按钮。

  3. 导入arcpy.mapping模块:

    import arcpy.mapping as mapping
    
  4. 引用当前活动文档(Crime_Ch2.mxd)并将引用分配给一个变量:

    mxd = mapping.MapDocument("CURRENT")
    
  5. 获取地图文档中的数据框列表并搜索名为Crime的特定数据框(请注意,文本字符串可以由单引号或双引号包围):

    for df in mapping.ListDataFrames(mxd):
      if df.name == 'Crime':
    
  6. 调用ListLayers()函数,并传递地图文档的引用、一个通配符以限制搜索,以及上一步找到的数据框以进一步限制搜索。ListLayers()函数应该缩进在刚刚创建的if语句内部:

    layers = mapping.ListLayers(mxd,'Burg*',df)
    
  7. 开始一个 for 循环并打印出地图文档中每个图层的名称:

    for layer in layers:
        print(layer.name)
    
  8. 完整的脚本应如下所示,或者你可以查阅位于c:\ArcpyBook\code\Ch2\RestrictLayers.py的解决方案文件:如何做…

  9. 运行脚本以查看以下输出:

    Burglaries in 2009
    
    

它是如何工作的…

ListDataFrames()函数是arcpy.mapping提供的另一个列表函数。此函数返回地图文档中所有数据框的列表。然后我们遍历该函数返回的每个数据框,寻找名为Crime的数据框。如果我们找到具有该名称的数据框,我们调用ListLayers()函数,将可选通配符值Burg*作为第二个参数传递,以及Crime数据框的引用。作为第二个参数传递的通配符值接受任意数量的字符和一个可选的通配符字符(*)。

在这个特定的菜谱中,我们搜索了所有以字符Burg开头并且数据框名为Crime的图层。任何符合这些限制的图层都会被打印出来。请注意,在这个例子中,我们只是打印了图层名称,但在大多数情况下,你将使用工具或其他函数执行额外的地理处理,拥有一个更短的列表将加快你的脚本速度,并保持整洁。

缩放以查看所选要素

在 ArcMap 中创建选择集是一个常见任务。选择集通常作为属性或空间查询的结果创建,但也可以在用户手动选择要素时发生,有时在某些其他情况下也会发生。为了更好地可视化选择集,用户通常会缩放到所选要素的范围。这可以通过 Python 以多种方式编程实现。在这个菜谱中,你将学习如何缩放到数据框中所有所选要素以及单个图层。

准备工作

DataFrame.zoomToSelectedFeatures 属性将缩放到数据帧中所有选定特征的范围内。本质上,它执行与 选择 | 缩放到所选特征 操作相同的操作。一个区别是,如果没有选择任何特征,它将缩放到所有层的完整范围。

缩放到单个图层中选定特征的范围需要您使用 Layer 对象。Layer 对象包括一个 getSelectedExtent() 方法,您可以调用它来缩放到选定记录的范围。这返回一个 Extent 对象,然后您可以使用它作为参数传递给 DataFrame.panToExtent() 方法。

如何操作…

按照以下步骤学习如何获取和设置 ArcMap 的活动数据帧和活动视图:

  1. 使用 ArcMap 打开 c:\ArcpyBook\Ch2\Crime_Ch2.mxd

  2. 在 ArcMap 目录 窗格中,确保 Crime 是活动数据帧。

  3. 目录 窗格中,点击 按选择列表 按钮。

  4. 通过点击图层名称右侧的切换按钮使 Bexar County Boundaries 图层不可选择:如何操作…

  5. 目录 窗格中点击 按来源列表 按钮。使用 选择特征 工具,在 Northside ISD 边界内拖动一个框来包围犯罪集群。这应该会选中特定学区的边界以及一些犯罪,如下面的图所示:如何操作…

  6. 从主 ArcMap 工具栏中点击 Python 窗口按钮。

  7. 导入 arcpy.mapping 模块:

    import arcpy.mapping as mapping
    
  8. 引用当前活动文档(Crime_Ch2.mxd)并将引用分配给一个变量:

    mxd = mapping.MapDocument("CURRENT")
    
  9. 获取活动数据帧(Crime)并缩放到选定特征:

    mxd.activeDataFrame.zoomToSelectedFeatures()
    
  10. 如果没有选择任何记录,调用 zoomToSelectedFeatures() 将会缩放到数据帧中所有记录的范围。通过导航到 选择 | 清除所选特征 来清除所选特征。这将清除选择集。现在,再次执行相同的代码行,以查看这如何影响 zoomToSelectedFeatures() 方法的操作:

    mxd.activeDataFrame.zoomToSelectedFeatures()
    
  11. 现在,我们将缩放到特定图层中选定特征的范围。使用 选择特征 工具,在 Northside ISD 边界内拖动一个框来包围犯罪集群。

  12. 首先,获取 Crime 数据帧的引用。调用 ListDataFrames() 函数并传入 Crime 通配符将返回一个包含单个项目的 Python 列表。我们使用 [0] 提取这个项目,它返回列表中的第一个也是唯一的项目:

    df = mapping.ListDataFrames(mxd, "Crime")[0]
    
  13. 现在,我们将获取对 Burglaries 图层的引用,该图层包含一些选定的要素。以下代码使用通配符 * 在我们上一行代码中引用的数据帧内搜索 **2009 年 Burglaries** 图层。ListLayers() 函数返回一个 Python 列表,我们使用 [0] 来提取包含单词 Burglaries 的第一个也是唯一的图层:

    layer = mapping.ListLayers(mxd,"Burglaries*",df)[0]
    
  14. 最后,我们将通过获取图层中选定要素的范围来设置数据帧的范围:

    df.extent = layer.getSelectedExtent
    
  15. 缩放到图层选定要素的完整脚本应如下所示,或者您可以查阅位于 c:\ArcpyBook\code\Ch2\ZoomSelectedExtent.py 的解决方案文件:

    import arcpy.mapping as mapping
    mxd = mapping.MapDocument("CURRENT")
    df = mapping.ListDataFrames(mxd, "Crime")[0]
    layer = mapping.ListLayers(mxd,"Burglaries*",df)[0]
    df.extent = layer.getSelectedExtent
    

它是如何工作的...

在这个菜谱中,您学习了如何缩放到数据帧中所有图层的所有选定记录的范围,以及如何缩放到数据帧中特定图层的所有选定记录的范围。要缩放到数据帧中所有图层的所有选定记录的范围,只需获取活动数据帧的引用,然后调用 zoomToSelectedFeatures() 即可。

将视图缩放到特定图层中选定记录的范围需要更多的编码。在导入 arcpy.mapping 模块并获取地图文档的引用后,我们接着获取对 Crime 数据帧的引用。使用 ListLayers() 函数,我们传递了数据帧的引用以及一个搜索以文本 Burglaries 开头的图层的通配符。ListLayers() 函数返回一个 Python 列表,因为我们知道只有一个图层与通配符搜索匹配,所以我们提取了第一个图层并将其分配给一个名为 layer 的变量。最后,我们使用 layer.getSelectedExtent 设置数据帧的范围。

更改地图范围

在许多情况下,您将需要更改地图范围。这在您自动化地图生产过程并需要创建不同区域或特征的许多地图时经常发生。有几种方法可以使用 arcpy 来更改地图范围。然而,对于这个菜谱,我们将专注于使用定义表达式来更改范围。

准备工作

DataFrame 类有一个 extent 属性,您可以使用它来设置地理范围。这通常与用于为图层定义定义查询的 Layer.definitionQuery 属性一起使用。在这个菜谱中,您将学习如何使用这些对象和属性来更改地图范围。

如何做...

按照以下步骤学习如何从地图文档中获取图层列表:

  1. 使用 ArcMap 打开 c:\ArcpyBook\Ch2\Crime_Ch2.mxd

  2. 从主 ArcMap 工具栏中单击 Python 窗口按钮。

  3. 导入 arcpy.mapping 模块:

    import arcpy.mapping as mapping
    
  4. 引用当前活动的文档(Crime_Ch2.mxd)并将引用分配给一个变量:

    mxd = mapping.MapDocument("CURRENT")
    
  5. 创建一个 for 循环,该循环将遍历地图文档中的所有数据帧:

    for df in mapping.ListDataFrames(mxd):
    
  6. 找到名为 Crime 的数据框架以及我们将应用定义查询的特定图层:

    if df.name == 'Crime':
      layers = mapping.ListLayers(mxd,'Crime Density by School District',df)
    
  7. 创建一个 for 循环,该循环将遍历图层。只有一个图层,但我们仍然会创建循环。在 for 循环中,创建一个定义查询并设置数据框架的新范围:

    for layer in layers:
      query = '"NAME" = \'Lackland ISD\''
      layer.definitionQuery = query
      df.extent = layer.getExtent()
    
  8. 整个脚本应如下所示,或者您可以查阅位于 c:\ArcpyBook\code\Ch2\ChangeMapExtent.py 的解决方案文件:如何做到这一点...

  9. 保存并运行脚本。数据视图的范围应更新,以便仅可视化与定义表达式匹配的特征,如下面的截图所示:如何做到这一点...

它是如何工作的...

此菜谱使用图层上的定义查询来更新地图范围。在脚本末尾,您创建了一个名为 query 的新变量,该变量包含定义表达式。定义表达式被设置为查找名为 Lackland ISD 的学区。然后,将此查询字符串应用于 definitionQuery 属性。最后,将 df.extent 属性设置为 layer.getExtent() 返回的值。

向地图文档中添加图层

将会有许多需要向地图文档添加图层的情况。映射模块通过 AddLayer() 函数提供此功能。在本菜谱中,您将学习如何使用此函数向地图文档添加图层。

准备工作

arcpy.mapping 模块提供了将图层或图层组添加到现有地图文档文件的能力。您可以利用 ArcMap 的 自动排列 功能,该功能会自动将图层放置在数据框架中以供查看。这基本上与 ArcMap 中 添加数据 按钮提供的功能相同,该按钮根据几何类型和图层权重规则将图层放置在数据框架中。

注意

图层不能添加到图层文件(.lyr)中。

当向地图文档添加图层时,该图层必须引用磁盘上图层文件中存在的现有图层,同一地图文档和数据框架,同一地图文档的不同数据框架,或完全独立的地图文档。图层可以是地图文档中的图层或 .lyr 文件中的图层。要向地图文档添加图层,您必须首先创建 Layer 类的实例,然后调用 AddLayer() 函数,传入新图层以及它应该放置的数据框架和其位置规则。

如何做到这一点...

按照以下步骤学习如何向地图文档添加图层:

  1. 使用 ArcMap 打开 c:\ArcpyBook\Ch2\Crime_Ch2.mxd

  2. 从 ArcMap 的主工具栏中点击 Python 窗口按钮。

  3. 导入 arcpy.mapping 模块:

    import arcpy.mapping as mapping
    
  4. 引用当前活动文档(Crime_Ch2.mxd)并将引用分配给变量:

    mxd = mapping.MapDocument("CURRENT")
    
  5. 获取对 Crime 数据帧的引用,它是 ListDataFrames() 方法返回的列表中的第一个数据帧。代码末尾指定的 [0] 值获取 ListDataFrames() 方法返回的数据帧列表中的第一个数据帧。列表是从 0 开始计数的,因此为了检索第一个数据帧,我们提供了一个索引 0

    df = mapping.ListDataFrames(mxd)[0]
    
  6. 创建一个引用 .lyr 文件的 Layer 对象:

    layer = mapping.Layer(r"C:\ArcpyBook\data\School_Districts.lyr")
    
  7. 将图层添加到数据帧:

    mapping.AddLayer(df,layer,"AUTO_ARRANGE")
    
  8. 您可以查阅位于 c:\ArcpyBook\code\Ch2\AddLayersMapDocument.py 的解决方案文件。运行脚本。School_Districts.lyr 文件将被添加到数据帧中,如下面的截图所示:如何操作…

工作原理...

在前两行中,我们简单地引用了 arcpy.mapping 模块并获取了对当前活动地图文档的引用。接下来,我们创建了一个名为 df 的新变量,它持有对 Crime 数据帧的引用。这是通过返回数据帧对象列表的 ListDataFrames() 函数获得的。然后我们使用列表访问返回列表中的第一个项目,即 Crime 数据帧。然后从磁盘上存储的 layer 文件创建了一个新的 Layer 实例,该实例称为 layer。这个 layer 文件被称为 School_Districts.lyr。最后,我们调用了 AddLayer() 函数,传递了图层应理想地驻留的数据帧的引用以及图层的引用,以及一个参数,表示我们想要使用 自动排列 功能。除了允许 ArcMap 使用自动排列自动将图层放置到数据帧中之外,您还可以使用 BOTTOMTOP 位置将图层放置在数据帧或组图层的顶部或底部。

还有更多...

除了提供将图层添加到地图文档的能力之外,arcpy.mapping 还提供了一个 AddLayerToGroup() 函数,可以用于将图层添加到组图层。图层可以添加到组图层的顶部或底部,或者您可以使用自动排列进行放置。您还可以将图层添加到空组图层。然而,就像常规图层对象一样,组图层不能添加到图层文件中。

图层也可以从数据帧或组图层中移除。RemoveLayer() 函数用于移除图层或组图层。如果两个图层具有相同的名称,则只移除第一个,除非您的脚本已设置为迭代。

将图层插入地图文档

AddLayer() 函数可用于将图层添加到地图文档中,无论是通过自动排列还是作为数据帧中的第一层或最后一层。然而,它并不提供您在数据帧中插入图层所需的具体控制。为了获得这种额外的控制,您可以使用 InsertLayer() 函数。在本教程中,您将学习如何控制添加到数据帧中的图层的放置。

准备工作

AddLayer()函数简单地将图层添加到数据框或组图层中,并自动使用自动排列放置图层。您可以选择将图层放置在顶部或底部。InsertLayer()方法允许您更精确地将新图层定位到数据框或组图层中。它使用引用图层来指定位置,图层被添加到引用图层之前或之后,具体取决于您的代码。由于InsertLayer()需要使用引用图层,因此您不能在空数据框上使用此方法。以下截图说明了这一点,其中District_Crime_Join是引用图层,School_Districts是要添加的图层。使用InsertLayer()可以将School_Districts图层放置在引用图层之前或之后:

准备就绪

如何操作…

按照以下步骤学习如何使用InsertLayer()将图层插入到数据框中:

  1. 使用 ArcMap 打开c:\ArcpyBook\Ch2\Crime_Ch2.mxd

  2. 从主 ArcMap 工具栏中点击 Python 窗口按钮。

  3. 导入arcpy.mapping模块:

    import arcpy.mapping as mapping
    
  4. 引用当前活动的文档(Crime_Ch2.mxd)并将引用分配给一个变量:

    mxd = mapping.MapDocument("CURRENT")
    
  5. 获取对Crime数据框的引用:

    df = mapping.ListDataFrames(mxd, "Crime")[0]
    
  6. 定义引用图层:

    refLayer = mapping.ListLayers(mxd, "Burglaries*", df)[0]
    
  7. 定义相对于引用图层的要插入的图层:

    insertLayer = mapping.Layer(r"C:\ArcpyBook\data\CityOfSanAntonio.gdb\Crimes2009")
    
  8. 将图层插入到数据框:

    mapping.InsertLayer(df,refLayer,insertLayer,"BEFORE")
    
  9. 您可以查阅c:\ArcpyBook\code\Ch2\InsertLayerMapDocument.py中的解决方案文件以验证您代码的准确性。

  10. 运行脚本。Crimes2009要素类将作为图层添加到数据框中,如下截图所示:如何操作…

工作原理…

在获取到arcpy.mapping模块、当前地图文档文件和Crime数据框的引用后,我们的脚本定义了一个引用图层。在这种情况下,我们使用ListLayers()函数和一个通配符Burglaries*以及Crime数据框来限制返回的图层列表只包含一个项目。这个项目应该是2009 年入室盗窃图层。我们使用 Python 列表访问并设置值为0来从列表中检索此图层并将其分配给一个图层对象。接下来,我们定义了insert图层,一个新的Layer对象,它引用了CityOfSanAntonio地理数据库中的Crimes2009要素类。最后,我们调用InsertLayer()函数,传入数据框、引用图层、要插入的图层以及一个关键字,表示要插入的图层应该放在引用图层之前。这如下面的截图所示:

工作原理…

更多内容…

你还可以重新定位已经位于数据框架或组图层中的图层。MoveLayer() 函数提供了在数据框架或组图层内重新定位图层的功能。图层的移动必须在同一数据框架内进行。你不能将图层从一个数据框架移动到另一个数据框架。就像 InsertLayer() 一样,MoveLayer() 使用参考图层来重新定位图层。

更新图层符号

有时候你可能需要更改地图文档中图层的符号。这可以通过使用 UpdateLayer() 函数来实现,该函数可以用来更改图层的符号以及图层的各种属性。在本例中,你将使用 UpdateLayer() 函数来更新图层的符号。

准备工作

arcpy.mapping 模块还通过使用 UpdateLayer() 函数,使你能够在脚本中更新图层符号。例如,你可能希望你的脚本将图层的符号从渐变色更改为渐变符号,如图下截图所示。UpdateLayer() 也可以用来更新各种图层属性,但默认功能是更新符号。由于 UpdateLayer() 是一个强大的函数,能够更改符号和属性,因此你需要了解可以提供的各种输入参数:

准备工作

如何操作…

按照以下步骤学习如何使用 UpdateLayer() 更新图层的符号:

  1. 使用 ArcMap 打开 c:\ArcpyBook\Ch2\Crime_Ch2.mxd

  2. 从主 ArcMap 工具栏中点击 Python 窗口按钮。

  3. 导入 arcpy.mapping 模块:

    import arcpy.mapping as mapping
    
  4. 引用当前活动文档(Crime_Ch2.mxd)并将引用分配给一个变量:

    mxd = mapping.MapDocument("CURRENT")
    
  5. 获取对 Crime 数据框架的引用:

    df = mapping.ListDataFrames(mxd, "Crime")[0]
    
  6. 定义将要更新的图层:

    updateLayer = mapping.ListLayers(mxd,"Crime Density by School District",df)[0]
    
  7. 定义用于更新符号的图层:

    sourceLayer = mapping.Layer(r"C:\ArcpyBook\data\CrimeDensityGradSym.lyr")
    
  8. 调用 UpdateLayer() 函数来更新符号:

    mapping.UpdateLayer(df,updateLayer,sourceLayer,True)
    
  9. 你可以查阅位于 c:\ArcpyBook\code\Ch2\UpdateLayerSymbology.py 的解决方案文件,以验证你代码的准确性。

  10. 运行脚本。现在学区犯罪密度图层将使用渐变符号而不是渐变色进行符号化,如图下截图所示:如何操作…

工作原理…

在这个菜谱中,我们使用了UpdateLayer()函数来更新图层的符号。我们没有更新任何属性,但在下一个菜谱中我们会这样做。UpdateLayer()函数要求您传递多个参数,包括数据框架、要更新的图层以及一个参考图层,从该图层中提取符号并将其应用到更新图层。在我们的代码中,updateLayer变量引用了按学区划分的犯罪密度图层,其符号将被更新。从该图层提取符号并将其应用到更新图层的源图层是一个图层文件(CrimeDensityGradSym.lyr),包含渐变符号。

要更新图层的符号,您必须首先确保更新图层和源图层具有相同的几何形状(点、线或多边形)。在某些情况下,您还需要检查属性定义是否相同,这取决于渲染器。例如,渐变色符号和渐变符号基于特定的属性。在这种情况下,两个图层都具有多边形几何形状,并且包含犯罪密度信息的CrimeDens字段。

一旦我们有了两个图层的引用,我们就调用了UpdateLayer()函数,传递了数据框架和图层,以及一个第四个参数,表示我们只更新符号。我们提供了True值作为这个第四个参数,表示我们只更新符号,而不更新属性:

mapping.UpdateLayer(df,updateLayer,sourceLayer,True)

还有更多...

UpdateLayer()函数还提供了替换一个图层并添加另一个图层的功能。图层可以完全不相关,因此不需要确保几何类型和属性字段与重新定义图层符号时相同。这种图层切换本质上执行了一个对RemoveLayer()的调用,然后是一个对AddLayer()的调用,作为一个操作。要利用此功能,您必须将symbology_only参数设置为False

更新图层属性

在前面的菜谱中,您学习了如何更新图层的符号。正如我提到的,UpdateLayer()也可以用来更新图层的各种属性,如字段别名、查询定义等。在这个菜谱中,您将使用UpdateLayer()来更改图层的各种属性。

准备工作

您还可以使用 UpdateLayer() 函数来更新有限数量的图层属性。特定的图层属性,例如字段别名、选择符号、查询定义、标签字段等,可以使用 UpdateLayer() 进行更新。一个常见的场景是,在许多地图文档中有一个图层需要更改所有地图文档中该图层实例的特定属性。为了实现这一点,您将不得不使用 ArcMap 修改具有适当属性的图层并将其保存到图层文件中。然后,该图层文件将成为源图层,它将被用来更新另一个名为 update_layer 的图层的属性。在这个菜谱中,您将使用 ArcMap 修改图层的属性,将其保存到图层文件(.lyr)中,然后使用 Python 编写一个脚本,该脚本使用 UpdateLayer() 将属性应用到另一个图层。

如何操作…

按照以下步骤学习如何使用 UpdateLayer() 更新图层属性:

  1. 使用 ArcMap 打开 c:\ArcpyBook\Ch2\Crime_Ch2.mxd。对于这个菜谱,您将使用 2009 年入室盗窃要素类,如图下所示:如何操作…

  2. 双击 Crime 数据框中的 2009 年入室盗窃要素类以显示 图层属性 窗口,如图下所示。每个选项卡代表可以为此图层设置的属性:如何操作…

  3. 点击 常规 选项卡,并将 图层名称 文本框中的值更改为名称,如图下所示:如何操作…

  4. 点击 定义查询 选项卡并定义查询,如图下所示。您可以使用 查询构建器… 按钮定义查询或直接输入查询:如何操作…

  5. OFFDESC 字段的别名更改为 Offense Description,如图下所示。

  6. 图层属性 中点击 字段 选项卡,并仅使以下截图中所选的字段可见。这是通过取消选中以下截图中的字段来完成的:如何操作…

  7. 点击 确定 关闭 图层属性 对话框。

  8. 在数据框中,右键单击 Burglaries – No Forced Entry 并选择 另存为图层文件

  9. 将文件保存为 c:\ArcpyBook\data\BurglariesNoForcedEntry.lyr

  10. 右键单击 Burglaries – No Forced Entry 图层并选择 删除

  11. 使用 ArcMap 中的 添加数据 按钮添加来自 CityOfSanAntonio 地理数据库的 Crimes2009 要素类。要素类将被添加到数据框中,如图下所示:如何操作…

  12. 在 ArcMap 中打开 Python 窗口。

  13. 导入 arcpy.mapping 模块:

    import arcpy.mapping as mapping
    
  14. 引用当前活动文档(Crime_Ch2.mxd)并将引用分配给变量:

    mxd = mapping.MapDocument("CURRENT")
    
  15. 获取 Crime 数据框的引用:

    df = mapping.ListDataFrames(mxd, "Crime")[0]
    
  16. 定义将更新的图层:

    updateLayer = mapping.ListLayers(mxd,"Crimes2009",df)[0]
    
  17. 定义将用于更新属性的图层:

    sourceLayer = mapping.Layer(r"C:\ArcpyBook\data\BurglariesNoForcedEntry.lyr")
    
  18. 调用UpdateLayer()函数来更新符号:

    mapping.UpdateLayer(df,updateLayer,sourceLayer,False)
    
  19. 您可以查阅位于c:\ArcpyBook\code\Ch2\UpdateLayerProperties.py的解决方案文件以验证代码的准确性。

  20. 运行脚本。

  21. Crimes2009图层将更新与BurglariesNoForcedEntry.lyr文件关联的属性。如图下截图所示。打开图层以查看已应用的定义查询。您还可以打开图层属性对话框以查看已应用到Crimes2009要素类的属性更改:如何操作…

在数据帧中处理时间启用图层

在本食谱中,您将学习如何为图层和数据帧启用时间。然后,您将编写一个脚本,该脚本循环遍历图层的时间范围,并以七天为间隔导出显示犯罪历史的 PDF 地图。

准备工作

DataFrameTime对象提供了对数据帧中时间启用图层的时间管理操作的访问。当您引用DataFrame.time属性时返回此对象,并包括用于检索当前时间、结束时间、开始时间、时间步长间隔以及其他通过使用时间滑块选项对话框并保存到地图文档中设置的属性。数据帧中必须有一个或多个图层启用时间,此功能才能正常工作。

如何操作...

按照以下步骤学习如何处理时间启用图层:

  1. 使用 ArcMap 打开c:\ArcpyBook\Ch2\Crime_Ch2.mxd

  2. 在 ArcMap 的内容表中,确保Crime是活动数据帧。

  3. 通过右键单击图层并选择属性打开2009 年入室盗窃图层属性对话框。选择时间选项卡,如图下截图所示:如何操作...

    通过点击在此图层上启用时间复选框来为图层启用时间。

  4. 时间属性下,为图层时间选择每个要素有一个单独的时间字段。选择时间字段SPLITDT字段。定义时间步长间隔7.00 天,如图下截图所示:如何操作...

    通过点击以下截图中的计算按钮定义图层时间范围,如图所示:

    如何操作...

  5. 检查时间步长间隔字段。您可能需要将其重置为7 天

  6. 点击应用然后确定

  7. 在 ArcMap 的工具工具栏中,选择时间滑块选项按钮以显示如图下截图所示的时间滑块选项对话框:如何操作...

  8. 时间显示选项卡的时间滑块选项对话框中,确保时间步长间隔设置为7.0 天。如果不是,请将其设置为7.0 天。同样操作时间窗口选项。如何操作...

  9. 点击确定

  10. 保存你的地图文档。保存与地图文档关联的时间启用数据非常重要。除非这样做,否则你编写的代码将无法工作。

  11. 打开 Python 窗口。

  12. 导入arcpy.mapping模块:

    import arcpy.mapping as mapping
    
  13. 引用当前活动的文档(Crime_Ch2.mxd),并将引用分配给一个变量:

    mxd = mapping.MapDocument("CURRENT")
    
  14. 获取Crime数据帧:

    df = mapping.ListDataFrames(mxd, "Crime")[0]
    
  15. 生成DataFrameTime对象:

    dft = df.time
    
  16. DataFrameTime.currentTime属性设置为DataFrameTime.startTime属性:

    dft.currentTime = dft.startTime
    
  17. 启动一个while循环,该循环将在currentTime小于或等于endTime时循环:

    while dft.currentTime <= dft.endTime:
    
  18. 在 while 循环内部,为每个将要创建的 PDF 文件创建一个文件,导出 PDF,并重置currentTime属性。整个while循环应如下所示:

    while dft.currentTime <= dft.endTime:
           fileName = str(dft.currentTime).split(" ")[0] + ".pdf"
           mapping.ExportToPDF(mxd,os.path.join(r"C:\ArcpyBook\Ch2", fileName), df)
           print("Exported " + fileName)
           dft.currentTime = dft.currentTime + dft.timeStepInterval
    
  19. 整个脚本应如下所示。你可以查阅位于c:\ArcpyBook\code\Ch2\TimeEnabledLayers.py的解决方案文件来验证你代码的准确性:如何操作...

它是如何工作的…

DataFrameTime对象提供了对数据帧中时间管理操作的访问。在这个菜谱中使用了DataFrameTime的几个属性,包括currentTimestartTimeendTimetimeStepInterval。最初,我们将currentTime属性设置为startTime属性。初始startTime是在你设置 ArcMap 中的时间步长间隔属性时计算的。while循环被设置为在currentTime属性大于endTime属性时循环。在循环内部,我们创建了一个fileName变量,将其设置为currentTime属性,并添加一个.pdf扩展名。然后我们调用ExportToPDF()函数,传入路径和文件名。理想情况下,这将导出页面布局视图到 PDF 文件。最后,我们通过将时间步长间隔属性中设置的7.0 天更新currentTime属性。

第三章. 查找和修复损坏的数据链接

在本章中,我们将介绍以下菜谱:

  • 在你的地图文档和图层文件中查找损坏的数据源

  • 使用 MapDocument.findAndReplaceWorkspacePaths() 修复损坏的数据源

  • 使用 MapDocument.replaceWorkspaces() 修复损坏的数据源

  • 使用 replaceDataSource() 修复单个图层和表对象

  • 在文件夹中的所有地图文档中查找损坏的数据源

简介

你的 GIS 数据源移动、迁移到新的数据格式或被删除的情况并不少见。结果可能导致许多地图文档或图层文件中的数据源损坏。这些损坏的数据源在修复之前无法使用,如果需要在多个地图文档中进行相同的更改,这可能是一个令人难以承受的过程。你可以使用 arcpy.mapping 自动化查找和修复这些数据源的过程,而无需打开受影响的地图文档。查找损坏的数据源是一个简单的过程,需要使用 ListBrokenDataSources() 函数,该函数返回一个包含地图文档或图层文件中所有损坏数据源的 Python 列表。通常,该函数用作脚本中的第一步,该脚本遍历列表并修复数据源。可以在单个数据层或公共工作空间中的所有图层上修复损坏的数据源。

在你的地图文档和图层文件中查找损坏的数据源

损坏的数据源是地图文档文件中一个非常普遍的问题。你可以使用 arcpy.mapping 识别已移动、已删除或格式更改的数据源。

准备工作

在 ArcMap 中,损坏的数据连接由图层名称前的红色感叹号表示。以下截图展示了这一点。arcpy.mapping 中的 ListBrokenDataSources() 函数返回来自地图文档或图层文件的具有损坏数据连接的图层对象列表:

准备工作

如何操作…

按以下步骤学习如何在地图文档文件中查找损坏的数据源。

  1. 在 ArcMap 中打开 C:\ArcpyBook\Ch3\Crime_BrokenDataLinks.mxd

    你会看到每个数据源都已损坏。在这种情况下,数据已移动到另一个文件夹,但如果数据被删除或迁移到不同的格式,你也会看到相同的指示器。例如,将数据从个人地理数据库转换为文件地理数据库的情况并不少见:

    如何操作…

  2. 关闭 ArcMap。

  3. 打开 IDLE 并创建一个新的脚本窗口。

  4. 导入 arcpy.mapping 模块:

    import arcpy.mapping as mapping
    
  5. 引用 Crime_BrokenDataLinks.mxd 地图文档文件:

    mxd = mapping.MapDocument(r"c:\ArcpyBook\Ch3\Crime_BrokenDataLinks.mxd")
    
  6. 获取损坏数据源的列表:

    listBrokenDS = mapping.ListBrokenDataSources(mxd)
    
  7. 遍历列表并打印出图层名称:

    for layer in listBrokenDS:
         print(layer.name)
    

    输出将如下所示:

    District_Crime_Join
    Bexar_County_Boundary
    District_Crime_Join
    Bexar_County_Boundary
    Bexar_County_Boundary
    Texas_Counties_LowRes
    School_Districts
    Crime_surf
    Bexar_County_Boundary
    Crime2009Table
    
  8. 将你的脚本保存为 FindFixBrokenData.py,位于 c:\ArcpyBook\Ch3 文件夹中。

  9. 你可以通过检查 c:\ArcpyBook\code\Ch3\FindFixBrokenData.py 解决方案文件来检查你的工作。

工作原理…

ListBrokenDataSources() 函数返回一个包含具有损坏数据源的 Layer 对象的 Python 列表。然后我们使用一个 for 循环来遍历这个列表并对每个图层执行某种操作。在这种情况下,我们简单地打印出图层名称,只是为了说明该函数返回的数据。在后面的菜谱中,我们将在此基础上构建代码,修复这些损坏的数据源。

还有更多...

除了从一个地图文档文件中返回损坏的数据源列表之外,ListBrokenDataSources() 函数还可以在(.lyr)图层文件中找到损坏的数据源。只需传递图层文件的路径,让函数检查文件中的损坏数据源。请注意,使用 MapLayer 包时不需要这些函数,因为这些数据与这些文件捆绑在一起,而图层文件则不同。

使用 MapDocument.findAndReplaceWorkspacePaths() 修复损坏的数据源

MapDocument.findAndReplaceWorkspacePaths() 方法用于在地图文档的所有图层和表中执行全局查找和替换工作空间路径。您还可以一次性替换多个工作空间类型的路径。例如,您可能同时传递个人和文件地理数据库工作空间类型。

准备工作

在检查修复数据集的方法之前,我们需要介绍一些定义。当讨论修复损坏数据源的方法时,您会经常看到这些术语的使用,因此您需要了解它们在这个上下文中的含义。工作空间只是一个数据容器。这可以是文件夹(在形状文件的情况下),个人地理数据库,文件地理数据库或 ArcSDE 连接。工作空间提供了工作空间的系统路径。在文件地理数据库的情况下,这包括地理数据库的名称。数据集是工作空间内的一个要素类或表,最后,数据源是工作空间和数据集名称的组合。不要将数据集与要素数据集混淆。前者是一个通用的数据术语,而后者是地理数据库中的一个对象,它作为要素类和其他数据集的容器。

在修复损坏的数据源中涉及三个 arcpy.mapping 类。它们是 MapDocumentLayerTableView。每个类都包含可以用来修复数据源的方法。在这个菜谱中,我们将检查如何使用 MapDocument 类中的 findAndReplaceWorkspacePaths() 方法在地图文档的图层和表中执行全局查找和替换操作。

如何做...

按照以下步骤学习如何使用 findAndReplaceWorkspacePaths() 修复地图文档中的图层和表:

  1. 在 ArcMap 中打开 c:\ArcpyBook\Ch3\Crime_BrokenDataLinks.mxd

  2. 右键单击任何图层并选择属性

  3. 转到 选项卡,您将注意到图层的位置是 ArcpyBook\Ch3\Data\OldData\CityOfSanAntonio.gdb。这是一个文件地理数据库,但位置已不再存在。它已移动到 C:\ArcpyBook\data 文件夹。

  4. 打开 IDLE 并创建一个新的脚本窗口。

  5. 导入 arcpy.mapping 模块:

    import arcpy.mapping as mapping
    
  6. 引用 Crime_BrokenDataLinks.mxd 地图文档文件:

    mxd = mapping.MapDocument(r"c:\ArcpyBook\Ch3\Crime_BrokenDataLinks.mxd")
    
  7. 使用 MapDocument.findAndReplaceWorkspacePaths() 来修复地图文档中每个数据源的原生路径。findAndReplaceWorksapcePaths() 方法接受旧路径作为第一个参数,新路径作为第二个参数:

    mxd.findAndReplaceWorkspacePaths(r" C:\ArcpyBook\Ch3\Data\OldData\CityOfSanAntonio.gdb", r" C:\ArcpyBook\Data\CityOfSanAntonio.gdb")
    
  8. 将结果保存到新的 .mxd 文件中:

    mxd.saveACopy(r"C:\ArcpyBook\Ch3\Crime_DataLinksFixed.mxd")
    
  9. 将脚本保存为 C:\ArcpyBook\Ch3\MapDocumentFindReplaceWorkspacePath.py

  10. 您可以通过检查 c:\ArcpyBook\code\Ch3\MapDocumentFindReplaceWorkspacePath.py 解决方案文件来检查您的作品。

  11. 运行脚本。

  12. 在 ArcMap 中打开 C:\ArcpyBook\Ch3\Crime_DataLinksFixed.mxd 文件。您将注意到所有数据源都得到了修复,如下面的截图所示:如何操作…

工作原理…

MapDocument.findAndReplaceWorkspacePaths() 方法在地图文档中的所有图层和表中执行全局查找和替换工作空间路径。您可以一次性替换多个工作空间类型的路径。

更多内容...

LayerTableView 对象也有一个 findAndReplaceWorkspacePaths() 方法,它执行相同类型的操作。区别在于,在这个 LayerTableView 对象中,该方法用于修复单个损坏的数据源,而不是全局查找,以及替换地图文档中所有损坏的数据源。

使用 MapDocument.replaceWorkspaces() 修复损坏的数据源

在正常的 GIS 操作过程中,将数据从一种文件类型迁移到另一种文件类型是一种相当常见的做法。例如,许多组织将数据从较旧的个人地理数据库格式迁移到新的文件地理数据库类型,或者甚至迁移到企业 ArcSDE 地理数据库。您可以使用 MapDocument.replaceWorkspaces() 方法自动化将您的数据集更新到不同格式的过程。

准备工作

MapDocument.replaceWorkspaces() 方法类似于 MapDocument.findAndReplaceWorkspacePaths(),但它还允许您从一个工作空间类型切换到另一个工作空间类型。例如,您可以从文件地理数据库切换到个人地理数据库。然而,它一次只能在一个工作空间中工作。在这个菜谱中,我们将使用 MapDocument.replaceWorkspaces() 来将我们的数据源从文件地理数据库切换到个人地理数据库。

如何操作…

按照以下步骤学习如何使用 MapDocument.replaceWorkspaces() 修复损坏的数据源:

  1. 在 ArcMap 中打开 c:\ArcpyBook\Ch3\Crime_DataLinksFixed.mxd

  2. 注意,所有图层和表都是从名为 CityOfSanAntonio.gdb 的文件地理数据库中加载的,如下面的截图所示:如何操作…

  3. 打开 IDLE 并创建一个新的脚本窗口。

  4. 导入 arcpy.mapping 模块:

    import arcpy.mapping as mapping
    
  5. 引用 Crime_DataLinksFixed.mxd 地图文档文件:

    mxd = mapping.MapDocument(r"c:\ArcpyBook\Ch3\Crime_DataLinksFixed.mxd")
    
  6. 调用 replaceWorkspaces() 方法,传递旧地理数据库类型和新地理数据库类型的引用:

    mxd.replaceWorkspaces(r"c:\ArcpyBook \data\CityOfSanAntonio.gdb", "FILEGDB_WORKSPACE",r"c:\ArcpyBook \new_data\CityOfSanAntonio_Personal.mdb","ACCESS_WORKSPACE")
    
  7. 保存地图文档文件的副本:

    mxd.saveACopy(r"c:\ArcpyBook\Ch3\Crime_DataLinksUpdated.mxd")
    
  8. 将脚本保存为 c:\ArcpyBook\Ch3\MapDocumentReplaceWorkspaces.py

  9. 您可以通过检查 c:\ArcpyBook\code\Ch3\MapDocumentReplaceWorkspaces.py 解决方案文件来验证您的操作。

  10. 运行脚本。

  11. 在 ArcMap 中打开 c:\ArcpyBook\Ch3\Crime_DataLinksUpdated.mxd 文件。如图所示,所有数据源现在都引用了一个个人地理数据库(注意 .mdb 扩展名)如何操作…

它是如何工作的…

MapDocument.replaceWorkspaces() 方法接受多个参数,包括旧工作空间路径和新工作空间路径,以及旧工作空间类型和新工作空间类型。工作空间的路径是自解释的,但关于工作空间类型的讨论可能会有所帮助。工作空间类型作为字符串关键字传递到方法中。在这种情况下,旧工作空间类型是文件地理数据库,因此其关键字是 FILEGDB_WORKSPACE。新工作空间类型是 ACCESS_WORKSPACE,表示个人地理数据库。个人地理数据库存储在 Microsoft Access 文件中。有几种不同类型的工作空间可以存储 GIS 数据。请确保您提供适合您数据集的工作空间类型。以下是一个有效工作空间类型的列表(许多人仍在使用形状文件,因此在这种情况下,工作空间类型将是 SHAPEFILE_WORKSPACE):

  • ACCESS_WORKSPACE: 这是一个个人地理数据库或 Access 工作空间

  • ARCINFO_WORKSPACE: 这是一个 ArcInfo 覆盖工作空间

  • CAD_WORKSPACE: 这是一个 CAD 文件工作空间

  • EXCEL_WORKSPACE: 这是一个 Excel 文件工作空间

  • FILEGDB_WORKSPACE: 这是一个文件地理数据库工作空间

  • NONE: 这用于跳过一个参数

  • OLEDB_WORKSPACE: 这是一个 OLE 数据库工作空间

  • PCCOVERAGE_WORKSPACE: 这是一个 PC ARC/INFO 覆盖工作空间

  • RASTER_WORKSPACE: 这是一个栅格工作空间

  • SDE_WORKSPACE: 这是一个 SDE 地理数据库工作空间

  • SHAPEFILE_WORKSPACE: 这是一个形状文件工作空间

  • TEXT_WORKSPACE: 这是一个文本文件工作空间

  • TIN_WORKSPACE: 这是一个 TIN 工作空间

  • VPF_WORKSPACE: 这是一个 VPF 工作空间

小贴士

当通过 replaceWorkspaces() 方法切换工作空间时,数据集名称必须相同。例如,一个名为 Highways.shp 的形状文件只能重定向到文件地理数据库工作空间,如果文件地理数据库中的数据集名称也称为 Highways。如果数据集名称不同,请在 layerTableView 对象上使用 replaceDataSource() 方法。

使用 replaceDataSource() 方法修复单个图层和表格对象

本章前面的食谱使用了MapDocument对象的各种方法来修复损坏的数据链接。LayerTableView对象也有方法可以在单个对象级别修复损坏的数据链接,而不是在地图文档文件中的所有数据集中工作。本食谱讨论了LayerTableView对象的修复。

准备工作

LayerTableView类都有一个replaceDataSource()方法。此方法可以更改单个图层或表的 workspace 路径、工作空间类型和/或数据集名称。在本例中,你将编写一个脚本,更改单个图层的 workspace 路径和工作空间类型。replaceDataSource()方法适用于LayerTableView类。对于图层,它可以在地图文档或图层文件中,对于表格,它只能引用地图文档,因为TableView对象不能包含在图层文件中。

如何操作…

按照以下步骤学习如何使用replaceDataSource()方法在地图文档中修复单个LayerTableView对象:

在 ArcMap 中打开c:\ArcpyBook\Ch3\Crime_DataLinksLayer.mxd。犯罪数据框架包含一个名为盗窃的图层,它位于CityOfSanAntonio文件地理数据库中的要素类。你将用包含相同数据的 shapefile 图层替换这个要素类:

如何操作…

  1. 打开IDLE并创建一个新的脚本窗口。

  2. 导入arcpy.mapping模块:

    import arcpy.mapping as mapping
    
  3. 引用Crime_DataLinksLayer.mxd地图文档文件:

    mxd = mapping.MapDocument(r"c:\ArcpyBook\Ch3\ Crime_DataLinksLayer.mxd")
    
  4. 获取Crime数据框架的引用:

    df = mapping.ListDataFrames(mxd,"Crime")[0]
    
  5. 找到盗窃图层并将其存储在一个变量中:

    lyr = mapping.ListLayers(mxd,"Burglary",df)[0]
    
  6. Layer对象上调用replaceDataSource()方法并传递 shapefile 的路径。一个关键字将指示这将是一个 shapefile 工作空间,并且它也指明了 shapefile 的名称:

    lyr.replaceDataSource(r"c:\ArcpyBook\data","SHAPEFILE_WORKSPACE","Burglaries_2009")
    
  7. 将结果保存到新的地图文档文件:

    mxd.saveACopy(r"c:\ArcpyBook\Ch3\Crime_DataLinksNewLayer.mxd")
    
  8. 将脚本保存为c:\ArcpyBook\Ch3\LayerReplaceDataSource.py

  9. 你可以通过检查c:\ArcpyBook\code\Ch3\LayerReplaceDataSource.py解决方案文件来验证你的工作。

  10. 运行脚本。

  11. 在 ArcMap 中打开C:\ArcpyBook\Ch3\Crime_DataLinksNewLayer.mxd。你应该能看到盗窃图层现在引用了一个新的工作空间:如何操作…

  12. 右键点击盗窃图层并选择属性

  13. 点击选项卡并注意新的工作空间、工作空间类型和数据集名称:如何操作…

它是如何工作的…

replaceDataSource()方法接受两个必需参数和两个可选参数。前两个参数定义了用作替换的图层的工作空间路径和工作空间类型。第三个参数dataset_name是一个可选参数,它定义了用作替换层的数据集名称。此名称必须完全匹配。例如,在本菜谱中,我们传递了一个dataset_name属性作为Burglaries_2009,这是现在将用作数据框中替换层的 shapefile 的名称。如果没有提供名称,则方法将尝试通过查找与当前图层的数据集属性同名的表来替换数据集。最后一个可选参数是validate。默认情况下,此值设置为True。当设置为True时,只有当workspace_path值是有效的工作空间时,工作空间才会更新。如果不是有效的工作空间,则工作空间将不会被替换。如果设置为False,则方法将设置源以匹配workspace_path,无论它是否是有效的匹配。这可能会导致损坏的数据源,但在创建或修改地图文档以准备尚未存在的数据时可能很有用。

还有更多...

LayerTableView类还包含一个findAndReplaceWorkspacePath()方法。此方法与MapDocument.findAndReplaceWorkspacePaths()方法非常相似。唯一的区别是它针对单个LayerTableView类而不是迭代整个地图文档或图层文件。

在文件夹中的所有地图文档中查找损坏的数据源

在许多组织中,一个常见的场景涉及数据从一个工作空间移动到另一个工作空间,或者从一个工作空间类型移动到另一个工作空间。当这种情况发生时,任何引用这些数据源的地图文档或图层都会损坏。如果手动执行,查找每个这些数据源可能是一项巨大的任务。幸运的是,您可以创建一个地理处理脚本,该脚本将查找文件夹或文件夹列表中的所有损坏数据源。

准备工作

在本菜谱中,您将学习如何递归搜索目录以查找地图文档文件,查找这些地图文档中的任何损坏数据源,并将损坏数据层的名称写入文件。

如何操作...

按照以下步骤学习如何在文件夹中的所有地图文档中查找所有损坏的数据源:

  1. 打开IDLE并创建一个新的脚本窗口。

  2. 导入arcpyos包:

    import arcpy.mapping as mapping, os
    
  3. 打开一个文件,用于写入损坏的图层名称:

    f = open('BrokenDataList.txt', 'w')
    
  4. 将路径传递给c:\ArcpyBook文件夹,以便在os.walk()方法和for循环中一起使用,以遍历目录树:

    for root,dirs,files in os.walk("C:\ArcpyBook"):
    
  5. for循环内部,创建一个第二个for循环,该循环遍历所有返回的文件并创建一个新的filename变量。请记住在第一个for循环内部缩进for循环:

    for name in files:
        filename = os.path.join(root, name)
    
  6. 在您添加的最后一行代码之后,测试文件扩展名以查看它是否是地图文档文件。如果是,使用路径创建一个新的地图文档对象实例,写入地图文档名称,获取损坏数据源列表,遍历每个损坏数据源,并将它们写入文件:

    if ".mxd" in filename:
         mxd = mapping.MapDocument(filename)
         f.write("MXD: " + filename + "\n")
         brknList = mapping.ListBrokenDataSources(mxd)
         for brknItem in brknList:
              print "Broken data item: " + brknItem.name + " in " + filename
              f.write("\t" + brknItem.name + "\n")
    
  7. 添加一个 print 语句来指示您已完成并关闭文件:

    print("All done")
    f.close()
    
  8. 整个脚本应如下所示:如何做...

  9. 您可以通过检查 c:\ArcpyBook\code\Ch3\ListBrokenDataSources.py 解决方案文件来验证您的作品。

  10. 运行脚本以生成文件。

  11. 打开文件查看结果。您的输出将取决于您定义的路径。以下截图显示了我的输出文件:如何做...

它是如何工作的...

此脚本结合了来自 Python os 包和 arcpy.mapping 包的方法。os.walk() 方法遍历目录树,并返回从您定义的 c:\ArcpyBook 目录开始的根目录的路径、目录列表和文件列表。这个根目录可以是任何目录。os.walk() 方法返回一个包含三个元素的元组,分别是根目录、该根目录内直接包含的目录列表以及该根目录内直接包含的文件列表。然后我们遍历这个文件列表,测试每个文件是否包含 .mxd 字符串,这表示一个地图文档文件。被识别为地图文档的文件将它们的文件名写入一个文本文件,并创建一个新的 MapDocument 对象实例。然后使用对地图文档的引用调用 ListBrokenDataSources() 方法,以生成文件内的损坏数据源列表,并将这些损坏数据源也写入文件。

第四章:自动化地图生产和打印

在本章中,我们将介绍以下菜谱:

  • 创建布局元素列表

  • 为布局元素分配唯一名称

  • 限制 ListLayoutElements() 返回的布局元素

  • 更新布局元素属性

  • 获取可用打印机的列表

  • 使用 PrintMap() 打印地图

  • 将地图导出为 PDF 文件

  • 将地图导出为图像文件

  • 导出报告

  • 使用数据驱动页面和 ArcPy 映射构建地图集

  • 将地图文档发布到 ArcGIS Server 服务

简介

ArcGIS 10 一起发布的 arcpy.mapping 模块提供了一系列与地图生产自动化相关的功能。arcpy.mapping 模块可用于自动化地图生产、构建地图集、将地图导出为图像或 PDF 文件,以及创建和管理 PDF 文件。在本章中,您将学习如何使用 arcpy.mapping 模块来自动化与地图生产和打印相关的各种地理处理任务。

创建布局元素列表

在自动化地图生产的地理处理脚本中,第一步通常是生成可用布局元素的列表。例如,您可能需要在打印或创建 PDF 文件之前更新地图的标题。在这种情况下,标题可能存储在 TextElement 对象中。您可以在地图布局视图中生成 TextElement 对象的列表,然后更改标题。第一步是生成 TextElement 对象的列表。

准备工作

在 ArcMap 中,有两个视图可用,即数据视图和布局视图。数据视图用于查看地理和表格数据、分析数据、符号化图层以及管理数据,而不考虑任何特定的地图页面大小或布局。布局视图显示打印在页面上的地图,并用于通过添加地图元素来创建生产质量的地图。这些元素包括地图框架、图层、图例、标题、北箭头、比例尺和标题块。布局中的每个对象在 arcpy.mapping 中都表示为一个布局元素类。以下屏幕截图显示了这些布局元素类中的许多示例:

准备中

每个元素都可以分配一个唯一的名称,然后可以使用该名称以编程方式访问该元素。这个唯一名称在 ArcMap 中定义。arcpy.mapping 模块提供了一个 ListLayoutElements() 函数,该函数返回所有这些元素的列表。在本例中,您将学习如何使用 ListLayoutElements() 函数生成地图布局元素列表。

如何操作...

按以下步骤学习如何生成布局元素列表:

  1. 在 ArcMap 中打开 C:\ArcpyBook\Ch4\Crime_Ch4.mxd

  2. 打开 Python 窗口。

  3. 导入 arcpy.mapping 模块:

    import arcpy.mapping as mapping
    
  4. 引用当前活动文档(Crime_Ch4.mxd)并将此引用分配给一个变量:

    mxd = mapping.MapDocument("CURRENT")
    
  5. 如果名称属性不为空,则生成布局元素列表并将其打印到屏幕上:

    for el in mapping.ListLayoutElements(mxd):
      if el.name != '':
        print(el.name)
    
  6. 整个脚本应如下所示:

    import arcpy.mapping as mapping
    mxd = mapping.MapDocument("CURRENT")
    for el in mapping.ListLayoutElements(mxd):
      if el.name != '':
        print(el.name)
    
  7. 您可以通过检查c:\ArcpyBook\code\Ch4\CreateListLayoutElements.py解决方案文件来验证您的操作。

  8. 运行脚本以查看以下输出:

    Crime_Inset
    Alternating Scale Bar
    Legend Test Performance
    Crime Legend
    North Arrow
    Inset_Map
    Test_Performance
    Crime
    
    

工作原理…

ListLayoutElements()返回一个布局元素列表,这些元素以各种布局类形式存在。每个元素可以是GraphicElementLegendElementPictureElementTextElementMapSurroundElement对象实例之一。每个元素都可以有一个唯一名称。您不必为每个元素分配名称,但如果您计划在脚本中以编程方式访问这些元素,这样做会有所帮助。在此脚本中,我们首先确保元素已分配了名称,然后再打印名称。这样做是因为 ArcMap 不需要为元素分配名称。

为布局元素分配唯一名称

使用 ArcMap 为所有布局元素分配唯一名称是一种良好的做法。如果您的地理处理脚本需要访问特定元素进行更改,这很重要。例如,您可能需要更新显示公司标志的图标。而不是在所有地图文档文件中手动进行此更改,您可以编写一个地理处理脚本,以编程方式更新所有地图文档文件并使用新标志。但是,为了使这成为可能,必须为布局元素分配唯一名称。这使您能够单独访问布局元素。

准备工作

如我之前所述,每个布局元素将属于多种元素类型之一,并且每个都可以分配名称。此元素名称可以在您需要引用 Python 脚本中的特定元素时使用。您可以使用 ArcMap 为每个布局元素分配唯一名称。在此配方中,您将使用 ArcMap 为元素分配名称。

如何操作…

按照以下步骤学习如何使用 ArcMap 为每个布局元素分配唯一名称:

  1. 在 ArcMap 中打开C:\ArcpyBook\Ch4\Crime_Ch4.mxd

  2. 切换到布局视图,您应该看到类似于以下截图的内容:如何操作…

  3. 根据元素类型,名称的分配方式不同。点击最上面的数据框,它应该是Crime,以选择它。选择手柄应如下所示:如何操作…

  4. 右键点击上方的数据框并选择属性以显示数据框属性窗口,如图下所示截图。元素名称属性定义了元素的唯一名称,并在如图下所示截图的大小和位置选项卡中找到。在此情况下,将元素名称设置为Crime如何操作…

  5. 关闭数据框属性窗口。

  6. 选择2009 犯罪数据图例,并通过右键点击图例并选择属性来打开属性窗口。

  7. 点击大小和位置选项卡。

  8. 元素名称值更改为Crime Legend,如图下所示:如何操作…

  9. 你也可以为文本元素定义唯一的名称。选择标题元素(Crime and Its Impact on School Test Performance),右键单击元素,并选择属性

  10. 点击大小和位置选项卡,并为该元素定义一个唯一的名称,如图下所示:如何操作…

工作原理…

布局视图中每个元素都可以分配一个名称,然后可以在你的地理处理脚本中使用该名称来检索特定元素。你应该努力为每个元素定义唯一的名称。并不是必须为每个元素定义一个唯一的名称,甚至不需要定义名称。然而,如果你打算从 Python 脚本中访问这些元素,给每个元素命名并确保每个名称都是唯一的是一个最佳实践。在元素命名实践中,你应该努力只包含字母和下划线。

更多内容…

你可以使用元素名称与ListLayoutElements()函数结合使用,通过通配符参数来限制函数返回的元素。在下一个示例中,你将学习如何通过使用通配符和元素类型来限制返回的布局元素列表。

限制ListLayoutElements()返回的布局元素

布局可以包含大量元素,其中许多元素你可能不需要用于特定的地理处理脚本。ListLayoutElements() 函数可以通过传递一个参数来限制返回的布局元素,该参数定义了应返回的元素类型,并可以附带一个可选通配符,该通配符通过名称的一部分来查找元素。

准备工作

布局元素有多种不同类型,包括图形、图例、图片、文本和数据框。当你返回一个布局元素列表时,你可以限制(过滤)返回的元素类型。在本例中,你将编写一个脚本,通过元素类型和通配符来过滤返回的布局元素。

如何操作…

按照以下步骤学习如何通过使用可选参数来限制ListLayoutElements()函数返回的图层列表,这些参数定义了应返回的元素类型,以及可以进一步限制返回元素的通配符:

  1. 在 ArcMap 中打开C:\ArcpyBook\Ch4\Crime_Ch4.mxd

  2. 打开 Python 窗口。

  3. 导入arcpy.mapping模块:

    import arcpy.mapping as mapping
    
  4. 引用当前活动文档(Crime_Ch4.mxd)并将此引用分配给一个变量:

    mxd = mapping.MapDocument("CURRENT")
    
  5. 使用ListLayoutElements()函数,仅限制为图例元素,以及一个通配符,该通配符返回名称中包含Crime文本的元素:

    for el in mapping.ListLayoutElements(mxd,"LEGEND_ELEMENT","*Crime*"):
      print(el.name)
    
  6. 您可以通过检查 c:\ArcpyBook\code\Ch4\RestrictLayoutElements.py 解决方案文件来验证您的作品。

  7. 运行脚本。在这种情况下,将只返回单个布局元素:

    Crime Legend
    
    

它是如何工作的...

ListLayoutElements() 是一个多功能函数,在其最基本的形式中,用于返回地图文档页面布局上的所有布局元素的列表。但是,您可以提供两个可选参数来筛选此列表。第一种筛选类型是元素类型筛选,您指定只返回布局元素类型之一。您还可以应用通配符来筛选返回的列表。这两种类型的筛选可以组合使用。例如,在这个菜谱中,我们指定只返回元素名称中包含 Crime 文本的 LEGEND_ELEMENT 对象。这导致了一个高度筛选的列表,只包含单个布局元素。

注意

ListLayoutElements() 可以使用以下元素类型之一进行筛选:DATAFRAME_ELEMENTGRAPHIC_ELEMENTLEGEND_ELEMENTMAPSURROUND_ELEMENTPICTURE_ELEMENTTEXT_ELEMENT

更新布局元素的属性

每个布局元素都有一组可以编程更新的属性。例如,LegendElement 包含允许您更改图例在页面上的位置的属性,更新图例标题,并访问图例项。

准备工作

布局元素有很多不同类型,包括图形、图例、文本、地图和图片。这些元素中的每一个都在 arcpy.mapping 包中的一个类中得到了表示。这些类提供了各种属性,您可以使用它们以编程方式更改元素。

DataFrame 类提供了访问地图文档文件中的数据帧属性。此对象可以与地图单元和页面布局单元一起工作,具体取决于所使用的属性。页面布局属性,如定位和尺寸,可以应用于包括 elementPositionXelementPositionYelementWidthelementHeight 在内的属性。

GraphicElement 对象是用于添加到页面布局的各种图形的通用对象,包括表格、图表、整洁线、标记、线条和区域形状。如果您打算通过 Python 脚本访问它,请确保为每个图形元素(以及任何其他元素)设置 name 属性。

LegendElement 提供了在页面布局中定位图例、修改图例标题以及访问图例项和父数据帧的操作。LegendElement 只能与单个数据帧相关联。

MapSurroundElement 可以指北箭头、比例尺和比例文本。它与 LegendElement 类似,并与单个数据帧相关联。此对象上的属性可以重新定位页面上的元素。

PictureElement 表示页面布局中的栅格或图像。此对象最有用的属性是获取和设置数据源,这在需要更改多个地图文档中的图片,如标志时非常有帮助。例如,您可以编写一个脚本,遍历所有地图文档文件,并用新的标志替换当前的标志。您还可以重新定位或调整大小对象。

TextElement 表示页面布局中的文本,包括插入的文本、注释、矩形文本和标题,但不包括图例标题或图表中的文本。属性允许修改文本字符串,这在需要在不同页面布局或多个地图文档中的多个位置更改相同的文本字符串时非常有用,当然,也可以重新定位对象。

页面布局中的每个元素都返回为元素对象的一个实例。在这个菜谱中,我们将使用 Legend 对象的 title 属性来编程更改 Crime 图例的标题,并获取图例中包含的图层列表。

如何做…

按照以下步骤学习如何更新布局元素的属性:

  1. 在 ArcMap 中打开 C:\ArcpyBook\Ch4\Crime_Ch4.mxd

  2. 打开 Python 窗口。

  3. 导入 arcpy.mapping 模块:

    import arcpy.mapping as mapping
    
  4. 引用当前活动文档(Crime_Ch4.mxd),并将此引用分配给一个变量:

    mxd = mapping.MapDocument("CURRENT")
    
  5. 使用 ListLayoutElements() 方法与通配符和仅限于图例元素的限制来返回仅 Crime 图例并将其存储在一个变量中:

    elLeg = mapping.ListLayoutElements(mxd, "LEGEND_ELEMENT","*Crime*")[0]
    
  6. 使用 title 属性更新图例的标题:

    elLeg.title = "Crimes by School District"
    
  7. 获取图例中包含的图层列表并打印名称:

    for item in elLeg.listLegendItemLayers():
      print(item.name)
    
  8. 整个脚本应如下所示:

    import arcpy.mapping as mapping
    mxd = mapping.MapDocument("CURRENT")
    elLeg = mapping.ListLayoutElements(mxd, "LEGEND_ELEMENT","*Crime*")[0]
    elLeg.title = "Crimes by School District"
    for item in elLeg.listLegendItemLayers():
      print(item.name)
    
  9. 您可以通过检查 c:\ArcpyBook\code\Ch4\UpdateLayoutElementProperties.py 解决方案文件来检查您的作品。

  10. 运行脚本。您应该看到以下图层被打印出来:

    Burglaries in 2009
    Crime Density by School District
    
    
  11. 变更将在以下屏幕截图显示:如何做…

它是如何工作的...

每个布局元素都有一组属性和方法。在这个特定的情况下,我们使用了 Legend 对象的 title 属性。此对象的其它属性允许您设置宽度、高度、定位等。用于 Legend 对象的方法可以调整列数、列出图例项、删除和更新项。

获取可用打印机的列表

arcpy 提供的另一个列表函数是 ListPrinterNames(),它生成可用打印机的列表。与其他我们检查过的列表函数一样,ListPrinterNames() 通常在多步脚本中的初步步骤中被调用。

准备工作

在使用PrintMap()函数打印地图之前,调用ListPrinterNames()函数是一种常见做法,该函数返回本地计算机上可用的打印机列表。然后可以通过迭代打印机列表并使用它作为PrintMap()函数的输入来找到特定的打印机。

如何做...

按照以下步骤学习如何使用ListPrinterNames()函数来返回您脚本中可用的打印机列表:

  1. 在 ArcMap 中打开C:\ArcpyBook\Ch4\Crime_Ch4.mxd

  2. 打开 Python 窗口。

  3. 导入arcpy.mapping模块:

    import arcpy.mapping as mapping
    
  4. 引用当前活动文档(Crime_Ch4.mxd)并将此引用分配给一个变量:

    mxd = mapping.MapDocument("CURRENT")
    
  5. 调用ListPrinterNames()函数并打印每个打印机:

    for printerName in mapping.ListPrinterNames():
      print(printerName)
    
  6. 您可以通过检查c:\ArcpyBook\code\Ch4\GetListOfPrinters.py解决方案文件来检查您的工作。

  7. 运行脚本。输出将根据您计算机上可用的打印机列表而变化。然而,它应该打印出类似于以下代码片段的内容:

    HP Photosmart D110 series
    HP Deskjet 3050 J610 series (Network)
    HP Deskjet 3050 J610 series (Copy 1)
    HP Deskjet 3050 J610 series
    Dell 968 AIO Printer
    
    

它是如何工作的...

ListPrinterNames()函数返回一个包含所有可用于您脚本的打印机的 Python 列表。然后您可以使用PrintMap()函数,我们将在下一节中探讨,将打印作业发送到您计算机上可用的特定打印机。

使用 PrintMap()打印地图

使用PrintMap()函数将地图布局发送到打印机非常简单。默认情况下,打印作业将被发送到与地图文档一起保存的默认打印机,但您也可以定义一个特定的打印机,将作业发送到该打印机。

准备工作

arcpy.mapping模块提供了一个PrintMap()函数,用于从 ArcMap 打印页面布局或数据帧。在调用PrintMap()之前,调用ListPrinterNames()函数是一种常见做法,该函数返回本地计算机上可用的打印机列表。然后可以通过迭代可用于PrintMap()函数的打印机列表来找到特定的打印机。

PrintMap()可以打印特定的数据帧或地图文档的页面布局。默认情况下,此函数将使用与地图文档一起保存的打印机或地图文档中的默认系统打印机。正如我之前提到的,您还可以使用ListPrinterNames()来获取可用打印机的列表,并从这些打印机中选择一个作为PrintMap()的输入。在本食谱中,您将学习如何使用PrintMap()函数来打印布局。

如何做...

按照以下步骤学习如何使用PrintMap()函数在 ArcMap 中打印布局视图:

  1. 在 ArcMap 中打开C:\ArcpyBook\Ch4\Crime_Ch4.mxd

  2. 打开 Python 窗口。

  3. 导入arcpy.mapping模块:

    import arcpy.mapping as mapping
    
  4. 引用当前活动文档(Crime_Ch4.mxd),并将此引用分配给一个变量:

    mxd = mapping.MapDocument("CURRENT")
    
  5. 查找Test_Performance数据帧,如果找到则打印它:

    for df in mapping.ListDataFrames(mxd):
      if df.name == "Test_Performance":
        mapping.PrintMap(mxd,"",df)
    
  6. 您可以通过检查c:\ArcpyBook\code\Ch4\PrintingWithPrintMap.py解决方案文件来检查您的工作。

  7. 运行脚本。脚本应将数据帧发送到默认打印机。

它是如何工作的...

PrintMap() 函数接受一个必需参数和一些可选参数。必需参数是对地图文档的引用。第一个可选参数是打印机名称。在这种情况下,我们没有指定要使用的特定打印机。由于我们没有提供特定的打印机;它将使用与地图文档一起保存的打印机或默认系统打印机,如果打印机不是地图文档的一部分。第二个可选参数是我们想要打印的数据帧,在这个例子中是 Test_Performance。其他可选参数,在本例中没有提供,是输出打印文件和图像质量。

将地图导出为 PDF 文件

而不是将你的地图或布局视图发送到打印机,你可能只想创建可以共享的 PDF 文件。ArcPy 映射提供了一个 ExportToPDF() 函数,你可以用它来做这件事。

准备工作

PDF 是一个非常流行的交换格式,旨在从许多不同的平台上可查看和打印。ArcPy 映射 ExportToPDF() 函数可以用来将数据帧或页面布局导出为 PDF 格式。默认情况下,ExportToPDF() 函数导出页面布局,但你可以传递一个可选参数,该参数引用特定的数据帧,可以打印而不是页面布局。在这个菜谱中,你将学习如何将页面布局以及特定的数据帧导出为 PDF 文件。

它是如何工作的…

按照以下步骤学习如何将地图导出为 PDF 文件:

  1. 在 ArcMap 中打开 C:\ArcpyBook\Ch4\Crime_Ch4.mxd

  2. 打开 Python 窗口。

  3. 导入 arcpy.mapping 模块:

    import arcpy.mapping as mapping
    
  4. 引用当前活动文档(Crime_Ch4.mxd),并将此引用分配给一个变量:

    mxd = mapping.MapDocument('CURRENT')
    
  5. 使用 ExportToPDF() 函数导出页面布局:

    mapping.ExportToPDF(mxd,r"c:\ArcpyBook\Ch4\Map_PageLayout.pdf")
    
  6. 你可以通过检查 c:\ArcpyBook\code\Ch4\ExportToPDF_Step1.py 解决方案文件来检查你的工作。

  7. 运行脚本。

  8. 打开创建的 Map_PageLayout.pdf 文件,你应该会看到以下截图类似的内容:如何做…

  9. 现在,我们将从我们的地图文档文件中打印特定的数据帧。修改你的脚本,使其看起来如下。你可以通过检查 c:\ArcpyBook\code\Ch4\ExportToPDF_Step2.py 解决方案文件来检查你的工作。如何做…

  10. 运行脚本并检查 PDF 文件的输出。

它是如何工作的…

ExportToPDF()函数需要两个参数,包括地图文档的引用和作为输出 PDF 文件的文件。我们开发的第一个脚本传递了地图文档的引用以及输出 PDF 文件。由于我们没有传递指定数据帧的可选参数,ExportToPDF()函数将导出页面布局。还有许多可选参数可以传递给此方法,包括特定的数据帧以及与输出内容和质量相关的参数。我们的第二个脚本传递了一个应该导出的特定数据帧。您可以通过 ArcGIS 帮助页面获取有关每个可选参数的更多信息。

将地图导出为图像文件

您也可以通过使用arcpy.mapping提供的许多功能之一,将地图或布局视图的内容导出为图像文件。每个图像导出函数的名称将根据您想要创建的图像文件类型而有所不同。传递给函数的参数也会略有不同。

准备工作

除了提供将数据帧和页面布局导出为 PDF 格式的功能外,您还可以使用arcpy.mapping提供的许多导出函数之一来导出图像文件。一些可用的格式包括 AI、BMP、EMF、EPS、GIF、JPEG、SVG 和 TIFF。每个函数提供的参数将根据图像类型而有所不同。这些函数名称的示例包括ExportToJPEG()ExportToGIF()ExportToBMP()。在本食谱中,您将学习如何将地图导出为图像。

如何操作…

按照以下步骤学习如何将您的数据或布局视图导出为图像文件:

  1. 在 ArcMap 中打开C:\ArcpyBook\Ch4\Crime_Ch4.mxd

  2. 打开 Python 窗口。

  3. 导入arcpy.mapping模块:

    import arcpy.mapping as mapping
    
  4. 引用当前活动文档(Crime_Ch4.mxd),并将此引用分配给一个变量:

    mxd = mapping.MapDocument("CURRENT")
    
  5. 获取地图文档中的数据帧列表,并找到名为"Crime"的数据帧。

    for df in mapping.ListDataFrames(mxd):
         if df.name == "Crime":
    
  6. Crime数据帧导出为 JPEG 图像。您的整个脚本现在应如下所示:如何操作…

  7. 您可以通过检查c:\ArcpyBook\code\Ch4\ExportMapImageFile.py解决方案文件来检查您的作品。

  8. 运行脚本并检查输出文件。

工作原理…

注意,ExportToJPEG()函数看起来几乎与ExportToPDF()相同。但请记住,所有导出函数的可选参数将有所不同。每个ExportTo<Type>函数将根据创建图像文件时可以使用的参数而有所不同。

导出报告

ArcGIS 中的报告为你提供了一种展示数据或分析信息的方式。报告中的信息是通过直接从要素类中的属性表或独立表中提取的信息来显示的。报告可以包含属性信息、地图、图片、图形和其他支持信息。ArcMap 包含一个 报告向导报告设计器,你可以使用它们来创建和修改报告。你还可以将报告的格式保存到模板文件中。这个模板文件可以重复使用,以根据数据中的任何变化生成新的报告。通过结合报告模板和 arcpy.mapping,你可以自动化报告的生产。

准备工作

ArcGIS 中的 报告向导 可以用来创建报告。ArcGIS 报告有两种原生数据格式:报告文档文件RDF)和报告布局文件RLF)。RDF 报告提供数据的静态报告。相当于一次性快照。RLF 是一个模板文件,它使用 报告设计器 创建。报告模板文件可以重复使用,并包含报告中的所有字段以及它们的分组、排序和格式。它还包括任何布局元素,如图形或地图。当报告重新运行时,报告将根据与模板连接的源数据重新生成。arcpy.mapping ExportReport() 函数可以用来将数据源连接到模板文件以自动化报告的创建。在本菜谱中,你将学习如何使用 ExportReport() 函数与 PDFDocument 类一起创建包含学区犯罪信息的报告。报告将包括属性信息和学区边界地图。

如何操作…

为了节省时间,我已经为你预先创建了一个报告模板(RLF)文件供你使用。这个文件名为 CrimeReport.rlf,位于 c:\ArcpyBook\Ch4 文件夹中,包含学区名称、犯罪数量、犯罪密度和测试成绩分数的属性列。此外,模板中还添加了一个包含学区边界的地图占位符。

按照以下步骤学习如何使用 arcpy.mapping ExportReport() 函数和 PDFDocument 类自动化生成报告:

  1. 在 IDLE 或你喜欢的 Python 编辑器中创建一个新的脚本文件,并将其保存为 c:\ArcpyBook\Ch4\CreateReport.py

  2. 导入 arcpyos 模块,并获取当前工作目录:

    import arcpy
    import os
    path = os.getcwd()
    
  3. 创建输出 PDF 文件:

    #Create PDF and remove if it already exists
    pdfPath = path + r"\CrimeReport.pdf"
    if os.path.exists(pdfPath):
      os.remove(pdfPath)
    pdfDoc = arcpy.mapping.PDFDocumentCreate(pdfPath)
    
  4. 创建一个学区列表。我们将遍历这个列表为每个学区创建报告:

    districtList = ["Harlandale", "East Central", "Edgewood", "Alamo Heights", "South San Antonio", "Southside", "Ft Sam Houston", "North East", "Northside", "Lackland", "Southwest", "Judson", "San Antonio"]
    
  5. 获取地图文档、数据框架和图层的引用:

    mxd = arcpy.mapping.MapDocument(path + r"\Crime_Ch4.mxd")
    df = arcpy.mapping.ListDataFrames(mxd)[0]
    lyr = arcpy.mapping.ListLayers(mxd, "Crime Density by School District")[0]
    
  6. 开始遍历学区,并应用一个 where 子句作为定义查询,以便只显示单个学区:

    pageCount = 1
    for district in districtList:
      #Generate image for each district
      whereClause = "\"NAME\" = '" + district + " ISD'"
      lyr.definitionQuery = whereClause
    
  7. 选择单个学区,将数据框架范围设置为学区的范围,并清除选择集:

    arcpy.SelectLayerByAttribute_management(lyr, "NEW_SELECTION", whereClause)
    df.extent = lyr.getSelectedExtent()
    arcpy.SelectLayerByAttribute_management(lyr, "CLEAR_SELECTION")
    
  8. 将数据框架导出为位图(.bmp)文件:

    arcpy.mapping.ExportToBMP(mxd, path + "\DistrictPicture.bmp", df) #single file
    
  9. 调用ExportReport()函数来创建报告:

    #Generate report
    print("Generating report for: " + district + " ISD")
    arcpy.mapping.ExportReport(report_source=lyr, report_layout_file=path + r"\CrimeLayout.rlf",output_file=path + r"\temp" + str(pageCount) + ".pdf", starting_page_number=pageCount)
    
  10. 将报告附加到 PDF 文件:

    #Append pages into final output
    print("Appending page: " + str(pageCount))
    pdfDoc.appendPages(path + r"\temp" + str(pageCount) + ".pdf")
    
  11. 删除临时 PDF 报告:

    os.remove(path + r"\temp" + str(pageCount) + ".pdf")
    pageCount = pageCount + 1
    
  12. 保存 PDF 文档:

    pdfDoc.saveAndClose()
    
  13. 整个脚本应如下所示:如何操作…

  14. 您可以通过检查c:\ArcpyBook\code\Ch4\CreateReport.py解决方案文件来检查您的工作。

  15. 保存并运行您的脚本。这将创建一个名为CrimeReport.pdf的文件,位于您的c:\ArcpyBook\ch4文件夹中。内容将包含每个学区的一页报告,如本截图所示:如何操作…

它是如何工作的…

在这个配方中,我们使用了arcpy.mapping模块中的几个函数和类,包括PDFDocumentExportToReport()ExportToBMP()。最初,我们使用了PDFDocumentCreate()函数来创建PDFDocument的一个实例,它包含指向我们将创建的CrimeReport.pdf文件的指针。接下来,我们创建了一个学区列表,并开始遍历其中的每一个。在循环内部,对于每个学区,我们在图层上设置了一个定义查询,选择了该学区,并返回了用于设置数据框架范围的学区范围。然后,使用ExportToBMP()函数创建了一个位图文件,并使用ExportReport()函数生成了报告。最后,每个页面都被附加到CrimeReport.pdf文件中,并保存了文档。

使用数据驱动页面和 ArcPy 地图构建地图集

许多组织需要创建包含一系列覆盖更大地理区域的单个地图的地图集。这些地图集包含一系列地图和一些可选和附加页面,包括标题页、概述图以及一些其他辅助信息,例如报告和表格。例如,一家公用事业公司可能希望生成一份详细说明其服务区域内资产的地图集。这份公用事业公司的地图集可能包括一系列地图,每个地图都采用大比例尺,以及标题页和概述图。然后,这些资源将被合并成一个可以打印或作为 PDF 文件分发的单一文档。

准备工作

ArcGIS for Desktop 通过结合数据驱动页面和arcpy.mapping脚本来提供高效创建地图集的能力。使用单个地图文档文件,您可以使用数据驱动页面工具栏,通过布局视图以及您的操作数据和索引图层来创建一系列基本地图。索引图层包含将用于定义系列中每个地图范围的特征。然而,如果您需要在地图集中包含额外的页面,包括标题页、概述图和其他辅助页面,您需要将数据驱动页面工具栏的输出与arcpy.mapping模块提供的功能相结合。使用arcpy.mapping模块,您可以自动化地图系列的导出并将辅助文件附加到单个地图集文档中。虽然当然可以使用 Python 和arcpy.mapping模块仅通过编程生成整个地图集,但结合编程和数据驱动页面工具栏的组合使用更为高效。在本菜谱中,您将学习如何创建包含一系列地图以及标题页和概述图页的地图集。

如何操作…

为了节省时间,我已经为您预先创建了一个包含数据和数据驱动页面功能以创建一系列华盛顿州金县地形图的地图文档文件。这个名为Topographic.mxd的文件位于c:\ArcpyBook\Ch4文件夹中。您可能需要花几分钟时间在 ArcGIS for Desktop 中打开此文件并检查数据。数据驱动页面功能已经为您启用。此外,还为您创建了一个地图标题页(TitlePage.pdf)和一个概述图页(MapIndex.pdf)。这些文件也位于您的c:\ArcpyBook\Ch4文件夹中。

生成地图系列的步骤可能有些长,超出了本书的范围。但是,如果您想了解过程概述,请访问ArcGIS Desktop 帮助系统,导航到桌面 | 地图 | 页面布局 | 创建地图集,并遵循此文件夹下的前七项。这包括通过向地图集中添加动态文本来使用 ArcGIS 创建地图集。

按照以下步骤学习如何使用数据驱动页面功能和arcpy.mapping模块来创建地图集:

  1. 创建一个新的 IDLE 脚本并将其保存为c:\ArcpyBook\Ch4\DataDrivenPages_MapBook.py

  2. 导入arcpyos模块:

    import arcpy
    import os
    
  3. 创建一个输出目录变量:

    # Create an output directory variable
    outDir = r"C:\ArcpyBook\Ch4"
    
  4. 在指定的输出目录中创建一个新的、空的 PDF 文档:

    # Create a new, empty pdf document in the specified output directory
    finalpdf_filename = outDir + r"\MapBook.pdf"
    if os.path.exists(finalpdf_filename):
      os.remove(finalpdf_filename)
    finalPdf = arcpy.mapping.PDFDocumentCreate(finalpdf_filename)
    
  5. 将标题页添加到 PDF 中:

    # Add the title page to the pdf
    print("Adding the title page  \n")
    finalPdf.appendPages(outDir + r"\TitlePage.pdf")
    
  6. 将索引图添加到 PDF 中:

    # Add the index map to the pdf
    print("Adding the index page  \n")
    finalPdf.appendPages(outDir + r"\MapIndex.pdf")
    
  7. 将数据驱动页面导出到一个临时 PDF 文件,并将其添加到最终 PDF 中:

    # Export the Data Driven Pages to a temporary pdf and then add it to the
    # final pdf. Alternately, if your Data Driven Pages have already been
    # exported, simply append that document to the final pdf.
    mxdPath = outDir + r"\Topographic.mxd"
    mxd = arcpy.mapping.MapDocument(mxdPath)
    print("Creating the data driven pages \n")
    ddp = mxd.dataDrivenPages
    temp_filename = outDir + r"\tempDDP.pdf"
    
    if os.path.exists(temp_filename):
      os.remove(temp_filename)
    ddp.exportToPDF(temp_filename, "ALL")
    print("Appending the map series  \n")
    finalPdf.appendPages(temp_filename)
    
  8. 更新最终 PDF 的属性:

    # Update the properties of the final pdf.
    finalPdf.updateDocProperties(pdf_open_view="USE_THUMBS", pdf_layout="SINGLE_PAGE")
    
  9. 保存 PDF:

    # Save your result
    finalPdf.saveAndClose()
    
  10. 删除临时数据驱动页面文件:

    # remove the temporary data driven pages file
    if os.path.exists(temp_filename):
        os.remove(temp_filename)
    
  11. 整个脚本应如下所示:如何操作…

  12. 您可以通过检查c:\ArcpyBook\code\Ch4\DataDrivenPages_MapBook.py解决方案文件来验证您的作品。

  13. 保存并执行您的脚本。如果脚本成功执行,您应该在c:\ArcpyBook\Ch4文件夹中找到一个名为MapBook.pdf的新文件。当您打开这个文件时,您应该看到这个截图:如何操作…

工作原理…

arcpy.mapping模块中的PDFDocument类常用于创建地图集。在这个示例中,我们使用了PDFDocumentCreate()函数来创建一个PDFDocument实例。将输出 PDF 文件的路径传递给了PDFDocumentCreate()函数。使用这个PDFDocument实例,我们随后调用了两次PDFDocument.appendPages()方法,插入已经存在的作为 PDF 文件的标题页和地图索引文件。接下来,我们从地图文档文件中检索了一个dataDrivenPages对象,并将每一页导出到单个 PDF 文档中。然后,将这个文档附加到我们最终的输出 PDF 文件中,该文件已经包含了标题页和地图索引页。最后,我们更新了PDFDocument属性以使用缩略图和单页视图,保存了整个文件,并删除了临时数据驱动页面文档。

将地图文档发布到 ArcGIS Server 服务

使用arcpy.mapping模块,您可以将地图文档文件发布到ArcGIS Server作为地图服务。ArcGIS Server 是一个在网络上分发地图和数据的平台。使用 ArcGIS JavaScript API,可以从 ArcGIS Server 中创建的服务创建 Web 和移动应用程序。有关 ArcGIS Server 的更多信息,请访问 esri ArcGIS Server 网站www.esri.com/software/arcgis/arcgisserver。从地图文档文件创建地图服务涉及几个步骤。地图文档文件必须首先分析其适用性和性能问题,并在最终发布到 ArcGIS Server 之前修复任何出现的错误。这个过程包括调用arcpy.mapping函数以及使用ArcToolbox中的几个工具,这些工具可以从您的脚本中调用。错误修复后,您可以上传生成的服务定义草案文件到 ArcGIS Server 作为服务。

准备工作

使用 Python 将地图文档发布到 ArcGIS Server 是一个三步过程。第一步是调用CreateMapSDDraft() arcpy.mapping函数。这将把地图文档文件转换为服务定义草稿文件。此文件包含地图文档、关于服务的信息以及一组服务属性。关于服务的信息包括要发布到的服务器连接或服务器类型、要发布的服务类型、服务的元数据以及数据引用。草稿服务定义文件不包含数据。CreateMapSDDraft()还会生成一个包含可能引起服务发布问题的错误和警告的 Python 字典。

第二步是调用StageService 工具(.sd)。暂存编译了成功发布 GIS 资源所需的信息。如果您的数据未在服务器上注册,它将在服务定义草稿暂存时添加。最后,可以使用UploadServiceDefinition 工具将服务定义草稿文件上传并发布为 GIS 服务到指定的 GIS 服务器。此步骤将服务定义文件复制到服务器上,提取所需信息,并发布 GIS 资源。以下是此过程的示意图:

准备就绪

注意,您需要能够访问 ArcGIS Server 实例,并且还需要有发布服务的必要权限才能完成此练习。在本食谱中,您将学习如何将地图文档文件发布到 ArcGIS Server 地图服务。

如何操作…

按照以下步骤分析地图文档,以确定其是否适合发布到 ArcGIS Server,然后将其作为地图服务发布:

  1. 创建一个新的 IDLE 脚本,并将其保存为c:\ArcpyBook\Ch4\PublishMapService.py

  2. 导入arcpy.mapping模块:

    import arcpy.mapping as mapping
    
  3. 设置当前工作空间:

    wrkspc = r'c:\ArcpyBook\Ch4'
    
  4. 获取地图文档的引用:

    mxd = mapping.MapDocument(wrkspc + r"\Crime.mxd")
    
  5. 定义服务名称和服务草稿定义文件的变量:

    service = 'Crime'
    sddraft = wrkspc + service + '.sddraft'
    
  6. 创建服务定义草稿文件:

    mapping.CreateMapSDDraft(mxd, sddraft, service)
    
  7. 分析草稿文件:

    analysis = mapping.AnalyzeForSD(wrkspc + "Crime.sddraft")
    
  8. 创建一个循环结构,该结构将遍历所有潜在的消息、警告和错误,并打印出信息:

    for key in ('messages', 'warnings', 'errors'):
        print("----" + key.upper() + "----")
        vars = analysis[key]
        for ((message, code), layerlist) in vars.iteritems():
            print "    ", message, " (CODE %i)" % code
            print("     applies to:",)
            for layer in layerlist:
                print(layer.name)
    
  9. 整个脚本应如下所示:如何操作…

  10. 您可以通过检查c:\ArcpyBook\code\Ch4\PublishMapService.py解决方案文件来验证您的操作。

  11. 保存并运行您的代码以查看此输出:

    ----MESSAGES----
         Layer draws at all scale ranges  (CODE 30003)
         applies to: District_Crime_Join
    Bexar_County_Boundary
    District_Crime_Join
    Bexar_County_Boundary
    Bexar_County_Boundary
    Texas_Counties_LowRes
    School_Districts
    Crime_surf
    Bexar_County_Boundary
    ----WARNINGS----
         Layer's data source has a different projection [GCS_WGS_1984] than the data frame's projection  (CODE 10001)
         applies to: District_Crime_Join
    Bexar_County_Boundary
    District_Crime_Join
    Bexar_County_Boundary
    Bexar_County_Boundary
    Texas_Counties_LowRes
    School_Districts
    Crime_surf
    Bexar_County_Boundary
         Missing Tags in Item Description  (CODE 24059)
         applies to:      Missing Summary in Item Description (CODE 24058)
         applies to: ----ERRORS----
         Data frame uses a background symbol that is not a solid fill  (CODE 18)
    
    

    小贴士

    您需要特别注意错误部分。在创建服务之前,必须修复错误。警告可能表明与服务的性能相关的问题,但它们不会阻止服务发布。在这种情况下,错误表明数据帧使用了一个不是实心填充的背景符号。在我们可以继续之前,需要在 ArcGIS 中进行更正。

  12. 在 ArcMap 中,打开位于c:\ArcpyBook\ch4文件夹中的crime.mxd文件,在Crime数据帧上右键单击并选择属性

  13. 选择 框架 选项卡,如图所示:如何操作…

  14. 背景 从当前符号更改为无,然后点击 确定如何操作…

  15. 对地图文档中的每个数据帧重复此过程。

  16. 重新运行你刚才编写的脚本。这次,你不应该看到任何错误。你仍然有一个可能需要修复的警告,但警告不会阻止你的地图文档作为服务发布。

  17. 在所有错误都修复后,我们现在将 Crime.mxd 文件转换为 Crime.sd 文件。删除你在第 6 步中添加的循环结构。

  18. 添加以下 if/else 代码块。请注意,我对调用 UploadServiceDefinition 工具的代码行进行了注释。如果你有权访问一个 ArcGIS Server 实例,并且拥有适当的权限和连接信息,你可以取消注释此行,以便将其作为地图服务上传文件。你还需要在 con 变量中添加实例的连接参数,该变量作为此工具的第二个参数传递。保存并执行脚本以查看结果:

    if analysis['errors'] == {}:
        #execute StageService
        arcpy.StageService_server(sddraft,sd)
        #execute UploadServiceDefinition
        #arcpy.UploadServiceDefinition_server(sd, con)
    else:
        #if the sddraft analysis contained errors, display them
        print(analysis['errors'])
    
  19. 你的整个脚本应该如下所示:如何操作…

  20. 你可以通过检查 c:\ArcpyBook\code\Ch4\PublishMapService2.py 解决方案文件来检查你的工作。

  21. 如果你有权访问一个 ArcGIS Server 实例并且拥有必要的权限,你可以取消注释 UploadServiceDefinition 工具并执行脚本。

它是如何工作的…

CreateMapSDDraft() 函数从地图文档文件创建服务定义草案文件。接下来,我们调用 AnalyzeForSD() 函数并检查返回的消息、警告或错误。任何识别出的错误必须在创建地图服务之前修复。最后,如果没有错误,我们调用 StageService 工具,该工具创建一个可以传递给 UploadServiceDefinition 工具进行发布的 Service Definition Draft 文件。

第五章。从脚本中执行地理处理工具

在本章中,我们将涵盖以下菜谱:

  • 查找地理处理工具

  • 获取工具箱别名

  • 从脚本中执行地理处理工具

  • 将工具的输出用作另一个工具的输入

简介

ArcGIS for Desktop 包含超过 800 个地理处理工具,这些工具可以在您的 Python 脚本中使用。在您的 Python 脚本中使用地理处理工具可以使您执行复杂的流程并执行批量地理处理任务。在本章中,您将学习如何在脚本中使用这些工具。每个工具都有其独特的特性。执行每个工具的语法将根据所需输入类型的不同而有所不同。我们将探讨如何使用 ArcGIS for Desktop 帮助系统确定任何工具的输入参数。工具的执行将导致创建一个或多个输出数据集,以及工具运行期间生成的消息集。我们将探讨如何使用这些消息。

查找地理处理工具

在您的地理处理脚本中使用工具之前,您需要确保您可以根据当前运行的 ArcGIS for Desktop 许可证级别访问此工具,或者您的最终用户将运行。此外,您已许可并启用的任何扩展也必须考虑在内。这些信息包含在 ArcGIS for Desktop 帮助系统中。

准备工作

您的脚本中地理处理工具的可用性取决于您使用的 ArcGIS 许可证级别。在 ArcGIS for Desktop 的 10.3 版本中,有三个许可证级别,即基本、标准和高级。这些以前分别被称为 ArcViewArcEditorArcInfo。了解您在脚本中想要使用的工具所需的许可证级别非常重要。此外,在 ArcGIS for Desktop 中使用扩展可能会导致您的脚本可用更多工具。在 ArcGIS for Desktop 中查找工具有两种主要方法。第一种是使用搜索窗口,第二种是简单地浏览 ArcToolbox 的内容。在本菜谱中,您将学习如何使用搜索窗口查找可用于您脚本的可用地理处理工具。

如何做…

  1. 在 ArcMap 中打开 C:\ArcpyBook\Ch5\Crime_Ch5.mxd

  2. 地理处理 菜单项中选择 搜索工具。这将显示 搜索 窗口,如图下所示。默认情况下,您将搜索 工具如何做…

  3. 在搜索框中输入Clip术语。当您开始输入这个单词时,搜索框将自动根据您输入的前几个字母过滤结果。您会注意到对于Clip,有三种可能的工具:clip(analysis)clip(coverage)clip(data_management)。存在许多情况,其中有几个地理处理工具具有相同的名称。为了唯一地定义一个工具,工具箱别名附加到工具名称上。我们将在下一个菜谱中更详细地检查工具箱别名。

  4. 现在,点击搜索按钮以生成匹配工具的列表。搜索应生成类似于以下截图的列表。工具在搜索结果中以锤子图标表示。您还会在搜索结果中看到几个其他图标。滚动图标表示 Python 脚本,而包含多色方块的图标表示模型:如何操作…

  5. 选择Clip (Analysis)工具。这将打开Clip (Analysis)工具的对话框。这对您作为脚本程序员来说并不那么有用。您可能对 ArcGIS for Desktop 提供的特定工具的帮助更感兴趣。

  6. 点击工具对话框底部的工具帮助按钮以显示有关此特定工具的详细信息:如何操作…

  7. 滚动到帮助页面底部以检查Clip工具的语法。

它是如何工作的…

帮助系统包含每个工具的摘要、插图、用法、语法、代码示例、可用环境变量、相关主题和许可信息。作为地理处理脚本程序员,您主要会对语法、代码示例和底部附近的许可信息部分感兴趣。

小贴士

您应该始终检查每个工具的帮助文档底部的许可信息部分,以确保您拥有使用该工具的适当许可级别。

语法部分包含有关如何从您的 Python 脚本中调用此工具的信息,包括工具的名称和必需的以及可选的输入参数。所有参数都将包含在括号内。Clip工具的必需参数是in_featuresclip_featuresout_feature_class。当您从脚本调用此工具时,您必须提供这些参数以使工具正确执行。第四个参数是一个可选参数,称为cluster_tolerance。在语法中标记为可选的参数被大括号包围。以下截图提供了一个大括号包围的可选参数的示例。这并不意味着您在调用工具时将参数包围在大括号内。它仅用于帮助部分,以表明当从地理处理脚本调用时此参数是可选的:

它是如何工作的…

获取工具箱别名

所有工具箱都有一个别名,当与工具名称结合时,为 ArcGIS for Desktop 中的任何工具提供唯一的引用。这个别名是必要的,因为许多工具具有相同的名称。当从你的 Python 脚本引用工具时,需要引用工具名称和别名。

准备工作

在上一个示例中,我们探讨了裁剪工具。实际上有三个裁剪工具,它们分别位于分析工具覆盖工具数据管理工具工具箱中。每个裁剪工具执行不同的功能。例如,分析工具工具箱中的裁剪工具使用输入要素裁剪矢量要素类,而数据管理工具工具箱中的裁剪工具用于创建栅格的空间子集。由于可能存在多个具有相同名称的工具,我们可以通过提供工具名称和工具所在的工具箱别名来唯一地识别特定的工具。在这个示例中,你将学习如何找到工具箱的别名。

如何操作…

  1. 在 ArcMap 中打开 C:\ArcpyBook\Ch5\Crime_Ch5.mxd

  2. 如果需要,打开ArcToolbox

  3. 查找如图所示的分析工具工具箱:如何操作…

  4. 右键单击分析工具工具箱并选择属性。这将显示如图所示的分析工具属性对话框。别名文本框将包含别名:如何操作…

它是如何工作的…

你可以按照以下过程找到任何工具箱的别名名称。在 Python 脚本中,你可以通过使用 <toolname>_<toolbox alias> 语法来执行工具。例如,如果你正在调用缓冲区工具,它将是 Buffer_analysis。工具箱别名通常是简单的。它们通常是单个单词,不包含破折号或特殊字符。在下一个示例中,我们将创建一个简单的脚本,按照这个格式执行工具。

从脚本中执行地理处理工具

一旦你确定了工具箱别名并验证了基于你当前许可级别的工具可访问性,你就可以将工具的执行添加到脚本中。

准备工作

现在你已经了解了如何找到可用的工具以及如何唯一引用它们,下一步就是将这些工具组合起来,并在地理处理脚本中执行一个工具。在这个示例中,你可以从你的脚本中执行这个工具。

如何操作…

  1. 在 ArcMap 中打开 C:\ArcpyBook\Ch5\Crime_Ch5.mxd

  2. 点击添加数据按钮,将 EdgewoodSD.shp 文件从 c:\ArcpyBook\Ch5 文件夹添加到内容表中。

  3. 如果需要,关闭按学区划分的犯罪密度2009 年盗窃案图层,以更好地查看EdgewoodSD图层。此文件中只有一个多边形要素。它代表Edgewood 学区。现在,我们将编写一个脚本,将2009 年盗窃案要素剪辑到这个学区。

  4. 在 ArcMap 中打开 Python 窗口。

  5. 导入arcpy模块:

    import arcpy
    
  6. 创建一个变量,引用要剪辑的输入要素类:

    in_features = "c:/ArcpyBook/data/CityOfSanAntonio.gdb/Burglary"
    
  7. 创建一个变量,引用用于剪辑的图层:

    clip_features = "c:/ArcpyBook/Ch5/EdgewoodSD.shp"
    
  8. 创建一个变量,引用输出要素类:

    out_feature_class = "c:/ArcpyBook/Ch5/ClpBurglary.shp"
    
  9. 分析工具箱中执行Clip工具:

    arcpy.Clip_analysis(in_features,clip_features, out_feature_class)
    
  10. 你可以通过检查c:\ArcpyBook\code\Ch5\ExecuteGeoprocessingTools.py解决方案文件来检查你的工作。

  11. 运行脚本。包含仅限于EdgewoodSD学区内的盗窃点的输出要素类应添加到数据框中,如下截图所示:如何做…

如何工作…

在这个菜谱中,我们关注的代码主要行是执行Clip工具的最后一行。注意,我们通过指定Clip_analysis语法来调用此工具,这给了我们Clip工具在分析工具箱中的引用,该工具别名为analysis。我们还传递了三个参数,分别引用输入要素类、剪辑要素类和输出要素类。我应该指出,我们硬编码了每个数据集的路径。这不是一个好的编程实践,但在这个特定实例中,我只是想说明如何执行一个工具。未来的章节将展示如何从你的脚本中移除硬编码,并使它们更加灵活。

你使用的多数工具都需要数据源路径。此路径必须与 ArcCatalog 位置工具栏上报告的路径相同,如下截图所示:

如何工作…

工具使用 ArcCatalog 通过 ArcCatalog 路径查找地理数据。此路径是一个字符串,并且对每个数据集都是唯一的。路径可以包括文件夹位置、数据库连接或 URL。因此,在尝试针对数据编写 Python 脚本之前,使用 ArcCatalog 检查路径是很重要的。ArcSDE 路径需要特别注意。许多 ArcSDE 用户没有标准化的连接名称,这可能在运行模型或脚本时引起问题。

还有更多...

地理处理工具以两种方式组织。您可以通过arcpy上的函数或与工具箱别名匹配的模块访问工具。在第一种情况下,当工具可以通过arcpy作为函数访问时,它们将以您在本教程中遵循的格式调用。工具名称后跟一个下划线和工具箱别名。在第二种形式中,工具作为模块的函数调用,该模块的名称与工具箱别名相同。在这里,analysis是工具箱别名,因此它成为一个模块。Clip是这个模块的函数,调用方式如下:

arcpy.analysis.Clip(in_features,clip_features,out_feature_class)

您使用哪种方法完全是个人喜好问题。它们都完成了相同的事情,即执行地理处理工具。

使用工具的输出作为另一个工具的输入

在许多情况下,您需要将一个工具的输出作为另一个工具的输入。这被称为工具链。工具链的一个例子可能涉及缓冲一个stream层,然后找到所有位于缓冲区内的住宅属性。在这种情况下,Buffer工具将输出一个新的层,然后该层将被用作Select by Location工具或其他叠加工具的输入。在本教程中,您将学习如何获取工具的输出并将其用作另一个工具的输入。

准备工作

Buffer工具使用指定的距离从一个输入要素层创建输出要素类。这个输出要素类可以存储在变量中,然后可以将其用作另一个工具的输入,例如按位置选择层工具。在本教程中,您将学习如何使用Buffer工具的输出作为按位置选择层工具的输入,以找到位于溪流半英里范围内的学校。

如何操作...

按照以下步骤学习如何在 ArcMap 中访问当前活动的地图文档:

  1. 使用新的地图文档文件(.mxd)打开 ArcMap。

  2. 点击添加数据按钮,并将c:\ArcpyBook\data\TravisCounty中的溪流和学校要素文件添加到地图中。

  3. 点击 Python 窗口按钮。

  4. 导入arcpy模块:

    import arcpy
    
  5. 设置工作空间:

    arcpy.env.workspace = "c:/ArcpyBook/data/TravisCounty"
    
  6. 开始try语句并添加用于溪流、缓冲溪流层、距离和学校的变量:

    try:
      # Buffer areas of impact around major roads
      streams = "Streams.shp"
      streamsBuffer = "StreamsBuffer.shp"
      distance = "2640 Feet"
      schools2mile = "Schools.shp"
      schoolsLyrFile = 'Schools2Mile_lyr'
    
  7. 通过传递输入要素类、输出要素类、距离以及控制输出缓冲区外观的几个可选变量来执行Buffer工具。

    arcpy.Buffer_analysis(streams, streamsBuffer, distance,'FULL','ROUND','ALL')
    
  8. 使用MakeFeatureLayer工具创建学校的临时图层:

    arcpy.MakeFeatureLayer_management(schools2mile, schoolsLyrFile)
    
  9. 使用SelectLayerByLocation工具选择位于溪流半英里范围内的所有学校:

    arcpy.SelectLayerByLocation_management(schoolsLyrFile, 'intersect', streamsBuffer)
    
  10. 添加except块以捕获任何错误:

    except Exception as e:
      print(e.message)
    
  11. 整个脚本应如下所示:如何操作...

  12. 您可以通过检查c:\ArcpyBook\code\Ch5\ToolOutputUsedAsInput.py解决方案文件来检查您的作业。

  13. 运行脚本以查看以下截图所示的结果:如何操作...

工作原理...

Buffer 工具创建一个输出要素类,我们称之为 StreamsBuffer.shp,并存储在一个名为 streamsBuffer 的变量中。然后,streamsBuffer 变量被用作 SelectLayerByLocation 工具的输入,作为传递给函数的第三个参数。创建 Schools2Mile_lyr 层文件也实现了将此输出作为输入参数的功能。使用一个工具的输出只需创建一个变量来存储输出数据,然后它可以在其他工具中按需重复使用。

第六章:创建自定义地理处理工具

在本章中,我们将介绍以下食谱:

  • 创建自定义地理处理工具

  • 创建 Python 工具箱

简介

除了可以访问 ArcGIS 提供的系统工具外,您还可以创建自己的自定义工具。这些工具与系统工具的工作方式相同,可以在 ModelBuilder、Python 窗口或独立的 Python 脚本中使用。许多组织构建自己的工具库,这些工具库执行特定于其数据的地理处理操作。

创建自定义地理处理工具

除了能够在脚本中执行任何可用的工具外,您还可以创建自己的自定义工具,这些工具也可以从脚本中调用。自定义工具通常用于处理特定于组织的地理处理任务。这些工具也可以轻松共享。

准备工作

在本食谱中,您将学习如何通过在 ArcToolbox 中的自定义工具箱中附加 Python 脚本来创建自定义地理处理脚本工具。创建自定义脚本工具有许多优点。当您采取这种方法时,脚本成为地理处理框架的一部分,这意味着它可以从模型、命令行或另一个脚本中运行。此外,脚本可以访问 ArcMap 的环境设置和帮助文档。其他优点包括美观、易于使用的用户界面和错误预防功能。提供的错误预防功能包括一个对话框,它会通知用户某些错误。

这些自定义开发的脚本工具必须添加到您创建的自定义工具箱中,因为 ArcToolbox 提供的系统工具箱是只读工具箱,因此不能接受新工具。

在本食谱中,您将获得一个预先编写的 Python 脚本,该脚本从逗号分隔的文本文件中读取野火数据,并将这些信息写入名为 FireIncidents 的点要素类。对这些数据集的引用是硬编码的,因此您必须修改脚本以接受动态变量输入。然后,您将脚本附加到 ArcToolbox 中的自定义工具,以便您的最终用户可以通过可视界面使用该脚本。

如何操作…

您编写的自定义 Python 地理处理脚本可以添加到自定义工具箱中的 ArcToolbox 中。您不允许将您的脚本添加到任何系统工具箱中,例如 分析数据管理 工具箱。然而,通过创建一个新的自定义工具箱,您可以这样添加脚本:

  1. 使用空地图文档文件打开 ArcMap 并打开 ArcToolbox 窗口。

  2. 在 ArcToolbox 的空白区域中右键单击,然后选择 添加工具箱

  3. 导航到 C:\ArcpyBook\Ch6 文件夹。

  4. 添加工具箱 对话框中,单击新建工具箱按钮。这将创建一个名为 Toolbox.tbx 的默认名称的新工具箱;您将在下一步中重命名工具箱:如何操作…

  5. 将工具箱命名为WildfireTools.tbx如何操作…

  6. 通过选择WildfireTools.tbx并点击打开按钮来打开工具箱。现在工具箱应该如以下截图所示显示在ArcToolbox中:如何操作…

  7. 每个工具箱都应该有一个名称和一个别名。别名将用于唯一地定义您的自定义工具。别名名称应保持简短,不应包含任何特殊字符。右键单击新工具箱并选择属性。添加一个别名为wildfire,如以下截图所示:如何操作…

    注意

    您可以选择在这个工具箱内部创建一个新的工具集,通过右键单击工具箱并导航到新建 | 工具集。工具集允许您按功能分组您的脚本。在这个例子中,这样做可能不是必要的,但如果您将来需要分组您的脚本,那么这就是您如何实现它的方法。

  8. 在下一步中,我们将修改一个名为InsertWildfires.py的现有 Python 脚本,使其能够接受用户通过 ArcToolbox 界面提供的动态输入。在 IDLE 中打开c:\ArcpyBook\Ch6\InsertWildfires.py

    注意,我们已经将工作空间的路径以及包含野火事件的逗号分隔文本文件的路径硬编码:

    arcpy.env.workspace = "C:/ArcpyBook/data/Wildfires/WildlandFires.mdb"
    f = open("C:/ArcpyBook/data/Wildfires/NorthAmericaWildfires_2007275.txt","r")
    
  9. 删除前面的两行代码。

    此外,我们还硬编码了输出要素类的名称:

    cur = arcpy.InsertCursor("FireIncidents")
    

    这种硬编码限制了脚本的有用性。如果数据集移动或被删除,脚本将无法运行。此外,脚本缺乏指定不同输入和输出数据集的灵活性。在下一步中,我们将移除这种硬编码,并替换为接受动态输入的能力。

  10. 我们将使用arcpy中的GetParameterAsText()函数来接受用户的动态输入。将以下代码行添加到 try 块中,使您的代码如下所示:

    try:
      #the output feature class name
      outputFC = arcpy.GetParameterAsText(0)
    
      # template featureclass that defines the attribute schema
      fClassTemplate = arcpy.GetParameterAsText(1)
    
      # open the file to read
      f = open(arcpy.GetParameterAsText(2),'r')
    
          arcpy.CreateFeatureclass_management (os.path.split(outputFC)[0], os.path.split(outputFC)[1], "point", fClassTemplate)
    

    注意我们调用了位于数据管理工具工具箱中的CreateFeatureClass工具,并将outputFC变量以及模板要素类(fClassTemplate)传递给它。此工具将创建一个包含用户定义的输出要素类的空要素类。

  11. 您还需要修改创建InsertCursor对象的代码行。按照以下方式更改该行:

    with arcpy.da.InsertCursor(outputFC) as cur:
    
  12. 整个脚本应如下所示:

    #Script to Import data to a feature class within a geodatabase
    import arcpy, os
    try:
        outputFC = arcpy.GetParameterAsText(0)
        fClassTemplate = arcpy.GetParameterAsText(1)
        f = open(arcpy.GetParameterAsText(2),'r')
        arcpy.CreateFeatureclass_management(os.path.split(outputFC)[0], os.path.split(outputFC)[1],"point",fClassTemplate)
        lstFires = f.readlines()
        with arcpy.da.InsertCursor(outputFC) as cur:
            cntr = 1
            for fire in lstFires:
                if 'Latitude' in fire:
                    continue
                vals = fire.split(",")
                latitude = float(vals[0])
                longitude = float(vals[1])
                confid = int(vals[2])
                pnt = arcpy.Point(longitude, latitude)
                feat = cur.newRow()
                feat.shape = pnt
                feat.setValue("CONFIDENCEVALUE", confid)
                cur.insertRow(feat)
                arcpy.AddMessage("Record number" + str(cntr) + "written to feature class")
                cntr = cntr + 1
    except:
        print arcpy.GetMessages()
    finally:
        f.close()
    
  13. 您可以通过检查c:\ArcpyBook\code\Ch6\InsertWildfires.py解决方案文件来检查您的工作。

  14. 在下一步中,我们将把刚刚创建的脚本添加到Wildfire Tools工具箱中作为一个脚本工具。

  15. 在 ArcToolbox 中,右键单击您之前创建的Wildfire Tools自定义工具箱,然后导航到添加 | 脚本。这将显示添加脚本对话框,如下截图所示。为您的脚本提供一个名称、标签和描述。名称字段不能包含任何空格或特殊字符。标签字段是显示在脚本旁边的名称。对于本例,给它一个标签为从文本加载野火。最后,添加一些描述性信息,详细说明脚本将执行的操作。

  16. 名称标签描述相关的详细信息如下截图所示:如何操作…

  17. 点击下一步以显示添加脚本的下一个输入对话框。

  18. 在此对话框中,您将指定要附加到工具的脚本。导航到c:\ArcpyBook\Ch6\InsertWildfires.py并将InsertWildfires.py作为脚本添加。

  19. 您还希望确保选中了在进程中运行 Python 脚本复选框,如下截图所示。在进程中运行 Python 脚本可以增加脚本的性能。如何操作…

    注意

    在进程外运行脚本需要 ArcGIS 创建一个单独的进程来执行脚本。启动此过程并执行脚本所需的时间会导致性能问题。始终在进程中运行您的脚本。在进程中运行脚本意味着 ArcGIS 不需要生成第二个进程来运行脚本。它将在与 ArcGIS 相同的进程空间中运行。

  20. 点击下一步以显示参数窗口,如下截图所示:如何操作…

    您在此对话框中输入的每个参数都对应于对GetParameterAsText()的单次调用。之前,您通过GetParameterAsText()方法修改了您的脚本以接受动态参数。参数应按脚本期望接收它们的顺序输入此对话框。例如,您在代码中插入以下行:

    outputFC = arcpy.GetParameterAsText(0)
    

    添加到对话框中的第一个参数需要与此行相对应。在我们的代码中,此参数代表此脚本创建的特征类。您可以通过点击显示名称下第一行的第一个可用行来添加参数。您可以在该行中输入任何文本。此文本将显示给用户。您还需要为参数选择一个对应的数据类型。在这种情况下,数据类型应设置为特征类,因为这是从用户那里收集的预期数据。每个参数还可以设置一些属性。一些更重要的属性包括类型方向默认值

  21. 将以下信息,如以下屏幕截图所示,输入到你的对话框中,用于输出要素类。确保将方向设置为Output如何操作…

  22. 接下来,我们需要添加一个参数,用于定义将用作我们新要素类属性模板的要素类。在对话框中输入以下信息:如何操作…

  23. 最后,我们需要添加一个参数,用于指定在创建我们的新要素类时用作输入的逗号分隔的文本文件。将以下信息输入到你的对话框中:如何操作…

  24. 点击完成。新的脚本工具将被添加到你的Wildfire Tools工具箱中,如下一个屏幕截图所示:如何操作…

  25. 现在,我们将测试这个工具以确保它正常工作。双击脚本工具以显示如下所示的对话框:如何操作…

  26. 定义一个新的输出要素类,它应该加载到现有的WildlandFires.mdb个人地理数据库中,如下一个屏幕截图所示。点击打开文件夹图标,导航到WildlandFires.mdb个人地理数据库,它应该位于c:\ArcpyBook\data\Wildfires

  27. 你还需要给你的新要素类起一个名字。在这个例子中,我们将要素类命名为TodaysWildfires,但名字可以是任何你想要的。在下面的屏幕截图中,你可以看到一个如何操作的例子。点击保存按钮:如何操作…

  28. 对于属性模板,你需要指向已经为你创建的FireIncidents要素类。这个要素类包含一个名为CONFIDENCEVAL的字段。这个字段将在我们的新要素类中创建。点击浏览按钮,导航到c:\ArcpyBook\data\Wildfires\WildlandFires.mdb,你应该能看到FireIncidents要素类。选择它并点击添加

  29. 最后,最后一个参数需要指向包含野火信息的逗号分隔的文本文件。此文件位于c:\ArcpyBook\data\Wildfires\NorthAmericaWildfires_2007275.txt。点击浏览按钮,导航到c:\ArcpyBook\data\Wildfires。点击NorthAmericaWildfires_2007275.txt,然后点击添加按钮。你的工具应该如下所示:如何操作…

  30. 点击确定以执行工具。任何消息都将写入如下所示的对话框。这是任何地理处理工具的标准对话框。如何操作…

  31. 如果一切设置正确,你应该会看到下面的屏幕截图,显示一个新的要素类将被添加到 ArcMap 显示中:如何操作…

  32. 在 ArcMap 中,选择添加底图,然后选择地形底图。点击添加按钮以添加底图图层。如何操作…

这将为您刚刚导入的数据提供参考,如前一个截图所示。

它是如何工作的…

几乎所有的脚本工具都有参数,这些值是为工具对话框设置的。当工具执行时,参数值会发送到您的脚本。您的脚本读取这些值,然后继续其工作。Python 脚本可以接受参数作为输入。参数,也称为参数,使您的脚本变得动态。到目前为止,我们所有的脚本都使用了硬编码的值。通过为脚本指定输入参数,您可以在运行时提供要素类的名称。这种能力使您的脚本更加灵活。

GetParameterAsText() 方法用于捕获参数输入,它是基于零的,第一个输入的参数占据 0 索引,每个后续参数增加 1。通过读取逗号分隔的文本文件创建的输出要素类由 outputFC 变量指定,该变量通过 GetParameterAsText(0) 获取。使用 GetParameterAsText(1),我们捕获一个将作为输出要素类属性模式的模板的要素类。模板要素类中的属性字段用于定义将填充我们的输出要素类的字段。最后,GetParameterAsText(2) 用于创建一个名为 f 的变量,该变量将保存要读取的逗号分隔的文本文件。

还有更多...

arcpy.GetParameterAsText() 方法并不是捕获传递到您的脚本中的信息的唯一方式。当您从命令行调用 Python 脚本时,您可以传递一组参数。当向脚本传递参数时,每个单词必须由一个空格分隔。这些单词存储在一个名为 sys.argv 的零基于列表对象中。使用 sys.argv,列表中的第一个项目,通过 0 索引引用,存储脚本的名称。每个后续的单词通过下一个整数引用。因此,第一个参数将存储在 sys.argv[1] 中,第二个在 sys.argv[2] 中,依此类推。然后可以从脚本内部访问这些参数。

建议您使用 GetParameterAsText() 函数而不是 sys.argv,因为 GetParameterAsText() 没有字符限制,而 sys.argv 每个参数有 1,024 个字符的限制。在任何情况下,一旦参数被读入脚本,您的脚本就可以使用输入值继续执行。

创建 Python 工具箱

在 ArcGIS 中创建工具箱有两种方式:在自定义工具箱中的脚本工具,这是我们上一道菜谱中提到的,以及在 Python 工具箱中的脚本工具。Python 工具箱是在 ArcGIS 10.1 版本中引入的,它将所有内容封装在一个地方:参数、验证代码和源代码。这与使用向导和单独处理业务逻辑的脚本创建的自定义工具箱不同。

准备工作

Python 工具箱类似于 ArcToolbox 中的任何其他工具箱,但它完全由 Python 创建,并具有 .pyt 文件扩展名。它通过名为 Toolbox 的类以编程方式创建。在本菜谱中,您将学习如何创建 Python 工具箱 并添加自定义工具。在完成 ToolboxTool 的基本结构后,您将通过添加连接到 ArcGIS Server 地图服务、下载实时数据并将其插入要素类的代码来完成工具的功能。

如何操作…

完成以下步骤以创建 Python 工具箱 并创建一个连接到 ArcGIS Server 地图服务、下载实时数据并将其插入要素类的自定义工具:

  1. 打开ArcCatalog。您可以通过在文件夹上右键单击并选择新建 | Python 工具箱来在文件夹中创建一个 Python 工具箱。在 ArcCatalog 中,有一个名为 Toolboxes 的文件夹,其中包含一个 My Toolboxes 文件夹,如图所示:如何操作…

  2. 右键单击此文件夹并选择 新建 | Python 工具箱

  3. 工具箱的名称由文件名控制。将工具箱命名为 InsertWildfires.pyt如何操作…

  4. Python 工具箱文件(.pyt)可以在任何文本或代码编辑器中编辑。默认情况下,代码将在 记事本 中打开。您可以通过转到 地理处理 | 地理处理选项 并进入 编辑器 部分来设置脚本的默认编辑器。您会注意到在下图中,我已经将我的编辑器设置为 PyScripter,这是我首选的环境。您可能希望将其更改为 IDLE 或您目前正在使用的任何开发环境。请注意,此步骤不是必需的。如前所述,默认情况下,它将在记事本中打开您的代码。如何操作…

  5. 右键单击 InsertWildfires.pyt 并选择 编辑。这将打开您的开发环境。您的开发环境将取决于您定义的编辑器。

  6. 记住,你不会更改类的名称,该名称是Toolbox。然而,你将重命名Tool类以反映你想要创建的工具的名称。每个工具都将有各种方法,包括__init__(),这是工具的构造函数,以及getParameterInfo()isLicensed()updateParameters()updateMessages()execute()。你可以使用__init__()方法设置初始化属性,例如工具的标签和描述。查找Tool类并将其名称更改为USGSDownload。还要设置标签和描述,如下面的代码所示:

    class USGSDownload(object):
        def __init__(self):
            """Define the tool (tool name is the name of the class)."""
            self.label = "USGS Download"
            self.description = "Download from USGS ArcGIS Server instance"
    
  7. 你可以通过复制和粘贴类及其方法,将Tool类用作其他你想要添加到工具箱中的工具的模板。我们在这个特定的练习中不会这样做,但我希望你知道这个事实。你需要将每个工具添加到Toolboxtools属性中。添加USGS Download工具,如下面的代码所示:

    class Toolbox(object):
        def __init__(self):
            """Define the toolbox (the name of the toolbox is the name of the
            .pyt file)."""
            self.label = "Toolbox"
            self.alias = ""
            # List of tool classes associated with this toolbox
            self.tools = [USGSDownload]
    
  8. 当你关闭代码编辑器时,你的工具箱应该会自动刷新。你也可以通过右键单击工具箱并选择刷新来手动刷新工具箱。如果你的代码中发生语法错误,工具箱图标将改变,如下面的截图所示。注意工具箱旁边的红色X如何操作…

  9. 在这个时候,你不应该有任何错误,但如果有的话,右键单击工具箱并选择检查语法以显示错误,如下面的截图所示。注意,如果你有错误,它可能与以下示例不同:如何操作…

  10. 假设你没有语法错误,你应该看到以下工具箱/工具结构:如何操作…

  11. 几乎所有工具都有参数,你可以在工具对话框或脚本中设置它们的值。当工具执行时,参数值将发送到你的工具源代码。你的工具读取这些值并继续其工作。你使用getParameterInfo()方法来定义你的工具的参数。作为这个过程的一部分,创建单个Parameter对象。在getParameterInfo()方法中添加以下参数,然后我们将讨论它们:如何操作…

    每个Parameter对象都是使用arcpy.Parameter创建的,并传递了定义对象的一组参数。

    对于第一个Parameter对象(param0),我们将捕获一个包含当前野火数据的 ArcGIS Server 地图服务的 URL。我们给它一个显示名称(ArcGIS Server Wildfire URL),它将在工具的对话框中显示,一个参数名称,数据类型,参数类型(这是必需的),以及方向。

    在第一个参数(param0)的情况下,我们还分配了一个初始值,即包含野火数据的现有地图服务的 URL。

    对于第二个参数,我们定义了一个输出要素类,用于将从中读取的野火数据写入。一个空的要素类已为您创建以存储数据。最后,我们将这两个参数添加到一个名为params的 Python 列表中,并将列表返回给调用函数

  12. 工具的主要工作是在execute()方法中完成的。这是您的工具地理处理发生的地方。在以下代码中看到的execute()方法可以接受多个参数,包括工具(self)、参数和消息:

      def execute(self, parameters, messages):
            """The source code of the tool. """
            return
    
  13. 要访问传递给工具的参数值,您可以使用valueAsText()方法。将以下代码添加到您的工具中,以访问将要传递给您的工具的参数值。记住,正如之前提到的步骤中所示,第一个参数将包含一个包含野火数据的地图服务的 URL,第二个参数是数据将被写入的输出要素类:

    def execute(self, parameters, messages):
            inFeatures = parameters[0].valueAsText
            outFeatureClass = parameters[1].valueAsText
    
  14. 到目前为止,您已经创建了一个 Python 工具箱,添加了一个工具,定义了工具的参数,并创建了将保存最终用户定义的参数值的变量。最终,此工具将使用传递给工具的 URL 连接到 ArcGIS 服务器地图服务,下载当前的野火数据,并将野火数据写入要素类。我们将在下一步这样做。

  15. 注意,为了完成本练习的剩余部分,您需要使用pip安装 Python 的requests模块(请参阅docs.python-requests.org/en/latest/)。在继续下一步之前,现在就做这件事。piprequests的安装说明可以在提供的链接中找到。

  16. 接下来,添加连接到野火地图服务以执行查询的代码。在此步骤中,您还将定义传递给地图服务查询的QueryString参数。首先,我们将通过添加以下代码来导入requestsjson模块:

    import requests
    import json
    
  17. 然后,创建一个将保存QueryString参数的 payload 变量。请注意,在这种情况下,我们定义了一个where子句,以便只返回大于5英亩的火灾。inFeatures变量包含 URL:

    def execute(self, parameters, messages):
            inFeatures = parameters[0].valueAsText
            outFeatureClass = parameters[1].valueAsText
    
            agisurl = inFeatures
    
            payload = { 'where': 'acres > 5','f': 'pjson', 'outFields': 'latitude,longitude,fire_name,acres'}
    
  18. 将请求提交给 ArcGIS 服务器实例,并将响应存储在名为r的变量中。向对话框打印一条消息,指示响应:

    def execute(self, parameters, messages):
            inFeatures = parameters[0].valueAsText
            outFeatureClass = parameters[1].valueAsText
    
            agisurl = inFeatures
    
            payload = { 'where': 'acres > 5','f': 'pjson', 'outFields': 'latitude,longitude,fire_name,acres'}
    
            r = requests.get(inFeatures, params=payload)
    
  19. 让我们测试一下代码,以确保我们走在正确的道路上。保存文件并在 ArcCatalog 中刷新您的工具箱。执行工具并保留默认 URL。如果一切按预期工作,您应该会看到一个进度对话框的 JSON 对象输出。您的输出可能会有所不同。如何操作…

  20. 返回到execute()方法,并将 JSON 对象转换为 Python 字典:

        def execute(self, parameters, messages):
            inFeatures = parameters[0].valueAsText
            outFeatureClass = parameters[1].valueAsText
    
            agisurl = inFeatures
    
            payload = { 'where': 'acres > 5','f': 'pjson', 'outFields': 'latitude,longitude,fire_name,acres'}
    
            r = requests.get(inFeatures, params=payload)
    
            decoded = json.loads(r.text)
    
  21. 通过传递工具对话框中定义的输出要素类以及将要填充的字段来创建一个 InsertCursor。然后我们开始一个 for 循环,循环遍历从 ArcGIS 服务器地图服务请求返回的每个要素(野火)。decoded 变量是一个 Python 字典。在 for 循环内部,我们从 attributes 字典中检索火灾名称、纬度、经度和面积。最后,我们调用 insertRow() 方法将新的行插入到要素类中,并将火灾名称和面积作为属性。进度信息被写入到 进度对话框,并更新计数器。execute() 方法现在应如下所示:如何操作…

  22. 保存文件并在需要时刷新您的 Python 工具箱

  23. 您可以通过检查 c:\ArcpyBook\code\Ch6\InsertWildfires_PythonToolbox.py 解决方案文件来验证您的操作。

  24. 双击USGS 下载工具。

  25. 保持默认的 URL 并选择位于 c:\ArcpyBook\data 中的 WildlandFires 地理数据库中的 RealTimeFires 要素类。RealTimeFires 要素类为空,并包含 NAMEACRES 字段。

  26. 点击确定以执行工具。写入要素类的要素数量将根据当前的野火活动情况而变化。大多数时候,至少会有一点活动,但不太可能(尽管有可能)在美国没有任何野火:如何操作…

  27. ArcMap 中查看要素类以查看其要素。您可能想添加一个 basemap 图层以提供参考,如图中所示:如何操作…

它是如何工作的…

新风格的 ArcGIS Python 工具箱提供了一种以 Python 为中心的创建自定义脚本工具的方法。在 ArcGIS for Desktop 中创建自定义脚本工具的旧方法结合了 Python 和基于向导的方法来定义工具的各个方面。新方法为创建工具提供了一种更直接的方法。您创建的所有工具都包含在一个名为 Toolbox 的类中,该类不应重命名。默认情况下,Toolbox 内将创建一个单独的 Tool 类。这个 Tool 类应该重命名。在本食谱中,我们将其重命名为 USGSDownload。在 USGSDownload 类内部,存在 getParameterInfo()execute() 方法等。使用 getParameterInfo() 方法,可以定义 Parameter 对象来保存输入数据。在这个工具中,我们定义了一个 Parameter 来捕获包含实时野火数据的 ArcGIS 服务器地图服务的 URL,以及一个用于引用本地要素类的第二个 Parameter 对象来保存数据。最后,当用户在工具中点击 OK 按钮时,将触发 execute() 方法。参数信息以 parameters 变量的形式作为参数发送给 execute() 方法。在这个方法内部,使用 Python 的 requests 模块提交一个请求以从远程 ArcGIS 服务器实例获取野火数据。响应以 json 对象的形式返回,并将其转换为存储在名为 decoded 的变量中的 Python 字典。从解码变量中提取火灾名称、纬度、经度和英亩数,并使用来自 arcpy.da 模块的 InsertCursor 对象将其写入本地要素类。我们将在本书的后续章节中详细介绍 arcpy.da 模块。

第七章. 查询和选择数据

本章将涵盖以下菜谱:

  • 构建正确的属性查询语法

  • 创建要素图层和表视图

  • 使用“按属性选择图层”工具选择要素和行

  • 使用“按位置选择”工具选择要素

  • 使用“按位置选择”工具结合空间和属性查询

简介

从地理图层选择要素或从独立属性表中选择行是 GIS 操作中最常见的操作之一。查询被创建以启用这些选择,可以是属性查询或空间查询。属性查询使用 SQL 语句通过使用数据集中的一个或多个字段或列来选择要素或行。一个属性查询的例子是“选择所有价值超过 50 万美元的土地地块”。空间查询用于根据某种空间关系选择要素。一个例子可能是“选择所有与学区相交的土地地块”或“选择所有完全位于德克萨斯州特拉维斯县的道路”。也可以将属性查询和空间查询结合起来。一个例子可能是“选择所有与 100 年洪水平原相交且价值超过 50 万美元的土地地块”。

构建正确的属性查询语法

构建属性查询对于您成功创建查询要素类和表的地理处理脚本至关重要。您对要素类和表执行的任何属性查询都需要正确的 SQL 语法,并且根据您执行的查询的数据类型,还需要遵循各种规则。

准备工作

创建属性查询的语法是您在创建包含按属性选择工具使用的 Python 脚本时需要掌握的最困难且耗时最长的任务之一。这些查询基本上是 SQL 语句,以及一些您需要掌握的特殊性。如果您已经很好地理解了在 ArcMap 中创建查询或可能在其他编程语言中创建 SQL 语句方面有经验,那么这将对您来说容易一些。除了创建有效的 SQL 语句外,您还需要了解一些特定的 Python 语法要求以及一些数据类型差异,这会导致某些数据类型的语句格式略有改变。在本菜谱中,您将学习如何构建有效的查询语法,并了解不同数据类型如何改变语法以及一些 Python 特定的结构。

如何操作…

首先,我们将看看如何在 ArcMap 中构建查询,这样您可以了解它们的结构。

  1. 在 ArcMap 中,打开C:\ArcpyBook\Ch7\Crime_Ch7.mxd

  2. 右键单击 2009 年的 Burglaries 层,并选择 Open Attribute Table。你应该会看到一个类似于以下截图的属性表。我们将查询 SVCAREA 字段:如何做…

  3. 在打开属性表后,选择 Table Options 按钮,然后选择 Select by Attributes 以显示一个对话框,该对话框允许你构建属性查询。

    注意查询对话框(如下截图所示)中的 Select * FROM Burglary WHERE: 语句。这是一个基本的 SQL 语句,它将返回所有满足通过查询构建器定义的条件的 Burglary 属性表中的列。星号(****)简单地表示将返回所有字段:

    如何做…

  4. 确保在 Method 下拉列表中选中的是 Create a new selection。这将创建一个新的选择集。

  5. 从字段列表中双击 SVCAREA 以将其添加到 SQL 语句构建器中,如下所示:如何做…

  6. 点击 = 按钮。

  7. 点击 Get Unique Values 按钮。

  8. 从生成的值列表中双击 'North' 以完成 SQL 语句,如下面的截图所示:如何做…

  9. 点击 Apply 按钮以执行查询。这应该选择 7520 条记录。

    许多人错误地认为可以将以这种方式生成的查询直接粘贴到 Python 脚本中。事实并非如此。这里有一些重要的区别,我们将在下一部分进行介绍。

  10. 关闭 Select by Attributes 窗口和 2009 年的 Burglaries 表。

  11. 通过导航到 Selection | Clear Selected Features 来清除选定的要素集。

  12. 打开 Python 窗口并添加导入 arcpy 的代码:

    import arcpy
    
  13. 创建一个新的变量来保存查询,并添加你之前创建的相同语句:

    qry = "SVCAREA" = 'North'
    
  14. 在键盘上按 Enter 键,你应该会看到一个类似于以下错误消息:

    Runtime error SyntaxError: can't assign to literal (<string>, line 1)
    
    

    Python 将 SVCAREANorth 解释为字符串,但两个字符串之间的等号不是用于设置 qry 变量的字符串的一部分。我们需要做一些事情来生成一个对 Python 解释器语法正确的语句。

    虽然已经处理了一个重要的事情。在查询中使用的每个字段名都需要用双引号括起来。在这种情况下,SVCAREA 是查询中使用的唯一字段,并且已经用双引号括起来。当你与 shapefile、文件地理数据库或 ArcSDE 地理数据库一起工作时,这总是成立的。然而,这里有一点会让人有些困惑。如果你正在处理来自个人地理数据库的数据,字段名需要用方括号而不是双引号括起来,如下面的代码示例所示。这当然会给脚本开发者带来困惑:

    qry = [SVCAREA] = 'North'
    

    现在,我们需要处理围绕'North'的单引号。当从具有text数据类型的字段查询数据时,被评估的字符串必须用引号括起来。如果你检查原始查询,你会注意到我们实际上已经用引号括起了North,所以一切应该都正常,对吧?不幸的是,在 Python 中并不那么简单。引号以及许多其他字符必须用反斜杠后跟被转义的字符来转义。在这种情况下,转义序列将是\',如下面的步骤所示:

  15. 修改你的查询语法以包含转义序列:

    qry = "SVCAREA" = \'North\'
    
  16. 最后,整个查询语句应该用引号括起来:

    qry = '"SVCAREA" = \'North\''
    

除了等于号(=)用于测试相等之外,还有许多其他运算符可以与字符串和数值数据一起使用,包括不等于(< >)、大于(>)、大于等于(>=)、小于(<)和小于等于(<=)。

通配符字符,包括%_,也可以用于 shapefiles、文件地理数据库和 ArcSDE 地理数据库。这包括表示任意数量字符的%LIKE运算符通常与通配符字符一起使用,以执行部分字符串匹配。例如,以下查询将找到所有服务区域以N开头并且后面跟有任意数量字符的记录:

qry = '"SVCAREA" LIKE \'N%\''

下划线字符(_)可以用来表示单个字符。对于个人地理数据库,星号(*)用于表示任意数量字符的通配符,而问号(?)表示单个字符。

你还可以查询数据不存在的情况,也称为NULL值。NULL值通常被误认为是零的值,但这并不总是正确的。NULL值表示数据不存在,这与零的值不同。空值运算符包括IS NULLIS NOT NULL。以下代码示例将找到所有SVCAREA字段不包含数据的记录:

qry = '"SVCAREA" IS NULL'

本节我们将讨论的最后一个主题是用于组合表达式的运算符,当需要满足多个查询条件时。AND运算符要求两个查询条件都满足,查询结果才为真,从而选择记录。OR运算符要求至少满足一个条件。

它是如何工作的...

创建语法正确的查询是使用 Python 进行 ArcGIS 编程最具挑战性的方面之一。然而,一旦你理解了一些基本规则,它就会变得容易一些。在本节中,我们将总结这些规则。需要记住的一个重要事项是,对于所有数据集,字段名必须用双引号括起来,个人地理数据库除外,它要求字段名周围用大括号括起来。

此外,还有一个 AddFieldDelimiters() 函数,您可以使用它根据函数参数提供的数据源向字段添加正确的分隔符。此函数的语法如下:

AddFieldDelimiters(dataSource,field)

此外,大多数人,尤其是那些刚开始用 Python 编程的人,都会遇到在查询中添加字符串值单引号的问题。在 Python 中,引号必须用单个反斜杠 \ 后跟引号来转义。使用此转义序列将确保 Python 确实将其视为引号,而不是字符串的结尾。

最后,花一些时间熟悉通配符字符。对于除个人地理数据库之外的数据集,您将使用 % 字符来匹配多个字符,并使用下划线字符 _ 来匹配单个字符。如果您使用的是个人地理数据库,则使用 * 字符来匹配多个字符,并使用 ? 字符来匹配单个字符。显然,个人地理数据库与其他所有类型数据集之间的语法差异可能会导致一些混淆。

创建要素层和表格视图

要素层和表格视图作为特定用于工具(如按位置选择按属性选择)的中间数据集,存储在内存中。尽管这些临时数据集可以保存,但在大多数情况下并不需要。

准备工作

要素类是地理数据的物理表示,以文件(形状文件、个人地理数据库和文件地理数据库)或地理数据库中的形式存储。环境系统研究协会Esri)将要素类定义为“共享相同几何形状(点、线或多边形)、属性表和空间参考的一组要素”。

要素类可以包含默认字段和用户定义字段。默认字段包括 SHAPEOBJECTID 字段。这些字段由 ArcGIS 自动维护和更新。SHAPE 字段包含地理要素的几何表示,而 OBJECTID 字段包含每个要素的唯一标识符。根据要素类的类型,还将存在其他默认字段。线要素类将有一个 SHAPE_LENGTH 字段。多边形要素类将同时具有 SHAPE_LENGTHSHAPE_AREA 字段。

可选字段是由 ArcGIS 的最终用户创建的,并且不会被 GIS 自动更新。这些字段包含有关要素的属性信息。这些字段也可以通过您的脚本进行更新。

表以独立的 DBF(也称为 dBase 文件格式)表或地理数据库中的形式进行物理表示。表和要素类都包含属性信息。然而,表只包含属性信息。与表关联的没有 SHAPE 字段,并且它们可能包含或不包含 OBJECTID 字段。

使用 按属性选择按位置选择 工具的独立 Python 脚本需要您创建一个中间数据集,而不是使用要素类或表。这些中间数据集是临时的,被称为 要素层表视图。与要素类和表不同,这些临时数据集不表示磁盘或地理数据库中的实际文件。相反,它们是要素类和表的内存表示。这些数据集仅在 Python 脚本运行时是活动的。在工具执行后,它们将从内存中删除。然而,如果脚本在 ArcGIS 中作为脚本工具运行,则可以通过在内容表中右键单击图层并选择 另存为图层文件 或简单地保存地图文档文件来保存临时图层。

在您可以使用 按属性选择按位置选择 工具之前,必须在您的 Python 脚本中单独创建要素层和表视图。创建要素层 工具生成要素类的内存表示,然后可以用来创建查询和选择集以及连接表。完成此步骤后,您可以使用 按属性选择按位置选择 工具。同样,创建表视图 工具用于创建表的内存表示。此工具的功能与 创建要素层 相同。创建要素层创建表视图 工具都需要一个输入数据集、一个输出层名称以及可选的查询表达式,该表达式可以用来限制输出层中的要素或行。此外,这两个工具都可以在 数据管理工具 工具箱中找到。

使用 创建要素层 工具的语法如下:

arcpy.MakeFeatureLayer_management(<input feature layer>, <output layer name>,{where clause})

使用 创建表视图 工具的语法如下:

Arcpy.MakeTableView_management(<input table>, <output table name>, {where clause})

在本菜谱中,您将学习如何使用 创建要素层创建表视图 工具。这些任务将在 ArcGIS 内完成,这样您可以看到创建的层的内存副本。

如何操作…

按照以下步骤学习如何使用 创建要素层创建表视图 工具:

  1. 在 ArcMap 中打开 c:\ArcpyBook\Ch7\Crime_Ch7.mxd

  2. 打开 Python 窗口。

  3. 导入 arcpy 模块:

    import arcpy
    
  4. 设置工作空间:

    arcpy.env.workspace = "c:/ArcpyBook/data/CityOfSanAntonio.gdb"
    
  5. 开始一个 try 块:

    try:
    
  6. 使用 创建要素层 工具创建 Burglary 要素类的内存副本。确保缩进此行代码:

    flayer = arcpy.MakeFeatureLayer_management("Burglary","Burglary_Layer")
    
  7. 添加一个 except 块和一行代码,以便在出现问题时打印错误消息:

    except Exception as e:
      print(e.message)
    
  8. 整个脚本应如下所示:

    import arcpy
    arcpy.env.workspace = "c:/ArcpyBook/data/CityOfSanAntonio.gdb"
    try:
      flayer = arcpy.MakeFeatureLayer_management("Burglary","Burglary_Layer")
    except Exception as e:
      print(e.message)
    
  9. 将脚本保存到 C:\ArcpyBook\Ch7\CreateFeatureLayer.py

  10. 您可以通过检查 c:\ArcpyBook\code\Ch7\CreateFeatureLayer.py 解决方案文件来检查您的作品。

  11. 运行脚本。新的 Burglary_Layer 文件将被添加到 ArcMap 的内容表中:如何操作…

  12. Make Table View工具的功能与Make Feature Layer工具等效。区别在于它针对独立表而不是特征类。

  13. 删除以下代码行:

    flayer = arcpy.MakeFeatureLayer_management("Burglary","Burglary_Layer")
    
  14. 在其位置添加以下代码行:

    tView = arcpy.MakeTableView_management("Crime2009Table","Crime2009TView")
    
  15. 您可以通过检查c:\ArcpyBook\code\Ch7\CreateTableView.py解决方案文件来检查您的作品。

  16. 运行脚本以查看添加到 ArcMap 内容表的表视图。

它是如何工作的...

Make Feature Layer 和 Make Table View 工具分别创建特征类和表的内存表示。Select by Attributes 和 Select by Location 工具在从 Python 脚本调用时,都需要将这些临时内存结构作为参数传递。这两个工具还要求您传递临时结构的名称。

更多内容...

您还可以将查询应用于 Make Feature Layer 或 Make Table View 工具,以限制特征层或表视图中返回的记录。这是通过在脚本中调用这些工具时添加where子句来完成的。此查询类似于您通过导航到图层属性 | 定义查询在图层上设置定义查询的情况。

添加查询的语法如下:

MakeFeatureLayer(in_features, out_layer, where_clause)
MakeTableView(in_table, out_view, where_clause)

使用 Select Layer by Attribute 工具选择特征和行

属性查询可以通过使用 Select Layer by Attribute 工具对特征类或表执行。可以包含where子句以过滤选定的记录,并包含各种选择类型。

准备工作

如下截图所示的Select Layer by Attribute工具用于根据您定义的查询从特征类或表中选择记录。我们在本章前面的配方中介绍了查询的相对复杂主题,因此希望您现在理解了创建查询的基本概念。您还学习了如何创建特征类或表的临时内存表示,这是使用Select by AttributesSelect by Location工具的先决条件。

准备工作

Select by Attributes工具使用查询以及特征层或表视图和选择方法来选择记录。默认情况下,选择方法将是一个新的选择集。其他选择方法包括“添加到选择”、“从选择中删除”、“子集选择”、“切换选择”和“清除选择”。每种选择方法如下总结:

  • NEW_SELECTION:这是默认的选择方法,它创建一个新的选择集

  • ADD_TO_SELECTION:此操作基于查询将选择集添加到当前选定的记录中

  • REMOVE_FROM_SELECTION:此操作基于查询从选择集中删除记录

  • SUBSET_SELECTION:此操作将选定的记录与现有选择集合并

  • SWITCH_SELECTION:这将选择当前未选中的记录,并取消选中现有的选择集

  • CLEAR_SELECTION:这将清除当前选中集中的所有记录

调用按属性选择工具的语法如下:

arcpy.SelectLayerByAttribute_management(<input feature layer or table view>, {selection method}, {where clause})

在本例中,你将学习如何使用按属性选择工具从要素类中选择要素。你将使用在先前的菜谱中学到的技能来构建查询、创建要素层,并最终调用按属性选择工具。

如何做到这一点…

按照以下步骤学习如何使用按要素层属性选择工具从表或要素类中选择记录:

  1. 打开 IDLE 并创建一个新的脚本窗口。

  2. 将脚本保存到c:\ArcpyBook\Ch7\SelectLayerAttribute.py

  3. 导入arcpy模块:

    import arcpy
    
  4. 将工作空间设置为圣安东尼奥市地理数据库。

    arcpy.env.workspace = "c:/ArcpyBook/data/CityOfSanAntonio.gdb"
    
  5. 开始一个try块:

    try:
    
  6. 创建本章第一个菜谱中使用的查询。这将成为一个where子句,将选择所有服务区域为North的记录。这一行代码和接下来的四行应该有缩进:

    qry = '"SVCAREA" = \'North\''
    
  7. 创建Burglary要素类的内存副本:

    flayer = arcpy.MakeFeatureLayer_management("Burglary","Burglary_Layer")
    
  8. 通过传递我们刚刚创建的要素层的引用来调用按要素层属性选择工具。将其定义为新的选择集,并传递查询的引用:

    arcpy.SelectLayerByAttribute_management(flayer, "NEW_SELECTION", qry)
    
  9. 使用获取计数工具在图层中打印所选记录的数量:

    cnt = arcpy.GetCount_management(flayer)
    print("The number of selected records is: " + str(cnt))
    
  10. 添加一个except块和一行代码,以便在出现问题时打印错误消息:

    except Exception as e:
      print(e.message)
    
  11. 整个脚本应如以下代码片段所示。请记住,包括tryexcept块的缩进:

    import arcpy
    arcpy.env.workspace = "c:/ArcpyBook/data/CityOfSanAntonio.gdb"
    try:
      qry = '"SVCAREA" = \'North\''
      flayer =   arcpy.MakeFeatureLayer_management("Burglary","Burglary_Layer")
      arcpy.SelectLayerByAttribute_management(flayer, "NEW_SELECTION", qry)
      cnt = arcpy.GetCount_management(flayer)
      print("The number of selected records is: " + str(cnt))
    except Exception as e:
      print(e.message)
    
  12. 保存脚本。

  13. 你可以通过检查c:\ArcpyBook\code\Ch7\SelectLayerAttribute.py解决方案文件来检查你的工作。

  14. 运行脚本。如果一切正确,你应该会看到一个消息,表明已选择7520条记录:

    The total number of selected records is: 7520
    
    

它是如何工作的…

按属性选择工具要求第一个参数传递一个要素层或表视图。在本例中,我们传递了一个由上一行中的创建要素层工具创建的要素层。我们使用创建要素层工具从Burglary要素类创建要素层。这个要素层被分配给flayer变量,然后作为第一个参数传递给按属性选择工具。在此脚本中,我们还传递了一个参数,表示我们希望创建一个新的选择集,以及final参数,它是一个where子句。where子句在qry变量中指定。此变量包含一个查询,将选择所有服务区域为North的要素。

使用按位置选择工具选择要素

如下截图所示的 Select Layer by Location 工具可以用于根据某种空间关系选择要素。由于它处理空间关系,此工具仅适用于要素类及其对应的内存要素层。

准备中

在使用 Select by Location 工具选择要素时,你可以应用许多不同类型的空间关系,包括相交、包含、在范围内、边界接触、完全相同以及许多其他关系。如果没有指定,将应用默认的相交空间关系。输入要素层是唯一必需的参数,但还有许多可选参数,包括空间关系、搜索距离、要测试输入层的要素层或要素类,以及选择类型。在本教程中,你将学习如何在 Python 脚本中使用 Select by Location 工具根据空间关系选择要素。你将使用此工具选择位于 Edgewood 学区边界内的盗窃事件。

准备中

如何操作…

按照以下步骤学习如何使用 Select by Location 工具执行空间查询:

  1. 打开 IDLE 并创建一个新的脚本窗口。

  2. 将脚本保存到 c:\ArcpyBook\Ch7\SelectByLocation.py

  3. 导入 arcpy 模块:

    import arcpy
    
  4. 将工作空间设置为圣安东尼奥市地理数据库:

    arcpy.env.workspace = "c:/ArcpyBook/data/CityOfSanAntonio.gdb"
    
  5. 开始一个 try 块:

    try:
    
  6. 创建 Burglary 要素类的内存副本:

    flayer = arcpy.MakeFeatureLayer_management("Burglary","Burglary_Layer")
    
  7. 调用 Select Layer by Location 工具,传入我们刚刚创建的要素层的引用。空间关系测试将是 COMPLETELY_WITHIN,这意味着我们想要找到完全位于比较层边界内的所有盗窃事件。将 EdgewoodSD.shp 定义为比较层:

    arcpy.SelectLayerByLocation_management (flayer, "COMPLETELY_WITHIN", "c:/ArcpyBook/Ch7/EdgewoodSD.shp")
    
  8. 使用 Get Count 工具在图层中打印所选记录的数量:

    cnt = arcpy.GetCount_management(flayer)
    print("The number of selected records is: " + str(cnt))
    
  9. 添加一个 except 块和一行代码,以便在出现问题时打印错误消息:

    except Exception as e:
      print e.message
    
  10. 整个脚本应如以下代码片段所示。请记住,包括 tryexcept 块的缩进:

    import arcpy
    arcpy.env.workspace = "c:/ArcpyBook/data/CityOfSanAntonio.gdb"
    try:
      flayer =   arcpy.MakeFeatureLayer_management("Burglary","Burglary_Layer")
      arcpy.SelectLayerByLocation_management (flayer, "COMPLETELY_WITHIN", "c:/ArcpyBook/Ch7/EdgewoodSD.shp")
      cnt = arcpy.GetCount_management(flayer)
      print("The number of selected records is: " + str(cnt))
    except Exception as e:
      print("An error occurred during selection")
    
  11. 保存脚本。

  12. 你可以通过检查 c:\ArcpyBook\code\Ch7\SelectByLocation_Step1.py 解决方案文件来验证你的工作。

  13. 运行脚本。如果一切操作正确,你应该会看到一个消息指示已选择 1470 条记录:

    The total number of selected records is: 1470
    
    

    在这种情况下,我们没有定义可选的搜索距离和选择类型参数。默认情况下,将应用新的选择作为选择类型。我们没有应用距离参数,但现在我们将这样做以说明其工作原理。

  14. 更新调用 Select Layer by Location 工具的代码行:

    arcpy.SelectLayerByLocation_management (flayer, "WITHIN_A_DISTANCE", "c:/ArcpyBook/Ch7/EdgewoodSD.shp","1 MILES")
    
  15. 保存脚本。

  16. 你可以通过检查 c:\ArcpyBook\code\Ch7\SelectByLocation_Step2.py 解决方案文件来验证你的工作。

  17. 运行脚本。如果一切操作正确,你应该会看到一个消息指示已选择2976条记录。这将选择 Edgewood 学区边界内的所有盗窃案以及边界内一英里范围内的任何盗窃案:

    The total number of selected records is: 2976
    

    在本节中,你将使用复制要素工具将临时图层写入新的要素类。

  18. 注释掉获取要素数量并打印到屏幕上的两行代码:

    ## cnt = arcpy.GetCount_management(flayer)
    ## print("The number of selected records is: " + str(cnt))
    
  19. 添加一行代码来调用复制要素工具。这一行代码应放置在调用按位置选择图层工具的代码行下方。复制要素工具接受一个要素图层作为第一个输入参数和一个输出要素类,在这种情况下将是一个名为EdgewoodBurglaries.shp的 shapefile:

    arcpy.CopyFeatures_management(flayer, 'c:/ArcpyBook/Ch7/EdgewoodBurglaries.shp') 
    
  20. 现在脚本应该看起来像以下代码片段所示。请记住,包括tryexcept块之间的缩进:

    import arcpy
    arcpy.env.workspace = "c:/ArcpyBook/data/CityOfSanAntonio.gdb"
    try:
      flayer = arcpy.MakeFeatureLayer_management("Burglary","Burglary_Layer")
      arcpy.SelectLayerByLocation_management (flayer, "WITHIN_A_DISTANCE", "c:/ArcpyBook/Ch7/EdgewoodSD.shp","1 MILES")
      arcpy.CopyFeatures_management(flayer, 'c:/ArcpyBook/Ch7/EdgewoodBurglaries.shp')
    	#cnt = arcpy.GetCount_management(flayer)
     #print("The total number of selected records is: " + str(cnt))
    except Exception as e:
      print(e.message)
    
  21. 保存脚本。

  22. 你可以通过检查c:\ArcpyBook\code\Ch7\SelectByLocation_Step3.py解决方案文件来检查你的工作。

  23. 运行脚本。

  24. 检查你的c:\ArcpyBook\Ch7文件夹以查看输出 shapefile。

它是如何工作的…

按位置选择工具要求将要素图层作为第一个参数传递。在这个菜谱中,我们传递了一个由上一行中的创建要素图层工具创建的要素图层。我们使用创建要素图层Burglary要素类创建了一个要素图层。这个要素图层被分配给flayer变量,然后作为第一个参数传递给按位置选择工具。在这个脚本中,我们还传递了一个参数,表示我们想要应用的空间关系。最后,我们还定义了一个用于比较空间关系的源图层。其他可以应用的可选参数包括搜索距离和选择类型。

使用按位置选择工具结合空间和属性查询

有时候你可能想使用组合属性和空间查询来选择要素。例如,你可能想选择在 Edgewood 学区发生的所有星期一的盗窃案。这可以通过依次运行按位置选择按属性选择工具并应用子集选择选择类型来实现。

准备工作

此菜谱将需要你创建一个作为临时图层使用的要素图层,该图层将与 按位置选择按属性选择图层 工具一起使用。按位置选择 工具将找到所有位于 Edgewood 学校区内的盗窃案件,并将选择集应用于这些要素。按属性选择图层 工具使用相同的临时要素图层,并应用一个 where 子句,以找到特定星期一发生的所有盗窃案件。此外,该工具还指定选择应该是通过 按位置选择 工具找到的当前所选要素的子集。最后,你将打印出通过组合空间和属性查询所选的总记录数。

如何操作...

  1. 打开 IDLE 并创建一个新的脚本窗口。

  2. 将脚本保存为 c:\ArcpyBook\Ch7\SpatialAttributeQuery.py

  3. 导入 arcpy 模块:

    import arcpy 
    
  4. 将工作空间设置为圣安东尼奥市的地理数据库:

    arcpy.env.workspace = "c:/ArcpyBook/data/CityofSanAntonio.gdb"
    
  5. 开始一个 try 块。你需要将以下行缩进到 except 块:

    try:
    
  6. 为查询创建一个变量并定义 where 子句:

    qry = '"DOW" = \'Mon\''
    
  7. 创建要素图层:

    flayer = arcpy.MakeFeatureLayer_management("Burglary","Burglary_Layer")
    
  8. 执行 按位置选择 工具以找到 Edgewood 学校区内的所有盗窃案件:

    arcpy.SelectLayerByLocation_management (flayer, "COMPLETELY_WITHIN", "c:/ArcpyBook/Ch7/EdgewoodSD.shp")
    
  9. 执行 按属性选择图层 工具以找到所有与我们在 qry 变量中先前定义的查询匹配的盗窃案件。这应该定义为子集查询:

    arcpy.SelectLayerByAttribute_management(flayer, "SUBSET_SELECTION", qry)
    
  10. 打印所选记录的数量:

    cnt = arcpy.GetCount_management(flayer)
    print("The total number of selected records is: " + str(cnt))
    
  11. 添加 except 块:

    except Exception as e:
      print(e.message)
    
  12. 整个脚本应如下所示:

    import arcpy
    arcpy.env.workspace = "c:/ArcpyBook/data/CityOfSanAntonio.gdb"
    try:
      qry = '"DOW" = \'Mon\''
      flayer = arcpy.MakeFeatureLayer_management("Burglary","Burglary_Layer")
      arcpy.SelectLayerByLocation_management (flayer, "COMPLETELY_WITHIN", "c:/ArcpyBook/Ch7/EdgewoodSD.shp")
      arcpy.SelectLayerByAttribute_management(flayer, "SUBSET_SELECTION", qry)
      cnt = arcpy.GetCount_management(flayer)
      print("The total number of selected records is: " + str(cnt))
    except Exception as e:
      print(e.message)
    
  13. 保存并运行脚本。如果一切操作正确,你应该会看到一个消息表明已选择 197 条记录。这将选择在 Edgewood 学校区边界内发生的所有星期一发生的盗窃案件:

    The total number of selected records is: 197
    
    
  14. 你可以通过检查 c:\ArcpyBook\code\Ch7\SpatialAttributeQuery.py 解决方案文件来验证你的工作。

它是如何工作的...

使用创建要素图层工具创建了一个新的要素图层,并将其分配给变量flayer。这个临时图层随后被用作按位置选择工具的输入,同时使用COMPLETELY_WITHIN空间运算符,以找到位于 Edgewood 学区内的所有盗窃事件。这个相同的要素图层,在已经定义了选择集之后,被用作按属性选择图层工具的输入参数。除了传递对要素图层的引用外,按属性选择图层工具还传递了一个参数,该参数定义了选择类型和where子句。选择类型设置为SUBSET_SELECTION。这种选择类型创建了一个新的选择,并将其与现有选择合并。只有两个选择都共有的记录才会被选中。作为第三个参数传入的where子句是一个属性查询,用于查找所有发生在周一的盗窃事件。查询使用DOW字段,寻找值为Mon的值。最后,使用获取计数工具对flayer变量进行操作,以获取选中记录的数量,并将此信息打印到屏幕上。

第八章:使用 ArcPy 数据访问模块与要素类和表

在本章中,我们将介绍以下菜谱:

  • 使用 SearchCursor 从要素类中检索特征

  • 使用 where 子句过滤记录

  • 使用几何标记提高游标性能

  • 使用 InsertCursor 插入行

  • 使用 UpdateCursor 更新行

  • 使用 UpdateCursor 删除行

  • 在编辑会话中插入和更新行

  • 从要素类中读取几何形状

  • 使用 Walk() 导航目录

简介

我们将从这个章节的基本问题开始。什么是游标?游标是包含来自表或要素类的数据行的一个或多个行的内存对象。每一行包含数据源中每个字段的属性以及每个要素的几何形状。游标允许您在表和要素类中搜索、添加、插入、更新和删除数据。

arcpy数据访问模块或arcpy.da是在 ArcGIS 10.1 中引入的,它包含允许您遍历游标中每一行的方法。根据开发者的需求,可以创建各种类型的游标。例如,可以创建搜索游标来读取行中的值。可以创建更新游标来更新行中的值或删除行,也可以创建插入游标来插入新行。

随着 ArcPy 数据访问模块的引入,已经推出了一系列游标改进。在 ArcGIS 10.1 开发之前,游标性能臭名昭著地慢。现在,游标的速度显著提高。Esri 估计SearchCursors的速度可以快 30 倍,而InsertCursors可以快 12 倍。除了这些一般性能改进之外,数据访问模块还提供了一些新的选项,允许程序员加快处理速度。现在,您可以选择只返回游标中的部分字段,而不是所有字段,这样可以提高性能,因为需要返回的数据更少。同样也适用于几何形状。传统上,当访问要素的几何形状时,会返回整个几何定义。现在,您可以使用几何标记来返回几何形状的一部分,而不是要素的完整几何形状。您还可以使用列表和元组而不是使用行。还有其他一些新特性,例如编辑会话和与版本、域和子类型一起工作的能力。

arcpy.da中有三个光标函数。每个函数都返回一个与函数同名的光标对象。SearchCursor()创建一个包含来自表或要素类行的只读SearchCursor对象。InsertCursor()创建一个InsertCursor对象,可用于向表或要素类插入新记录。UpdateCursor()返回一个可用于编辑或删除表或要素类记录的光标对象。这些光标对象都有访问光标中行的方法。你可以看到光标函数、它们创建的对象以及它们的使用之间的关系,如下所示:

函数 创建的对象 用途
SearchCursor() SearchCursor 这是从表或要素类获取数据的只读视图
InsertCursor() InsertCursor 这用于向表或要素类添加行
UpdateCursor() UpdateCursor 这用于编辑或删除表或要素类的行

SearchCursor()函数用于返回一个SearchCursor对象。此对象只能用于迭代为只读目的返回的一组行。通过此对象无法进行插入、删除或更新操作。可以设置可选的where子句以限制返回的行。

一旦你获得了光标实例,通常会对记录进行迭代,尤其是在使用SearchCursorUpdateCursor时。在光标中导航记录时,你需要了解一些特殊之处。光标导航仅向前移动。当创建光标时,光标指针位于光标中第一行之上。对next()的第一次调用将指针移动到第一行。你不仅可以调用next()方法,还可以使用for循环来处理每条记录,而无需调用next()方法。在完成对这一行的任何所需处理之后,对next()的后续调用将指针移动到第二行。只要你需要访问额外的行,这个过程就会继续。然而,一旦访问过一行,你无法一次回退一个记录。例如,如果当前行是第三行,你无法通过编程方式回退到第二行。你只能向前移动。要重新访问第一行和第二行,你需要要么调用reset()方法,要么重新创建光标并通过对象回退。正如我之前提到的,光标通常通过使用for循环来导航。事实上,这是迭代光标和编写脚本更常见、更有效的方法。光标导航在以下图中展示:

简介

使用 InsertCursor() 函数创建 InsertCursor 对象,允许您以编程方式向要素类和表中添加新记录。要插入行,请在此对象上调用 insertRow() 方法。您还可以通过 fields 属性检索包含游标正在使用的字段名称的只读元组。通过游标访问的表或要素类会被放置一个锁。因此,始终以在完成时释放游标的方式设计您的脚本是很重要的。

使用 UpdateCursor() 函数可以创建一个 UpdateCursor 对象,可以更新和删除表或要素类中的行。与 InsertCursor 一样,此函数在编辑或删除数据时会对数据进行锁定。如果游标在 Python 的 with 语句内部使用,则在数据被处理后锁将自动释放。这并不总是如此。在 ArcGIS 10.1 之前,必须使用 Python 的 del 语句手动释放游标。一旦获得 UpdateCursor 的实例,您就可以调用 updateCursor() 方法来更新表或要素类中的记录,以及调用 deleteRow() 方法来删除一行。

数据锁的主题需要更多的解释。insertupdate 游标必须对其引用的数据源获取锁。这意味着没有其他应用程序可以同时访问此数据源。锁是防止多个用户同时更改数据并因此损坏数据的一种方式。当在您的代码中调用 InsertCursor()UpdateCursor() 方法时,Python 会尝试获取数据的锁。此锁必须在游标完成处理之后特别释放,以便其他用户的运行应用程序,如 ArcMapArcCatalog,可以访问数据源。如果不这样做,其他应用程序将无法访问数据。在 ArcGIS 10.1 和 with 语句之前,游标必须通过 Python 的 del 语句特别解锁。同样,ArcMapArcCatalog 在更新或删除数据时也会获取数据锁。如果数据源被这两个应用程序中的任何一个锁定,您的 Python 代码将无法访问数据。因此,最佳实践是在运行任何使用 insertupdate 游标的独立 Python 脚本之前关闭 ArcMapArcCatalog

在本章中,我们将介绍使用游标访问和编辑表和要素类的方法。然而,ArcGIS 10.1 之前存在的许多游标概念仍然适用。

使用 SearchCursor 从要素类检索要素

有很多场合你需要从表或要素类中检索行以进行只读操作。例如,你可能想生成一个包含价值超过 $100,000 的所有土地地块的列表。在这种情况下,你不需要编辑数据。你的需求仅通过生成满足某些条件的行列表就能得到满足。SearchCursor 对象包含来自表或要素类的行的只读副本。这些对象也可以通过使用 where 子句进行过滤,以便只返回数据集的一个子集。

准备工作

SearchCursor() 函数用于返回一个 SearchCursor 对象。此对象只能用于迭代为只读目的返回的一组行。通过此对象不能进行插入、删除或更新操作。可以设置一个可选的 where 子句来限制返回的行。在本例中,你将学习如何通过使用 SearchCursor() 函数在要素类上创建一个基本的 SearchCursor 对象。

SearchCursor 对象包含一个 fields 属性以及 next()reset() 方法。fields 属性是一个只读结构,形式为 Python 元组,包含从要素类或表中请求的字段。你将经常在游标的使用中听到术语元组。如果你之前没有覆盖这个主题,元组是 Python 用来存储类似 Python 列表的数据序列的结构。然而,Python 元组和列表之间有一些重要的区别。元组定义为括号内的一系列值,而列表定义为方括号内的一系列值。与列表不同,元组不能增长和缩小,这在某些情况下可能是一个非常好的事情,当你希望数据值每次都占据一个特定的位置时。这是使用元组来存储来自表和要素类字段的数据的游标对象的情况。

如何操作...

按照以下步骤学习如何在 SearchCursor 对象内部检索表或要素类的行:

  1. 打开 IDLE 并创建一个新的脚本窗口。

  2. 将脚本保存为 C:\ArcpyBook\Ch8\SearchCursor.py

  3. 导入 arcpy.da 模块:

    import arcpy.da
    
  4. 设置工作空间:

    arcpy.env.workspace = "c:/ArcpyBook/Ch8"
    
  5. 使用 Python with 语句创建游标:

    with arcpy.da.SearchCursor("Schools.shp",("Facility","Name")) as cursor:
    
  6. 遍历 SearchCursor 中的每一行并打印学校的名称。确保在 with 块内缩进 for 循环:

    for row in sorted(cursor):
      print("School name: " + row[1])
    
  7. 整个脚本应如下所示:

    import arcpy.da
    arcpy.env.workspace = "c:/ArcpyBook/Ch8"
    with arcpy.da.SearchCursor("Schools.shp",("Facility","Name")) as cursor:
        for row in sorted(cursor):
            print("School name: " + row[1])
    
  8. 保存脚本。

  9. 你可以通过检查 C:\ArcpyBook\code\Ch8\SearchCursor_Step1.py 解决方案文件来检查你的工作。

  10. 运行脚本。你应该看到以下输出:

    School name: ALLAN
    School name: ALLISON
    School name: ANDREWS
    School name: BARANOFF
    School name: BARRINGTON
    School name: BARTON CREEK
    School name: BARTON HILLS
    School name: BATY
    School name: BECKER
    School name: BEE CAVE
    
    

它是如何工作的...

使用与SearchCursor()函数一起使用的with语句将创建、打开和关闭游标。因此,你不再需要担心像在 ArcGIS 10.1 之前那样显式释放游标的锁。传递给SearchCursor()函数的第一个参数是一个要素类,由Schools.shp文件表示。第二个参数是一个 Python 元组,包含我们希望在游标中返回的字段列表。出于性能考虑,将游标中返回的字段限制为你需要完成任务的那些字段是一个最佳实践。在这里,我们指定只返回FacilityName字段。SearchCursor对象存储在一个名为cursor的变量中。

with块内部,我们使用 Python 的for循环遍历返回的每一所学校。我们还使用 Python 的sorted()函数对游标的内容进行排序。要访问行上的字段值,只需使用你想要返回的字段的索引号。在这种情况下,我们想要返回Name列的内容,这将是一个1索引号,因为它是在返回的字段名元组中的第二个项目。

使用where子句过滤记录

默认情况下,SearchCursor将包含表或要素类中的所有行。然而,在许多情况下,你可能希望根据某种标准限制返回的行数。通过使用where子句应用过滤器可以限制返回的记录。

准备工作

默认情况下,当你创建SearchCursor对象时,将返回表或要素类中的所有行。然而,在许多情况下,你可能希望限制返回的记录。你可以通过创建一个查询,并在调用SearchCursor()函数时将其作为where子句参数传递来实现这一点。在这个菜谱中,你将通过添加一个限制返回记录的where子句来扩展你在上一个菜谱中创建的脚本。

如何做…

按照以下步骤对SearchCursor对象应用过滤器,以限制从表或要素类返回的行:

  1. 打开IDLE并加载你在上一个菜谱中创建的SearchCursor.py脚本。

  2. 通过添加一个查询设施字段并查询具有HIGH SCHOOL文本的记录的where子句来更新SearchCursor()函数。

    with arcpy.da.SearchCursor("Schools.shp",("Facility","Name"), '"FACILITY" = \'HIGH SCHOOL\'') as cursor:
    
  3. 你可以通过检查C:\ArcpyBook\code\Ch8\SearchCursor_Step2.py解决方案文件来检查你的工作。

  4. 保存并运行脚本。现在输出将小得多,仅限于高中:

    High school name: AKINS
    High school name: ALTERNATIVE LEARNING CENTER
    High school name: ANDERSON
    High school name: AUSTIN
    High school name: BOWIE
    High school name: CROCKETT
    High school name: DEL VALLE
    High school name: ELGIN
    High school name: GARZA
    High school name: HENDRICKSON
    High school name: JOHN B CONNALLY
    High school name: JOHNSTON
    High school name: LAGO VISTA
    
    

它是如何工作的…

我们在第七章中介绍了查询的创建,查询和选择数据,所以希望你现在对这些结构的创建有一个很好的掌握,以及当你编写这些结构时需要遵循的所有规则。where子句参数接受任何有效的 SQL 查询,并且在这个情况下用于限制返回的记录数。

使用几何令牌提高游标性能

几何令牌是在 ArcGIS 10.1 中引入的,作为游标性能改进的一部分。而不是在游标内返回特征的整个几何形状,只返回几何形状的一部分。返回特征的整个几何形状可能会导致游标性能下降,因为需要返回的数据量很大。仅返回所需的具体几何形状部分要快得多。

准备工作

令牌作为字段列表中传递给构造函数的一个字段提供,其格式为SHAPE@<要返回的特征部分>。此格式的唯一例外是OID@令牌,它返回特征的对象 ID。以下代码示例仅检索特征的XY坐标:

with arcpy.da.SearchCursor(fc, ("SHAPE@XY","Facility","Name")) as cursor:

以下表格列出了可用的几何令牌。并非所有游标都支持完整的令牌列表。请查阅 ArcGIS 帮助文件以获取有关每个游标类型支持的令牌的信息。SHAPE@令牌返回特征的整个几何形状。尽管如此,请谨慎使用,因为返回特征的整个几何形状是一个昂贵的操作,并且可能会显著影响性能。如果您不需要整个几何形状,则不要包含此令牌!

准备工作

在这个菜谱中,您将使用几何令牌来提高游标的处理性能。您将从parcels要素类中检索每个土地地块的XY坐标,以及地块的一些属性信息。

如何做…

按照以下步骤将几何令牌添加到游标中,这应该会提高该对象的处理性能:

  1. 打开IDLE并创建一个新的脚本窗口。

  2. 将脚本保存为C:\ArcpyBook\Ch8\GeometryToken.py

  3. 导入arcpy.da模块和时间模块:

    import arcpy.da
    import time
    
  4. 设置工作空间:

    arcpy.env.workspace = "c:/ArcpyBook/Ch8"
    
  5. 我们将使用几何令牌来测量执行代码所需的时间。为脚本添加start时间:

    start = time.clock()
    
  6. 使用 Python 的with语句创建一个游标,该游标包括每个特征的质心以及存储在PY_FULL_OW字段中的所有权信息:

    with arcpy.da.SearchCursor("coa_parcels.shp",("PY_FULL_OW","SHAPE@XY")) as cursor:
    
  7. 遍历SearchCursor中的每一行,并打印包裹名称和位置。确保在with块内部缩进for循环:

    for row in cursor:
      print("Parcel owner: {0} has a location of: {1}".format(row[0], row[1]))
    
  8. 测量经过的时间:

    elapsed = (time.clock() - start)
    
  9. 打印执行时间:

    print("Execution time: " + str(elapsed))
    
  10. 整个脚本应如下所示:

    import arcpy.da
    import time
    arcpy.env.workspace = "c:/ArcpyBook/Ch9"
    start = time.clock()
    with arcpy.da.SearchCursor("coa_parcels.shp",("PY_FULL_OW", "SHAPE@XY")) as cursor:
        for row in cursor:
            print("Parcel owner: {0} has a location of: {1}".format(row[0], row[1]))
    elapsed = (time.clock() - start)
    print("Execution time: " + str(elapsed))
    
  11. 您可以通过检查C:\ArcpyBook\code\Ch8\GeometryToken.py解决方案文件来检查您的作品。

  12. 保存脚本。

  13. 运行脚本。您应该看到以下类似的输出。注意执行时间;您的时间会有所不同:

    Parcel owner: CITY OF AUSTIN ATTN REAL ESTATE DIVISION has a location of: (3110480.5197341456, 10070911.174956793)
    Parcel owner: CITY OF AUSTIN ATTN REAL ESTATE DIVISION has a location of: (3110670.413783513, 10070800.960865)
    Parcel owner: CITY OF AUSTIN has a location of: (3143925.0013213265, 10029388.97419636)
    Parcel owner: CITY OF AUSTIN % DOROTHY NELL ANDERSON ATTN BARRY LEE ANDERSON has a location of: (3134432.983822767, 10072192.047894118)
    Execution time: 9.08046185109
    
    

现在,我们将测量如果返回整个几何形状而不是所需几何形状的部分,执行时间将如何变化:

  1. 将脚本保存为新副本,命名为C:\ArcpyBook\Ch8\GeometryTokenEntireGeometry.py

  2. SearchCursor()函数更改为使用SHAPE@而不是SHAPE@XY返回整个几何形状:

    with arcpy.da.SearchCursor("coa_parcels.shp",("PY_FULL_OW", "SHAPE@")) as cursor:
    
  3. 你可以通过检查 C:\ArcpyBook\code\Ch8\GeometryTokenEntireGeometry.py 解决方案文件来检查你的工作。

  4. 保存并运行脚本。你应该会看到以下输出。你的时间可能会和我的不同,但请注意执行时间较慢。在这种情况下,它只慢了一点点,但我们只返回了 2600 个特征。如果特征类的大小显著更大,像许多情况一样,这将放大:

    Parcel owner: CITY OF AUSTIN ATTN REAL ESTATE DIVISION has a location of: <geoprocessing describe geometry object object at 0x06B9BE00>
    Parcel owner: CITY OF AUSTIN ATTN REAL ESTATE DIVISION has a location of: <geoprocessing describe geometry object object at 0x2400A700>
    Parcel owner: CITY OF AUSTIN has a location of: <geoprocessing describe geometry object object at 0x06B9BE00>
    Parcel owner: CITY OF AUSTIN % DOROTHY NELL ANDERSON ATTN BARRY LEE ANDERSON has a location of: <geoprocessing describe geometry object object at 0x2400A700>
    Execution time: 10.1211390896
    
    

它是如何工作的…

可以将几何标记作为游标构造函数中提供的字段名称之一提供。这些标记用于通过仅返回部分几何而不是整个几何来提高游标性能。这可以显著提高游标的性能,尤其是在处理大型折线或多边形数据集时。如果你只需要游标中几何的特定属性,你应该使用这些标记。

使用 InsertCursor 插入行

你可以使用 InsertCursor 对象将行插入到表或特征类中。如果你想将属性值与新行一起插入,你需要按属性表中的顺序提供这些值。

准备工作

InsertCursor() 函数用于创建一个 InsertCursor 对象,允许你以编程方式向特征类和表添加新记录。InsertCursor 对象上的 insertRow() 方法添加行。将形式为列表或元组的行传递到 insertRow() 方法中。列表中的值必须与创建 InsertCursor 对象时定义的字段值相对应。类似于包含其他类型游标的实例,你也可以使用方法的第二个参数限制返回的字段名称。此函数还支持几何标记。

以下代码示例说明了如何使用 InsertCursor 将新行插入到特征类中。在这里,我们将两个新的野火点插入到 California 特征类中。要插入的行值定义在一个 list 变量中。然后,创建一个 InsertCursor 对象,传入特征类和字段。最后,通过使用 insertRow() 方法将新行插入到特征类中:

rowValues = [(Bastrop','N',3000,(-105.345,32.234)), ('Ft Davis','N', 456, (-109.456,33.468))]
fc = "c:/data/wildfires.gdb/California"
fields = ["FIRE_NAME", "FIRE_CONTAINED", "ACRES", "SHAPE@XY"]
with arcpy.da.InsertCursor(fc, fields) as cursor:
  for row in rowValues:
    cursor.insertRow(row)

在这个菜谱中,你将使用 InsertCursor 将从 .txt 文件中检索到的野火添加到点特征类中。在将行插入到特征类时,你需要知道如何将特征的空间表示添加到特征类中。这可以通过使用 InsertCursor 以及两个杂项对象:ArrayPoint 来实现。在这个练习中,我们将以野火事件的形式将点特征添加到空点特征类中。此外,你还将使用 Python 文件操作技术从文本文件中读取坐标数据。

如何做…

我们将导入 2007 年 10 月某一天的美国野火事件数据。这些数据包含在一个逗号分隔的文本文件中,该文件包含该特定日期上每个火灾事件的单独一行。每个火灾事件都有一个由逗号分隔的纬度、经度坐标对以及一个置信度值。这些数据是通过使用遥感数据来推导野火的有无而自动生成的。置信度值范围从 0 到 100。数值越高表示这是一个真正的野火的置信度越大:

  1. 打开文件C:\ArcpyBook\Ch8\Wildfire Data\NorthAmericaWildfire_2007275.txt并检查其内容。

    你会注意到这是一个简单的逗号分隔的文本文件,包含每个火灾的经纬度值以及一个置信度值。我们将使用 Python 逐行读取该文件的内容,并将新的点要素插入到位于C:\ArcpyBook\Ch8 \WildfireData\WildlandFires.mdb个人地理数据库中的FireIncidents要素类中。

  2. 关闭文件。

  3. 打开ArcCatalog

  4. 导航到C:\ArcpyBook\Ch8\WildfireData

    你应该看到一个名为WildlandFires的个人地理数据库。打开此数据库,你会看到一个名为FireIncidents的点要素类。目前,这是一个空要素类。我们将通过读取你之前检查的文本文件并插入点来添加要素。

  5. 右键点击FireIncidents并选择属性

  6. 点击字段选项卡。

    在我们之前检查的文件中找到的纬度/经度值将被导入到SHAPE字段,置信度值将被写入CONFIDENCEVALUE字段。

  7. 打开IDLE并创建一个新的脚本。

  8. 将脚本保存到C:\ArcpyBook\Ch8\InsertWildfires.py

  9. 导入arcpy模块:

    import arcpy
    
  10. 设置工作空间:

    arcpy.env.workspace = "C:/ArcpyBook/Ch8/WildfireData/WildlandFires.mdb"
    
  11. 打开文本文件并将所有行读入一个列表:

    f = open("C:/ArcpyBook/Ch8/WildfireData/NorthAmericaWildfires_2007275.txt","r")
    lstFires = f.readlines()
    
  12. 开始一个try块:

    try:
    
  13. 使用with块创建一个InsertCursor对象。确保在try语句内部缩进。游标将在FireIncidents要素类中创建:

    with arcpy.da.InsertCursor("FireIncidents",("SHAPE@XY","CONFIDENCEVALUE")) as cur:
    
  14. 创建一个计数器变量,用于打印脚本的进度:

    cntr = 1
    
  15. 使用for循环逐行遍历文本文件。由于文本文件是逗号分隔的,我们将使用 Python 的split()函数将每个值分离到一个名为vals的列表变量中。然后我们将提取单独的纬度、经度和置信度值项并将它们分配给变量。最后,我们将这些值放入一个名为rowValue的列表变量中,然后将其传递给InsertCursor对象的insertRow()函数,然后打印一条消息:

    for fire in lstFires:
          if 'Latitude' in fire:
            continue
          vals = fire.split(",")
          latitude = float(vals[0])
          longitude = float(vals[1])
          confid = int(vals[2])
          rowValue = [(longitude,latitude),confid]
          cur.insertRow(rowValue)
          print("Record number " + str(cntr) + " written to feature class")
          #arcpy.AddMessage("Record number" + str(cntr) + " written to feature class")
          cntr = cntr + 1
    
  16. 添加except块以打印可能发生的任何错误:

    except Exception as e:
      print(e.message)
    
  17. 添加一个finally块以关闭文本文件:

    finally:
      f.close()
    
  18. 整个脚本应如下所示:

    import arcpy
    
    arcpy.env.workspace = "C:/ArcpyBook/Ch8/WildfireData/WildlandFires.mdb"
    f = open("C:/ArcpyBook/Ch8/WildfireData/NorthAmericaWildfires_2007275.txt","r")
    lstFires = f.readlines()
    try:
      with arcpy.da.InsertCursor("FireIncidents", ("SHAPE@XY","CONFIDENCEVALUE")) as cur:
        cntr = 1
        for fire in lstFires:
          if 'Latitude' in fire:
            continue
          vals = fire.split(",")
          latitude = float(vals[0])
          longitude = float(vals[1])
          confid = int(vals[2])
          rowValue = [(longitude,latitude),confid]
          cur.insertRow(rowValue)
          print("Record number " + str(cntr) + " written to feature class")
          #arcpy.AddMessage("Record number" + str(cntr) + " written to feature class")
          cntr = cntr + 1
    except Exception as e:
      print(e.message)
    finally:
      f.close()
    
  19. 你可以通过检查C:\ArcpyBook\code\Ch8\InsertWildfires.py解决方案文件来检查你的工作。

  20. 保存并运行脚本。当脚本运行时,你应该会看到消息被写入输出窗口:

    Record number: 406 written to feature class
    Record number: 407 written to feature class
    Record number: 408 written to feature class
    Record number: 409 written to feature class
    Record number: 410 written to feature class
    Record number: 411 written to feature class
    
    
  21. 打开 ArcMap 并将 FireIncidents 要素类添加到内容表中。点应该可见,如下面的截图所示:如何操作…

  22. 你可能想要添加一个底图来为数据提供一些参考。在 ArcMap 中,点击 添加底图 按钮,并从图库中选择一个底图。

它是如何工作的…

这里可能需要一些额外的解释。lstFires 变量包含了一个逗号分隔的文本文件中包含的所有野火列表。for 循环将逐个遍历这些记录,将每个单独的记录插入到 fire 变量中。我们还包含了一个 if 语句,用于跳过文件中的第一个记录,该记录作为标题。正如我之前解释的,然后我们从 vals 变量中提取单个纬度、经度和置信度值项,vals 变量只是一个 Python 列表对象,并将它们分配给名为 latitudelongitudeconfid 的变量。然后我们将这些值按照我们在创建 InsertCursor 时定义的顺序放入一个新的列表变量 rowValue 中。因此,纬度和经度对应该首先放置,然后是置信度值。最后,我们在 cur 变量分配的 InsertCursor 对象上调用 insertRow() 函数,传入新的 rowValue 变量。我们通过打印一条消息来结束,该消息指示脚本的进度,并创建 exceptfinally 块来处理错误和关闭文本文件。将 file.close() 方法放在 finally 块中确保即使在之前的 try 语句中发生错误,它也会执行并关闭文件。

使用 UpdateCursor 更新行

如果你需要编辑或删除表或要素类中的行,你可以使用 UpdateCursor。与 InsertCursor 一样,可以通过使用 where 子句来限制 UpdateCursor 的内容。

准备工作

UpdateCursor() 函数可用于更新或删除表或要素类中的行。返回的游标会对数据进行锁定,如果在使用 Python with 语句时使用,锁定将自动释放。从对该方法的调用返回一个 UpdateCursor 对象。

UpdateCursor 对象在编辑或删除数据时会对数据进行锁定。如果游标在 Python with 语句中使用,则在数据被处理后,锁定将自动释放。这并不总是如此。之前的游标版本需要使用 Python del 语句手动释放。一旦获得 UpdateCursor 实例,你就可以调用 updateCursor() 方法来更新表或要素类中的记录,并使用 deleteRow() 方法来删除一行。

在本菜谱中,你将编写一个脚本,通过使用UpdateCursorpoorfairgoodexcellent的值分配给一个新字段,该字段更能描述置信值,从而更新FireIncidents要素类中的每个要素。在更新记录之前,你的脚本将向FireIncidents要素类添加new字段。

如何操作…

按照以下步骤创建一个UpdateCursor对象,该对象将用于编辑要素类中的行:

  1. 打开IDLE并创建一个新的脚本。

  2. 将脚本保存到C:\ArcpyBook\Ch8\UpdateWildfires.py

  3. 导入arcpy模块:

    import arcpy
    
  4. 设置工作空间:

    arcpy.env.workspace = "C:/ArcpyBook/Ch8/WildfireData/WildlandFires.mdb"
    
  5. 开始一个try块:

    try:
    
  6. FireIncidents要素类添加一个名为CONFID_RATING的新字段。确保在try语句内缩进:

    arcpy.AddField_management("FireIncidents","CONFID_RATING", "TEXT","10")
    print("CONFID_RATING field added to FireIncidents")
    
  7. with块内创建一个新的UpdateCursor实例:

    with arcpy.da.UpdateCursor("FireIncidents", ("CONFIDENCEVALUE","CONFID_RATING")) as cursor:
    
  8. 创建一个计数器变量,用于打印脚本的进度。确保将此行代码及其后with块内的所有代码缩进:

    cntr = 1
    
  9. 遍历FireIncidents火类中的每一行。根据以下指南更新CONFID_RATING字段:

    • 置信值 0 到 40 = POOR

    • 置信值 41 到 60 = FAIR

    • 置信值 61 到 85 = GOOD

    • 置信值 86 到 100 = EXCELLENT

    这可以通过以下代码块进行翻译:

        for row in cursor:
          # update the confid_rating field
          if row[0] <= 40:
            row[1] = 'POOR'
          elif row[0] > 40 and row[0] <= 60:
            row[1] = 'FAIR'
          elif row[0] > 60 and row[0] <= 85:
            row[1] = 'GOOD'
          else:
            row[1] = 'EXCELLENT'
          cursor.updateRow(row)			
          print("Record number " + str(cntr) + " updated")
          cntr = cntr + 1
    
  10. 添加except块以打印可能发生的任何错误:

    except Exception as e:
      print(e.message)
    
  11. 整个脚本应如下所示:

    import arcpy
    
    arcpy.env.workspace = "C:/ArcpyBook/Ch8/WildfireData/WildlandFires.mdb"
    try:
      #create a new field to hold the values
      arcpy.AddField_management("FireIncidents", "CONFID_RATING","TEXT","10")
      print("CONFID_RATING field added to FireIncidents")
      with arcpy.da.UpdateCursor("FireIncidents",("CONFIDENCEVALUE", "CONFID_RATING")) as cursor:
        cntr = 1
        for row in cursor:
          # update the confid_rating field
          if row[0] <= 40:
            row[1] = 'POOR'
          elif row[0] > 40 and row[0] <= 60:
            row[1] = 'FAIR'
          elif row[0] > 60 and row[0] <= 85:
            row[1] = 'GOOD'
          else:
            row[1] = 'EXCELLENT'
          cursor.updateRow(row)			
          print("Record number " + str(cntr) + " updated")
          cntr = cntr + 1
    except Exception as e:
      print(e.message)
    
  12. 你可以通过检查C:\ArcpyBook\code\Ch8\UpdateWildfires.py解决方案文件来检查你的工作。

  13. 保存并运行脚本。当脚本运行时,你应该会在输出窗口看到消息:

    Record number 406 updated
    Record number 407 updated
    Record number 408 updated
    Record number 409 updated
    Record number 410 updated
    
    
  14. 打开ArcMap并添加FireIncidents要素类。打开属性表,你应该会看到已添加并由UpdateCursor填充的新CONFID_RATING字段:如何操作…

注意

当你在游标中插入、更新或删除数据时,更改是永久的,如果你在编辑会话外工作,则无法撤销更改。然而,使用 ArcGIS 10.1 提供的新编辑会话功能,你现在可以在编辑会话内进行这些更改以避免这些问题。我们很快会介绍编辑会话。

工作原理…

在这种情况下,我们使用了 UpdateCursor 来更新要素类中的每个要素。我们首先使用 Add Field 工具添加一个名为 CONFID_RATING 的新字段,该字段将保存我们根据另一个字段中找到的值分配的新值。这些组是差、一般、好和优秀,并且基于 CONFIDENCEVALUE 字段中找到的数值。然后,我们根据 FireIncidents 要素类创建了一个新的 UpdateCursor 实例,并返回了之前提到的两个字段。然后脚本遍历每个要素,并根据 CONFIDENCEVALUE 中找到的数值将 CONFID_RATING 字段(row[1])的值设置为差、一般、好或优秀。使用 Python 的 if/elif/else 结构根据数值控制脚本的流程。然后通过将行变量传递到 updateRow() 方法中,将 CONFID_RATING 的值提交到要素类。

使用 UpdateCursor 删除行

除了用于编辑表或要素类中的行之外,UpdateCursor 还可以用于删除行。请注意,当在编辑会话之外删除行时,更改是永久的。

准备工作

除了更新记录之外,UpdateCursor 还可以从表或要素类中删除记录。在两种情况下,UpdateCursor 对象的创建方式相同,但不是调用 updateRow(),而是调用 deleteRow() 来删除记录。你还可以将 where 子句应用于 UpdateCursor,以限制返回的记录。在本例中,我们将使用带有 where 子句过滤的 UpdateCursor 对象来从我们的 FireIncidents 要素类中删除记录。

如何做到这一点...

按照以下步骤创建一个 UpdateCursor 对象,该对象将用于从要素类中删除行:

  1. 打开 IDLE 并创建一个新的脚本。

  2. 将脚本保存到 C:\ArcpyBook\Ch8\DeleteWildfires.py

  3. 导入 arcpyos 模块:

    import arcpy
    import os
    
  4. 设置工作空间:

    arcpy.env.workspace = "C:/ArcpyBook/Ch8/WildfireData/WildlandFires.mdb"
    
  5. 开始一个 try 块:

    try:
    
  6. with 块内创建 UpdateCursor 的新实例。确保在 try 语句内缩进:

    with arcpy.da.UpdateCursor("FireIncidents",("CONFID_RATING"), '[CONFID_RATING] = \'POOR\'') as cursor:
    
  7. 创建一个计数变量,该变量将用于打印脚本的进度。确保缩进此行代码以及 with 块内随后的所有代码行:

    cntr = 1
    
  8. 通过调用 deleteRow() 方法删除返回的行。这是通过遍历返回的游标并逐行删除来完成的:

    for row in cursor:
      cursor.deleteRow()
      print("Record number " + str(cntr) + " deleted")
      cntr = cntr + 1
    
  9. 添加 except 块以打印可能发生的任何错误:

    except Exception as e:
      print(e.message)
    
  10. 整个脚本应如下所示:

    import arcpy
    import os
    
    arcpy.env.workspace = "C:/ArcpyBook/Ch8/WildfireData/WildlandFires.mdb"
    try:
      with arcpy.da.UpdateCursor("FireIncidents",("CONFID_RATING"), '[CONFID_RATING] = \'POOR\'') as cursor:
        cntr = 1
        for row in cursor:
          cursor.deleteRow()
          print("Record number " + str(cntr) + " deleted")
          cntr = cntr + 1
    except Exception as e:
      print(e.message)
    
  11. 你可以通过检查 C:\ArcpyBook\code\Ch8\DeleteWildfires.py 解决方案文件来验证你的工作。

  12. 保存并运行脚本。当脚本运行时,你应该会看到消息被写入输出窗口。FireIncidents 要素类中应该会删除 37 条记录:

    Record number 1 deleted
    Record number 2 deleted
    Record number 3 deleted
    Record number 4 deleted
    Record number 5 deleted
    
    

它是如何工作的...

可以使用UpdateCursor中的deleteRow()方法从要素类和表中删除行。在本食谱中,我们使用UpdateCursor构造函数中的where子句来限制返回的记录仅包含CONFID_RATINGPOOR的要素。然后我们遍历游标返回的要素,并调用deleteRow()方法从要素类中删除该行。

在编辑会话内插入和更新行

正如我在本章中提到的,在编辑会话之外对表或要素类进行的插入、更新或删除操作是永久的。这些更改无法撤销。编辑会话为您提供了更大的灵活性,可以回滚任何不希望的变化。

准备工作

到目前为止,我们使用插入和更新游标来向要素类和表中添加、编辑和删除数据。这些更改在脚本执行后立即生效,并且无法撤销。数据访问模块中的新Editor类支持创建编辑会话和操作的能力。使用编辑会话,对要素类或表应用的变化在通过特定方法调用永久应用之前是临时的。这与 ArcGIS for Desktop 中的Edit工具栏提供的功能相同。

编辑会话从调用Editor.startEditing()开始,这会启动会话。在会话内部,您然后使用Editor.startOperation()方法开始一个操作。在这个操作中,您执行各种操作,这些操作对您的数据进行编辑。这些编辑也可以受到撤销、重做和取消操作的影响,以回滚、前进和取消您的编辑操作。操作完成后,您然后调用Editor.stopOperation()方法,接着调用Editor.stopEditing()。会话可以在不保存更改的情况下结束。在这种情况下,更改不会被永久应用。以下截图提供了此过程的概述:

准备工作

编辑会话也可以在不保存更改的情况下结束。在这种情况下,更改不会被永久应用。编辑会话还允许在会话内应用操作,然后可以选择将这些操作永久应用到数据库中或回滚。此外,Editor类还支持撤销和重做操作。

以下代码示例显示了完整的编辑会话堆栈,包括创建Editor对象、开始编辑会话和操作、对数据进行编辑(在本例中为插入操作)、停止操作,以及最后通过保存数据结束编辑会话:

edit = arcpy.da.Editor('Database Connections/Portland.sde')
edit.startEditing(False)
edit.startOperation()
with arcpy.da.InsertCursor("Portland.jgp.schools",("SHAPE","Name")) as cursor:
  cursor.insertRow([(7642471.100, 686465.725), 'New School'])
edit.stopOperation()
edit.stopEditing(True)

Editor类可以与个人、文件和 ArcSDE 地理数据库一起使用。此外,也可以在版本化数据库上启动和停止会话。你一次只能编辑一个工作空间,并且这个工作空间通过在Editor对象的构造函数中传递一个引用工作空间的字符串来指定。一旦创建,这个Editor对象就可以访问所有启动、停止和取消操作以及执行撤销和重做操作的方法。

如何做到这一点…

按照以下步骤将UpdateCursor包裹在编辑会话内:

  1. 打开IDLE

  2. 打开C:\ArcpyBook\Ch8\UpdateWildfires.py脚本并将其保存到一个名为C:\ArcpyBook\Ch8\EditSessionUpdateWildfires.py的新脚本中。

  3. 我们将对这个现有的脚本进行几处修改,该脚本用于更新CONFID_RATING字段中的值。

  4. 删除以下代码行:

    arcpy.AddField_management("FireIncidents","CONFID_RATING", "TEXT","10")
    print("CONFID_RATING field added to FireIncidents")
    
  5. 创建Editor类的实例并启动一个编辑会话。这些代码行应该放在try块内:

    edit = arcpy.da.Editor(r'C:\ArcpyBook\Ch8\WildfireData\WildlandFires.mdb')
    edit.startEditing(True)
    
  6. 修改if语句,使其如下所示:

    if row[0] > 40 and row[0] <= 60:
      row[1] = 'GOOD'
    elif row[0] > 60 and row[0] <= 85:
      row[1] = 'BETTER'
    else:
      row[1] = 'BEST'
    
  7. 结束编辑会话并保存更改。将此代码行放在计数器增加的下面:

    edit.stopEditing(True)
    
  8. 整个脚本应该如下所示:

    import arcpy
    import os
    
    arcpy.env.workspace = "C:/ArcpyBook/Ch8/WildfireData/WildlandFires.mdb"
    try:
      edit = arcpy.da.Editor(r'C:\ArcpyBook\Ch8\WildfireData\WildlandFires.mdb')
      edit.startEditing(True)
      with arcpy.da.UpdateCursor("FireIncidents",("CONFIDENCEVALUE", "CONFID_RATING")) as cursor:
        cntr = 1
        for row in cursor:
          # update the confid_rating field
          if row[0] > 40 and row[0] <= 60:
            row[1] = 'GOOD'
          elif row[0] > 60 and row[0] <= 85:
            row[1] = 'BETTER'
          else:
            row[1] = 'BEST'
          cursor.updateRow(row)
          print("Record number " + str(cntr) + " updated")
          cntr = cntr + 1
      edit.stopEditing(True)
    except Exception as e:
      print(e.message)
    
  9. 你可以通过检查C:\ArcpyBook\code\Ch8\EditSessionUpdateWildfires.py解决方案文件来检查你的工作。

  10. 保存并运行脚本以更新 374 条记录。

工作原理…

编辑操作应在编辑会话内进行,可以通过Editor.startEditing()方法启动编辑会话。startEditing()方法包含两个可选参数,包括with_undomultiuser_modewith_undo参数接受布尔值truefalse,默认为true。当设置为true时,这将创建一个撤销/重做堆栈。multiuser_mode参数默认为true。当它为false时,你可以完全控制编辑非版本化或版本化数据集。如果你的数据集是非版本化的,并且你使用stopEditing(False),你的编辑将不会被提交。否则,如果设置为true,你的编辑将被提交。Editor.stopEditing()方法接受一个布尔值truefalse,表示是否应保存更改。默认为true

Editor类支持撤销和重做操作。我们将首先查看撤销操作。在编辑会话期间,可以应用各种编辑操作。如果需要撤销之前的操作,调用Editor.undoOperation()将移除堆栈中最新的编辑操作。这如下所示:

工作原理…

通过Editor.redoOperation()方法启动的重做操作将重做之前撤销的操作。这如下所示:

工作原理…

从特征类读取几何

有时候你可能需要检索特征类中特征的几何定义。ArcPy 通过各种对象提供了读取这些信息的能力。

准备工作

在 ArcPy 中,要素类关联着几何对象,包括 PolygonPolylinePointGeometryMultiPoint,您可以从您的游标中访问这些对象。这些对象指向要素类 table 属性中的 shape 字段。您可以通过这些对象读取要素类中每个要素的几何形状。

多段线和多边形要素类由包含多个部分的要素组成。您可以使用 partCount 属性返回每个要素的部分数量,然后使用 getPart() 对每个要素中的每个部分进行循环,以遍历每个点并提取坐标信息。点要素类由每个要素的一个 PointGeometry 对象组成,该对象包含每个点的坐标信息。

在本菜谱中,您将使用 SearchCursorPolygon 对象来读取多边形要素类的几何形状。

如何操作…

按照以下步骤学习如何从要素类中的每个要素读取几何信息:

  1. 打开 IDLE 并创建一个新的脚本。

  2. 将脚本保存到 C:\ArcpyBook\Ch8\ReadGeometry.py

  3. 导入 arcpy 模块:

    import arcpy
    
  4. 将输入要素类设置为 SchoolDistricts 多边形要素类:

    infc = "c:/ArcpyBook/data/CityOfSanAntonio.gdb/SchoolDistricts"
    
  5. 使用输入要素类创建一个 SearchCursor 对象,并返回 ObjectIDShape 字段。Shape 字段包含每个要素的几何形状。游标将在一个 for 循环内创建,我们将使用它来遍历要素类中的所有要素:

    for row in arcpy.da.SearchCursor(infc, ["OID@", "SHAPE@"]):
    #Print the object id of each feature.
    # Print the current ID
      print("Feature {0}:".format(row[0]))
      partnum = 0
    
  6. 使用 for 循环遍历每个要素的部分:

      # Step through each part of the feature
      for part in row[1]:
        # Print the part number
        print("Part {0}:".format(partnum))
    
  7. 使用 for 循环遍历每个部分中的每个顶点并打印 XY 坐标:

        # Step through each vertex in the feature
        #
        for pnt in part:
          if pnt:
            # Print x,y coordinates of current point
            #
            print("{0}, {1}".format(pnt.X, pnt.Y))
          else:
            # If pnt is None, this represents an interior ring
            #
            print("Interior Ring:")
        partnum += 1
    
  8. 您可以通过检查 C:\ArcpyBook\code\Ch8\ReadGeometry.py 解决方案文件来检查您的作业。

  9. 保存并运行脚本。当脚本为每个要素、每个要素的部分以及定义每个部分的 XY 坐标写入信息时,您应该看到以下输出:

    Feature 1:
    Part 0:
    -98.492224986, 29.380866971
    -98.489300049, 29.379610054
    -98.486967023, 29.378995028
    -98.48503096, 29.376808947
    -98.481447988, 29.375624018
    -98.478799041, 29.374304981
    
    

它是如何工作的…

我们最初创建了一个 SearchCursor 对象来保存我们要素类的所有内容。之后,我们使用 for 循环遍历游标中的每一行。对于每一行,我们遍历几何的所有部分。请记住,多段线和多边形要素由两个或多个部分组成。对于每个部分,我们也返回与每个部分关联的点,并打印每个点的 XY 坐标。

使用 Walk() 导航目录

在本菜谱中,您将学习如何使用 Arcpy Walk() 函数在目录树中生成数据名称。尽管与 Python 的 os.walk() 函数类似,但 da.Walk() 函数提供了一些与地理数据库相关的重要增强功能。

准备工作

arcpy.da中的Walk()函数通过自上而下或自下而上遍历目录树来生成目录树中的数据名称。每个目录或工作空间产生一个包含目录路径、目录名称和文件名的元组。此函数类似于 Python 的os.walk()函数,但它具有额外的优势,即能够识别地理数据库结构。os.walk()函数基于文件,因此它无法告诉你关于地理数据库结构的信息,而arcpy.da.walk()可以做到这一点。

如何做到这一点…

按照以下步骤学习如何使用da.Walk()函数来遍历目录和空间,以揭示地理数据库的结构:

  1. IDLE中创建一个名为DAWalk.py的新 Python 脚本,并将其保存到C:\ArcpyBook\data文件夹。

  2. 导入arcpyarcpy.daos模块:

    import arcpy.da as da
    import os
    
  3. 首先,我们将使用os.walk()获取当前目录中的文件名列表。添加以下代码:

    print("os walk")
    for dirpath, dirnames, filenames in os.walk(os.getcwd()):
      for filename in filenames:
        print(filename)
    
  4. 保存文件并运行它,以查看类似于以下输出的内容:

    a00000001.gdbindexes
    a00000001.gdbtable
    a00000001.gdbtablx
    a00000002.gdbtable
    a00000002.gdbtablx
    a00000003.gdbindexes
    a00000003.gdbtable
    a00000003.gdbtablx
    a00000004.CatItemsByPhysicalName.atx
    a00000004.CatItemsByType.atx
    a00000004.FDO_UUID.atx
    a00000004.freelist
    a00000004.gdbindexes
    a00000004.gdbtable
    a00000004.gdbtablx
    
    
  5. 虽然可以使用os.walk()打印出目录中的所有文件名,但你可能会注意到它并不理解 Esri GIS 格式数据集的结构,例如文件地理数据库。像a000000001.gdbindexes这样的文件是构成要素类的物理文件,但os.walk()无法告诉你要素类的逻辑结构。在下一步中,我们将使用da.walk()来解决这个问题。

  6. 注释掉你刚刚添加的代码。

  7. 添加以下代码块:

    print("arcpy da walk")
    for dirpath, dirnames, filenames in da.Walk(os.getcwd(),datatype="FeatureClass"):
      for filename in filenames:
        print(os.path.join(dirpath, filename)
    
  8. 整个脚本应如下所示:

    import arcpy.da as da
    import os
    
    print("os walk")
    
    for dirpath, dirnames, filenames in os.walk(os.getcwd()):
        for filename in filenames:
            print(filename)
    
    print("arcpy da walk")
    
    for dirpath, dirnames, filenames in da.Walk(os.getcwd(),datatype="FeatureClass"):
        for filename in filenames:
            print(os.path.join(dirpath, filename))
    
  9. 你可以通过检查C:\ArcpyBook\code\Ch8\Walk.py解决方案文件来验证你的工作。

  10. 保存并执行脚本以查看以下输出。注意输出变得更加整洁,并且实际包含在地理数据库中的要素类名称被打印出来,而不是物理文件名:

    C:\ArcpyBook\data\Building_Permits.shp
    C:\ArcpyBook\data\Burglaries_2009.shp
    C:\ArcpyBook\data\Streams.shp
    C:\ArcpyBook\data\CityOfSanAntonio.gdb\Crimes2009
    C:\ArcpyBook\data\CityOfSanAntonio.gdb\CityBoundaries
    C:\ArcpyBook\data\CityOfSanAntonio.gdb\CrimesBySchoolDistrict
    C:\ArcpyBook\data\CityOfSanAntonio.gdb\SchoolDistricts
    C:\ArcpyBook\data\CityOfSanAntonio.gdb\BexarCountyBoundaries
    C:\ArcpyBook\data\CityOfSanAntonio.gdb\Texas_Counties_LowRes
    C:\ArcpyBook\data\CityOfSanAntonio.gdb\Burglary
    C:\ArcpyBook\data\TravisCounty\BuildingPermits.shp
    C:\ArcpyBook\data\TravisCounty\CensusTracts.shp
    C:\ArcpyBook\data\TravisCounty\CityLimits.shp
    C:\ArcpyBook\data\TravisCounty\Floodplains.shp
    C:\ArcpyBook\data\TravisCounty\Hospitals.shp
    C:\ArcpyBook\data\TravisCounty\Schools.shp
    C:\ArcpyBook\data\TravisCounty\Streams.shp
    C:\ArcpyBook\data\TravisCounty\Streets.shp
    C:\ArcpyBook\data\TravisCounty\TravisCounty.shp
    C:\ArcpyBook\data\Wildfires\WildlandFires.mdb\FireIncidents
    
    

它是如何工作的…

da.Walk()函数接受两个参数,包括要检索的最高级别工作空间(当前工作目录)以及用于过滤返回列表的数据类型。在这种情况下,我们只检索与要素类相关的文件。Walk()函数返回一个包含目录路径、目录名称和文件名的元组。

第九章。列出和描述 GIS 数据

在本章中,我们将介绍以下食谱:

  • 使用 ArcPy 列表函数

  • 获取要素类或表中的字段列表

  • 使用 Describe() 函数返回关于要素类的描述信息

  • 使用 Describe() 函数返回栅格图像的描述信息

简介

Python 通过脚本提供批量处理数据的能力。这有助于您自动化工作流程并提高数据处理效率。例如,您可能需要遍历磁盘上的所有数据集并对每个数据集执行特定操作。第一步通常是先进行初步的数据收集,然后再进行地理处理任务的主要部分。这种初步的数据收集通常是通过使用 ArcPy 中找到的一个或多个列表方法来完成的。这些列表作为真正的 Python 列表对象返回。然后,这些列表对象可以用于进一步处理。ArcPy 提供了许多用于生成数据列表的函数。这些方法适用于许多不同类型的 GIS 数据。在本章中,我们将检查 ArcPy 提供的许多用于创建数据列表的函数。在 第二章 中,管理地图文档和图层,我们也介绍了一些列表函数。然而,这些函数与使用 arcpy.mapping 模块有关,特别是用于处理地图文档和图层。本章中我们介绍的列表函数直接位于 ArcPy 中,并且更具有通用性。

我们还将介绍 Describe() 函数,以返回包含属性组的动态对象。这些动态生成的 Describe 对象包含依赖于所描述数据类型的属性组。例如,当 Describe() 函数针对要素类运行时,将返回特定于要素类的属性。此外,所有数据,无论数据类型如何,都会获得一组通用属性,我们将在稍后讨论。

使用 ArcPy 列表函数

获取数据列表通常是多步骤地理处理操作的第一步。ArcPy 提供了许多列表函数,您可以使用它们收集信息列表,无论是要素类、表、工作空间等。在收集数据列表后,您通常会对列表中的项目执行地理处理操作。例如,您可能希望向文件地理数据库中的所有要素类添加新字段。为此,您首先需要获取工作空间中所有要素类的列表。在本食谱中,您将通过使用 ListFeatureClasses() 函数来学习如何使用 ArcPy 中的列表函数。所有 ArcPy 列表函数的工作方式相同。

准备工作

ArcPy 提供了获取字段列表、索引、数据集、特征类、文件、栅格、表格等列表的函数。所有列表函数执行相同类型的基本操作。ListFeatureClasses()函数可用于生成工作空间中所有特征类的列表。ListFeatureClasses()函数有三个可选参数可以传递给函数,这些参数将用于限制返回的列表。第一个可选参数是一个通配符,可用于根据名称限制返回的特征类,第二个可选参数可用于根据数据类型(如点、线、多边形等)限制返回的特征类。第三个可选参数通过特征数据集限制返回的特征类。在本菜谱中,您将学习如何使用ListFeatureClasses()函数返回特征类列表。您还将学习如何限制返回的列表。

如何操作…

按照以下步骤学习如何使用ListFeatureClasses()函数检索工作空间中的特征类列表:

  1. 打开IDLE并创建一个新的脚本窗口。

  2. 将脚本保存为C:\ArcpyBook\Ch9\ListFeatureClasses.py。

  3. 导入arcpy模块:

    import arcpy
    
  4. 设置工作空间:

    arcpy.env.workspace = "C:/ArcpyBook/data/CityOfSanAntonio.gdb"
    

    注意

    您应该始终记住在调用使用 IDLE 或任何其他 Python 开发环境开发的脚本中的任何列表函数之前,使用环境设置设置工作空间。如果没有这样做,列表函数将不知道应该从哪个数据集中提取列表。如果在 ArcMap 中运行脚本,并且没有设置工作空间,它将返回默认地理数据库中的特征类。

  5. 调用ListFeatureClasses()函数并将结果分配给名为fcList的变量:

    fcList = arcpy.ListFeatureClasses()
    
  6. 遍历fcList中的每个特征类并将它们打印到屏幕上:

    for fc in fcList:
        print(fc)
    
  7. 您可以通过检查C:\ArcpyBook\code\Ch9\ListFeatureClasses_Step1.py解决方案文件来验证您的作品。

  8. 保存并运行脚本。您应该看到以下输出。

    Crimes2009
    CityBoundaries
    CrimesBySchoolDistrict
    SchoolDistricts
    BexarCountyBoundaries
    Texas_Counties_LowRes
    
    
  9. 通过传递给ListFeatureClasses()函数的第一个参数的通配符,可以限制由该函数返回的特征类列表。通配符用于根据名称限制列表的内容。例如,您可能只想返回以C开头的特征类列表。为了实现这一点,您可以使用星号与字符组合。更新ListFeatureClasses()函数以包含一个通配符,该通配符将找到所有以大写C开头并具有任意数量的字符的特征类:

    fcList = arcpy.ListFeatureClasses("C*")
    
  10. 您可以通过检查C:\ArcpyBook\code\Ch9\ListFeatureClasses_Step2.py解决方案文件来验证您的作品。

  11. 保存并运行脚本以查看以下输出:

    Crimes2009
    CityBoundaries
    CrimesBySchoolDistrict
    
    
  12. 除了使用通配符来限制 ListFeatureClasses() 函数返回的列表外,还可以应用类型限制,无论是与通配符结合使用还是单独使用。例如,您可以限制返回的特征类列表只包含以 C 开头且具有 polygon 数据类型的特征类。更新 ListFeatureClasses() 函数以包含一个通配符,该通配符将找到所有以大写 C 开头且具有多边形数据类型的特征类:

    fcs = arcpy.ListFeatureClasses("C*", "Polygon")
    
  13. 您可以通过检查 C:\ArcpyBook\code\Ch9\ListFeatureClasses_Step3.py 解决方案文件来验证您的作品。

  14. 保存并运行脚本。您将看到以下输出:

    CityBoundaries
    CrimesBySchoolDistrict
    
    

它是如何工作的…

在调用任何列表函数之前,您需要设置工作空间环境设置,该设置将当前工作空间设置为从中生成列表的工作空间。ListFeatureClasses() 函数可以接受三个可选参数,这些参数将限制返回的特征类。这三个可选参数包括通配符、特征类型和特征数据集。在这个配方中,我们应用了两个可选参数,包括通配符和特征类型。大多数其他列表函数的工作方式相同。参数类型将不同,但调用函数的方式基本上是相同的。

更多内容…

而不是返回工作空间中的特征类列表,您可能需要获取表列表。ListTables() 函数返回工作空间中的独立表列表。此列表可以通过名称或表类型进行筛选。表类型可以包括 dBase、INFO 和 ALL。列表中的所有值都是 string 数据类型,并包含表名。其他列表函数包括 ListFields()ListRasters()ListWorkspaces()ListIndexes()ListDatasets()ListFiles()ListVersions()

获取特征类或表中的字段列表

特征类和表包含一个或多个属性信息列。您可以通过 ListFields() 函数获取特征类中的字段列表。

准备工作

ListFields() 函数返回一个包含特征类或表中的每个字段的单个 Field 对象的列表。一些函数,如 ListFields()ListIndexes(),需要输入数据集来操作。您可以使用通配符或字段类型来约束返回的列表。每个 Field 对象包含各种只读属性,包括 NameAliasNameTypeLength 等。

如何做到这一点…

按照以下步骤学习如何返回特征类中的字段列表。

  1. 打开 IDLE 并创建一个新的脚本窗口。

  2. 将脚本保存为 C:\ArcpyBook\Ch9\ListOfFields.py

  3. 导入 arcpy 模块:

    import arcpy
    
  4. 设置工作空间:

    arcpy.env.workspace = "C:/ArcpyBook/data/CityOfSanAntonio.gdb"
    
  5. 在 try 块中对 Burglary 特征类调用 ListFields() 方法:

    try:
        fieldList = arcpy.ListFields("Burglary")
    
  6. 遍历字段列表中的每个字段,并打印出名称、类型和长度。确保根据需要缩进:

      for fld in fieldList:
        print("%s is a type of %s with a length of %i" % (fld.name, fld.type, fld.length))
    
  7. 添加 Exception 块:

    except Exception as e:
        print(e.message)
    
  8. 整个脚本应如下所示:

    import arcpy
    
    arcpy.env.workspace = "C:/ArcpyBook/data/CityOfSanAntonio.gdb"
    try:
       fieldList = arcpy.ListFields("Burglary")
       for fld in fieldList:
       print("%s is a type of %s with a length of %i" % (fld.name, fld.type, fld.length))
    except Exception as e:
        print(e.message)
    
  9. 您可以通过检查C:\ArcpyBook\code\Ch9\ListOfFields.py解决方案文件来检查您的工作。

  10. 保存并运行脚本。您应该看到以下输出:

    OBJECTID is a type of OID with a length of 4
    Shape is a type of Geometry with a length of 0
    CASE is a type of String with a length of 11
    LOCATION is a type of String with a length of 40
    DIST is a type of String with a length of 6
    SVCAREA is a type of String with a length of 7
    SPLITDT is a type of Date with a length of 8
    SPLITTM is a type of Date with a length of 8
    HR is a type of String with a length of 3
    DOW is a type of String with a length of 3
    SHIFT is a type of String with a length of 1
    OFFCODE is a type of String with a length of 10
    OFFDESC is a type of String with a length of 50
    ARCCODE is a type of String with a length of 10
    ARCCODE2 is a type of String with a length of 10
    ARCTYPE is a type of String with a length of 10
    XNAD83 is a type of Double with a length of 8
    YNAD83 is a type of Double with a length of 8
    
    

它是如何工作的...

ListFields()函数返回要素类或表中的字段列表。此函数接受一个必需参数,即函数应执行的要素类或表的引用。您可以使用通配符或字段类型来限制返回的字段。在本例中,我们仅指定了一个要素类,表示将返回所有字段。对于返回的每个字段,我们打印了名称、字段类型和字段长度。正如我之前在讨论ListFeatureClasses()函数时提到的,ListFields()和其他所有列表函数通常在脚本中的多步过程中作为第一步被调用。例如,您可能想更新包含在人口普查区要素类中的population字段的人口统计数据。为此,您可以获取要素类中所有字段的列表,通过查找包含有关人口信息的特定字段名称来遍历此列表,然后更新每行的人口信息。或者,ListFields()函数接受通配符作为其参数之一,因此如果您已经知道population字段的名称,您就可以将其作为通配符传递,这样只会返回单个字段。

使用Describe()函数返回关于要素类的描述性信息

所有数据集都包含描述性信息。例如,要素类具有名称、形状类型、空间参考等信息。在脚本中继续进一步处理之前,这些信息对于您寻找特定信息时非常有价值。例如,您可能只想在polyline要素类上执行缓冲区操作,而不是点或多边形。使用Describe()函数,您可以获取任何数据集的基本描述性信息。您可以将这些信息视为元数据。

准备工作

Describe()函数为您提供了获取数据集基本信息的功能。这些数据集可能包括要素类、表、ArcInfo 覆盖、图层文件、工作空间、栅格等。返回一个Describe对象,并包含基于描述的数据类型的特定属性。Describe对象上的属性组织到属性组中,所有数据集至少属于一个属性组。例如,对地理数据库执行Describe()操作将返回GDB FeatureClassFeatureClassTableDataset属性组。每个属性组都包含可以检查的特定属性。

Describe() 函数接受一个字符串参数,该参数是指向数据源的一个指针。在下面的代码示例中,我们传递一个包含在文件地理数据库中的要素类。该函数返回一个包含一组动态属性的 Describe 对象,这些属性被称为 属性组。然后我们可以像在这个例子中那样通过简单地使用打印函数打印属性来访问这些各种属性:

arcpy.env.workspace = "c:/ArcpyBook/Ch9/CityOfSanAntonio.gdb"
desc = arcpy.Describe("Schools")
print("The feature type is: " + desc.featureType)
The feature type is: Simple
print("The shape type is: " + desc.shapeType)
The shape type is: Polygon
print("The name is: " + desc.name)
The name is: Schools
print("The path to the data is: " + desc.path)
The path to the data is: c:/ArcpyBook/Ch9/CityOfSanAntonio.gdb

所有数据集,无论其类型如何,都包含在 Describe 对象上的一组默认属性。这些属性是只读的。一些更常用的属性包括 dataTypecatalogPathnamepathfile

在本例中,你将编写一个脚本,使用 Describe() 函数获取要素类的描述信息。

如何操作…

按照以下步骤学习如何获取要素类的描述信息:

  1. 打开 IDLE 并创建一个新的脚本窗口。

  2. 将脚本保存为 C:\ArcpyBook\Ch9\DescribeFeatureClass.py

  3. 导入 arcpy 模块:

    import arcpy
    
  4. 设置工作空间:

    arcpy.env.workspace = "C:/ArcpyBook/data/CityOfSanAntonio.gdb"
    
  5. 开始一个 try 块:

    try:
    
  6. Burglary 要素类上调用 Describe() 函数并打印出形状类型:

    descFC = arcpy.Describe("Burglary")
    print("The shape type is: " + descFC.ShapeType)
    
  7. 获取要素类中的字段列表并打印出每个字段的名称、类型和长度:

    flds = descFC.fields
    for fld in flds:
        print("Field: " + fld.name)
        print("Type: " + fld.type
        print("Length: " + str(fld.length))
    
  8. 获取要素类的地理范围并打印出定义范围的坐标:

    ext = descFC.extent
    print("XMin: %f" % (ext.XMin))
    print("YMin: %f" % (ext.YMin))
    print("XMax: %f" % (ext.XMax))
    print("YMax: %f" % (ext.YMax))
    
  9. 添加 Exception 块:

    except Exception as e:
        print(e.message)
    
  10. 整个脚本应该如下所示:

    import arcpy
    arcpy.env.workspace = "c:/ArcpyBook/data/CityOfSanAntonio.gdb"
    try:
        descFC = arcpy.Describe("Burglary")
        print("The shape type is: " + descFC.ShapeType)
        flds = descFC.fields
        for fld in flds:
            print("Field: " + fld.name)
            print("Type: " + fld.type)
            print("Length: " + str(fld.length))
        ext = descFC.extent
        print("XMin: %f" % (ext.XMin))
        print("YMin: %f" % (ext.YMin))
        print("XMax: %f" % (ext.XMax))
        print("YMax: %f" % (ext.YMax))
    except:
        print(arcpy.GetMessages())
    
  11. 你可以通过检查 C:\ArcpyBook\code\Ch9\DescribeFeatureClass.py 解决方案文件来检查你的工作。

  12. 保存并运行脚本。你应该看到以下输出:

    The shape type is: Point
    Field: OBJECTID
    Type: OID
    Length: 4
    Field: Shape
    Type: Geometry
    Length: 0
    Field: CASE
    Type: String
    Length: 11
    Field: LOCATION
    Type: String
    Length: 40
    .....
    .....
    XMin: -103.518030
    YMin: -6.145758
    XMax: -98.243208
    YMax: 29.676404
    
    

它是如何工作的…

对要素类执行 Describe() 操作,正如我们在脚本中所做的,返回一个 FeatureClass 属性组以及分别访问 TableDataset 属性组。除了返回 FeatureClass 属性组外,你还可以访问 Table 属性组。

Table 属性组非常重要,主要是因为它让你可以访问独立表或要素类中的字段。你还可以通过这个属性组访问表或要素类上的任何索引。Table 属性中的 Fields 返回一个包含每个要素类中 Field 对象的 Python 列表。每个字段都有许多只读属性,包括 namealiaslengthtypescaleprecision 等。最显然有用的属性是名称和类型。在这个脚本中,我们打印出了字段名称、类型和长度。注意使用 Python for 循环来处理 Python 列表中的每个 field

最后,我们通过使用Dataset属性组中的范围属性返回的Extent对象打印出了图层的地域范围。Dataset属性组包含许多有用的属性。也许,最常用的属性包括extentspatialReference,因为许多地理处理工具和脚本在执行过程中某个时刻都需要这些信息。您还可以获取datasetType和版本信息以及其他几个属性。

使用Describe()函数返回关于栅格图像的描述性信息

栅格文件也包含描述性信息,这些信息可以通过Describe()函数返回。

准备工作

栅格数据集也可以通过使用Describe()函数来描述。在这个菜谱中,您将通过返回其范围和空间参考来描述栅格数据集。Describe()函数包含对通用Dataset属性组的引用,同时也包含对数据集的SpatialReference对象的引用。然后可以使用SpatialReference对象来获取数据集的详细空间参考信息。

如何操作…

按照以下步骤学习如何获取关于栅格图像文件描述性信息的方法。

  1. 打开IDLE并创建一个新的脚本窗口。

  2. 将脚本保存为C:\ArcpyBook\Ch9\DescribeRaster.py

  3. 导入arcpy模块:

    import arcpy
    
  4. 设置工作空间:

    arcpy.env.workspace = "C:/ArcpyBook/data "
    
  5. 开始一个try块:

    try:
    
  6. 在栅格数据集上调用Describe()函数:

    descRaster = arcpy.Describe("AUSTIN_EAST_NW.sid")
    
  7. 获取栅格数据集的范围并打印出来:

    ext = descRaster.extent
    print("XMin: %f" % (ext.XMin))
    print("YMin: %f" % (ext.YMin))
    print("XMax: %f" % (ext.XMax))
    print("YMax: %f" % (ext.YMax))
    
  8. 获取对SpatialReference对象的引用并打印出来:

    sr = descRaster.SpatialReference
    print(sr.name)
    print(sr.type)
    
  9. 添加Exception块:

    except Exception as e:
        print(e.message)
    
  10. 整个脚本应如下所示:

    import arcpy
    arcpy.env.workspace = "c:/ArcpyBook/data"
    try:
        descRaster = arcpy.Describe("AUSTIN_EAST_NW.sid")
        ext = descRaster.extent
        print("XMin: %f" % (ext.XMin))
        print("YMin: %f" % (ext.YMin))
        print("XMax: %f" % (ext.XMax))
        print("YMax: %f" % (ext.YMax))
    
        sr = descRaster.SpatialReference
        print(sr.name)
        print(sr.type)
    except Exception as e:
        print(e.message)
    
  11. 您可以通过检查C:\ArcpyBook\code\Ch9\DescribeRaster.py解决方案文件来验证您的操作。

  12. 保存并运行脚本。您应该看到以下输出:

    XMin: 3111134.862457
    YMin: 10086853.262238
    XMax: 3131385.723907
    YMax: 10110047.019228
    NAD83_Texas_Central
    Projected
    
    

它是如何工作的…

这个菜谱与之前的菜谱非常相似。不同之处在于我们使用的是对栅格数据集的Describe()函数,而不是vector要素类。在这两种情况下,我们都使用范围对象返回了数据集的地理范围。然而,在脚本中,我们还获取了栅格数据集的SpatialReference对象,并打印出有关该对象的信息,包括其名称和类型。

第十章:使用插件自定义 ArcGIS 界面

在本章中,我们将介绍以下食谱:

  • 下载和安装 Python 插件向导

  • 创建按钮插件并使用 Python 插件模块

  • 安装和测试插件

  • 创建工具插件

简介

在本章中,我们将介绍使用 Python 创建插件的创建、测试、编辑和共享。插件提供了一种通过模块化代码库将用户界面项添加到 ArcGIS for Desktop 的方法,该代码库旨在执行特定操作。界面组件可以包括按钮、工具、工具栏、菜单、组合框、工具调色板和应用扩展。插件概念首次在 ArcGIS for Desktop 10.0 中引入,可以使用 .NET 或 Java 创建。然而,从 ArcGIS 10.1 的发布开始,现在可以使用 Python 创建插件。插件使用 Python 脚本和一个定义用户界面应如何显示的 XML 文件创建。

插件提供了一种简单的方法将用户界面自定义分发到最终用户。不需要安装程序。一个扩展名为 .esriaddin 的单个压缩文件被复制到一个知名文件夹中,然后 ArcGIS for Desktop 处理其余部分。为了进一步简化开发,Esri 提供了一个 Python 插件向导。您可以从 Esri 网站下载向导。我们将在本章的第一个食谱中这样做。

可以创建多种类型的插件。按钮和工具是最简单的插件类型,您可以创建。按钮在点击时简单地执行业务逻辑。工具与按钮类似,但在执行业务逻辑之前需要与地图进行交互。组合框为用户提供了一组选项供选择。

此外,还有许多容器对象,包括菜单、工具栏、工具调色板和应用扩展。菜单充当按钮或其他菜单的容器。工具栏是按钮、工具、组合框、工具调色板和菜单的容器。它们是插件中最通用的容器类型。工具调色板也充当工具的容器,需要在工具暴露之前添加到工具栏中。最后,应用扩展是最复杂的插件类型。此类插件协调其他组件之间的活动,并负责监听和响应各种事件,例如从数据帧中添加或删除图层。

下载和安装 Python 插件向导

Esri 提供了一个工具,您可以使用它使插件的开发更容易。Python 插件向导可以从 Esri 网站下载,是创建插件的绝佳资源。

准备工作

Python 插件向导是一个创建插件所需文件的绝佳资源。它从可视化界面生成插件所需的文件。在本食谱中,您将下载并安装 Python 插件向导。

如何操作...

按照以下步骤学习如何下载和安装 Python 插件向导:

  1. 打开网页浏览器并导航到 www.arcgis.com/home/item.html?id=5f3aefe77f6b4f61ad3e4c62f30bff3b.

    您应该看到一个类似于以下截图的网页:

    如何操作…

  2. 点击 打开 按钮下载安装文件。

  3. 使用 Windows 资源管理器,在您的计算机上创建一个名为 Python Add-In Wizard 的新文件夹。文件夹的名称无关紧要,但为了简单易记,您应该选择 Python Add-In Wizard 或类似名称。

  4. 将文件解压到这个新文件夹中。有许多工具可以用来解压文件。它们的使用方法可能略有不同,但使用 WinZip,您应该可以右键单击文件并选择 解压

  5. 打开解压后的 bin 文件夹,双击 addin_assistant.exe 运行向导。在下面的截图中,我已经创建了一个名为 Python Add-In Wizard 的新文件夹,并解压了下载的文件。创建了 bin 文件夹,在这个文件夹中有一个名为 addin_assistant.exe 的文件:如何操作…

  6. 双击 addin_assistant.exe 将提示您选择一个目录作为插件项目根目录:如何操作…

工作原理…

Python 插件向导是一个可视化界面工具,您可以使用它为 ArcGIS for Desktop 创建插件。它通过点选工具大大简化了过程。在下一个菜谱中,您将使用向导创建基本的 ArcGIS for Desktop 插件。

创建按钮插件和使用 Python 插件模块

按钮 插件是最简单类型的插件,也是最常用的。使用按钮插件,您在脚本中编写的功能会在每次点击按钮时执行。

准备工作

创建插件项目是创建新插件的第一步。要使用 Python 插件向导创建项目,您需要选择一个工作目录,输入各种项目设置,然后点击 保存 按钮。插件的创建随后遵循一个定义良好的过程,如下面的截图所示:

准备工作

您必须首先为插件创建一个容器,这可以是工具栏或菜单的形式。接下来,创建按钮、工具或您想要添加到容器中的任何其他插件。在本例中,我们将创建一个按钮。然后,您需要编辑与按钮关联的 Python 脚本。您还希望测试按钮以确保它按预期工作。最后,您可以与他人共享插件。在本例中,您将学习如何使用插件向导创建 ArcGIS for Desktop 的按钮插件。按钮插件将执行使用pythonaddins模块的代码,以显示一个对话框,允许用户添加已经为数据框架创建的特征类。

如何操作...

按照以下步骤学习如何创建一个按钮插件:

  1. 通过双击位于您提取向导的bin文件夹中的addin_assistant.exe文件来打开 ArcGIS Python 插件向导。

  2. 创建一个名为Wildfire_Addin的新项目文件夹,并选择确定如何操作...

  3. 初始时应该激活项目设置选项卡,并显示您刚刚创建的工作目录。默认情况下,ArcMap应该是选定的产品,但您应该验证这一点:如何操作...

  4. 给您的项目起一个名字。我们将称之为Load Wildfire Data Addin如何操作...

  5. 默认情况下,版本0.1。如果您愿意,可以更改它。版本号应随着您更新或添加工具而更改。这有助于跟踪和共享您的插件:如何操作...

  6. 名称版本属性是仅有的两个必需属性。按照以下截图所示,添加公司、描述和作者信息是一个好习惯。添加您自己的信息:如何操作...

  7. 您可能还希望为插件添加一个图像。在C:\ArcpyBook\Ch10文件夹中提供了一个名为wildfire.png的文件用于此目的:如何操作...

  8. 插件内容选项卡用于定义可以创建的各种插件。在本步骤中,我们将创建一个工具栏,用于包含一个运行野火脚本的单一按钮插件,该脚本将fires从文本文件导入到特征类。单击插件内容选项卡:如何操作...

  9. 插件内容选项卡中,右键单击工具栏并选择新建工具栏。为工具栏提供一个标题,接受默认名称,并确保选中初始显示复选框:如何操作...

    虽然在功能上并没有做很多事情,但工具栏插件非常重要,因为它充当其他插件的容器,例如按钮、工具、组合框、工具板和菜单。工具栏可以是浮动的或固定的。使用Python 插件向导创建工具栏插件很容易。

  10. 点击保存按钮。

  11. 现在,我们将通过右键单击新的野火工具栏选项并选择新建按钮来添加一个按钮。

  12. 填写按钮的详细信息,包括标题类名ID(变量名)工具提示等。你还可以包括控件图像。在此情况下,我没有这样做,但你可以选择这样做。这些信息将保存到附加件的配置文件中:如何操作...

  13. 点击保存按钮。附加件有一个它们所附加的 Python 脚本。默认情况下,此文件将命名为 AddIns_addin.py,并位于你工作项目文件夹的 install 目录中。

  14. 我们已经创建了一个自定义的 ArcToolbox Python 脚本工具,该工具从包含野火数据的磁盘上的逗号分隔文本文件加载到要素类中。我们将在我们的附加件中使用此脚本的输出。在 Windows 资源管理器中,转到你之前创建的 addin 目录。它应该被称为 Wildfire_Addin。转到 Install 文件夹,你应该找到一个名为 WildfireAddin_addin.py 的文件。将此文件加载到你的 Python 编辑器中。

  15. 在这一步,我们将编写使用 pythonaddins 模块的代码,以打开一个对话框,允许你向选定的数据框添加一个或多个图层。pythonaddins 中的 OpenDialog()GetSelectedTOCLayerorDataFrame() 函数用于完成此任务。找到以下代码片段中显示的 onClick(self) 方法。此方法在按钮被点击时触发。从 onClick 事件中删除 pass 语句并添加以下代码:

    import arcpy
    import pythonaddins
    
    class ButtonClassImportWildfires(object):
        """Implementation for Wildfire_addin.button (Button)"""
        def __init__(self):
            self.enabled = True
            self.checked = False
        def onClick(self):
            layer_files = pythonaddins.OpenDialog('Select Layers to Add', True, r'C:\ArcpyBook\data\Wildfires', 'Add')
            mxd = arcpy.mapping.MapDocument('current')
            df = pythonaddins.GetSelectedTOCLayerOrDataFrame()
            if not isinstance(df, arcpy.mapping.Layer):
                for layer_file in layer_files:
                    layer = arcpy.mapping.Layer(layer_file)
                    arcpy.mapping.AddLayer(df, layer)
            else:
                pythonaddins.MessageBox('Select a data frame', 'INFO', 0)
    
  16. 保存文件。

  17. 你可以通过检查 C:\ArcpyBook\code\Ch10\WildfireAddIn.py 解决方案文件来检查你的工作。

在下一个菜谱中,你将学习如何安装你的新附加件。

它是如何工作的...

正如你在本菜谱中看到的,Python 附加件向导通过可视化界面处理附加件的创建。然而,在幕后,向导为附加件创建了一系列文件夹和文件。附加件文件结构实际上非常简单。两个文件夹和一组文件构成了附加件结构。你可以在以下屏幕截图中看到此结构:

它是如何工作的...

Images 文件夹包含插件使用的任何图标或其他图像文件。在本示例中,我们使用了 wildfire.png 图像。因此,此文件现在应在 Images 文件夹中。Install 文件夹包含处理插件业务逻辑的 Python 脚本。这是您将大量工作的文件,用于编写插件。它执行按钮、工具、菜单项等需要执行的所有业务逻辑。插件主文件夹中的 config.xml 文件定义用户界面和静态属性,例如名称、作者、版本等。可以双击 makeaddin.py 文件来创建 .esriaddin 文件,该文件将所有内容封装到一个带有 .esriaddin 扩展名的压缩文件中。这个 .esriaddin 文件将分发给最终用户,以便安装插件。

安装和测试插件

在分发插件给最终用户之前,您可能想要测试插件。要测试这些插件,您首先需要安装插件。

准备工作

在您的插件工作文件夹中,可以使用 makeaddin.py 脚本来将所有文件和文件夹复制到工作目录中的一个压缩插件文件夹中,该文件夹以 <working folder name>.esriaddin 文件格式命名。双击此 .esriaddin 文件以启动 Esri ArcGIS 插件安装实用程序,这将安装您的插件。然后您可以在 ArcGIS for Desktop 中测试插件。自定义工具栏或菜单可能已经可见并准备好测试。如果不可见,请转到自定义菜单并点击插件管理器插件管理器对话框列出了针对当前应用程序的已安装插件。插件信息,如名称、描述和图像,作为项目设置输入,应显示。

如何操作…

  1. 在您的插件主文件夹内部,将有一个名为 makeaddin.py 的 Python 脚本文件。此脚本创建 .esriaddin 文件。双击脚本以执行并创建 .esriaddin 文件。此过程在下面的截图中有说明:如何操作…

  2. 要安装 ArcGIS for Desktop 的插件,请双击 Widlfire_Add-In.esriaddin 文件,这将启动Esri ArcGIS 插件安装实用程序窗口,如下面的截图所示:如何操作…

  3. 点击安装插件。如果一切顺利,您应该看到以下消息:如何操作…

  4. 要测试插件,请打开ArcMap。您的插件可能已经处于活动状态。如果不是,请导航到自定义 | 插件管理器。这将显示插件管理器对话框,如下面的截图所示。您应该能够看到您创建的插件:如何操作…

  5. 如果需要,请选择自定义按钮。要将工具栏添加到应用程序中,请单击工具栏选项卡并选择您创建的工具栏:如何操作…

    插件现在应显示,如本截图所示:

    如何操作…

  6. 点击按钮,在显示的对话框中,导航到Wildfires图层,这些图层您之前在WildlandFires.mdb中创建。选择并添加到显示中:如何操作…

    在这里,您将看到从对话框中选择一个或多个图层后的输出:

    如何操作…

如何工作…

该实用程序将插件放置在 ArcGIS for Desktop 可发现的知名文件夹中。此文件夹的位置如下:

  • Windows 8: C:\Users\<用户名>\Documents\ArcGIS\AddIns\Desktop10.3

  • Vista/7: C:\Users\<用户名>\Documents\ArcGIS\AddIns\Desktop10.3

  • XP: C:\Documents and Settings\<用户名>\My Documents\ArcGIS\AddIns\Desktop10.3

在知名文件夹内将创建一个具有唯一全局唯一标识符GUID名称的文件夹。插件将驻留在该唯一文件夹名称内。以下截图展示了这一点。当 ArcGIS for Desktop 启动时,它将搜索这些目录并加载插件:

如何工作…

插件将类似于以下所示:

如何工作…

注意

默认插件文件夹位于您的用户账户中的ArcGIS文件夹内。例如,如果您的ArcGIS安装版本为 10.1,则插件在 Vista 或 Windows 7 操作系统上被复制到C:\users\<用户名>\Documents\ArcGIS\AddIns\Desktop10.1

您还可以使用私有网络驱动器向最终用户分发插件。ArcGIS for Desktop 中的Add-In Manager添加并维护可以搜索插件的文件夹列表。选择选项选项卡,然后选择添加文件夹以将网络驱动器添加到列表中。

创建工具插件

工具插件类似于按钮,但工具需要与地图进行某种类型的交互。例如,缩放工具就是一种工具。工具应放置在工具栏或工具调色板内。它们的属性类似于按钮。您还需要编辑 Python 脚本。

准备就绪

Tool类有几个属性,包括cursorenabledshapecursor属性设置工具被点击时的光标,并定义为对应于光标类型的整数值,如下所示:

准备就绪

默认情况下,工具是启用的。不过,可以通过将 enabled 属性设置为 false 来更改此设置。最后,shape 属性指定要绘制的形状类型,可以是线、矩形或圆形。这些属性通常在工具的构造函数中设置,该构造函数由 __init__ 方法定义,如下面的代码示例所示。self 对象指的是当前对象(在这种情况下是工具)并是一个引用当前对象的变量:

def __init__(self):
  self.enabled = True
  self.cursor = 3
  self.shape = 'Rectangle'

Tool 类相关联有许多函数。所有类都将有一个构造函数,用于定义类的属性。你之前已经看到了这个 __init__ 函数的例子。工具类中的其他重要函数包括 onRectangle()onCircle()onLine()。这些函数对应于使用工具在地图上绘制的形状。绘制的形状的几何形状被传递到函数中。还有许多鼠标和键盘函数可以使用。最后,当您想要停用工具时,可以调用 deactivate() 函数。

我们已经看到了 Tool 类的构造函数在行动中的样子。这个名为 __init__ 的函数用于在创建工具时设置各种属性。在这里,我们还展示了 Tool 类的 onRectangle() 函数。当在地图上绘制矩形时,会调用此函数。函数接收矩形的几何形状以及工具本身的引用:

def onRectangle(self, rectangle_geometry):

在本教程中,你将学习如何创建一个工具插件,该插件能够响应用户在地图上拖动矩形。该工具将使用 生成随机点 工具在矩形内生成点。

如何操作...

按照以下步骤使用 ArcGIS Python Add-In 向导 创建工具插件:

  1. 通过双击位于提取向导的 bin 文件夹中的 addin_assistant.exe 文件来打开 ArcGIS Python Add-In 向导

  2. 创建一个名为 Generate_Random_Points 的新项目文件夹,并选择 确定

  3. 项目设置 选项卡中输入属性,包括 名称版本公司描述作者如何操作...

  4. 点击 插件内容 选项卡。

  5. 右键单击 工具栏 并选择 新建工具栏

  6. 将工具栏的标题设置为 随机点工具栏

  7. 右键单击新创建的 随机点工具栏 并选择 新建工具

  8. 按照以下截图所示输入工具项:如何操作...

  9. 点击 保存。这将生成插件的文件夹和文件结构。

  10. 前往新插件的 Install 文件夹,并在 IDLE 中打开 GenerateRandomPoints_addin.py 文件。

  11. 将以下代码添加到 __init__ 函数中,这是工具的构造函数:

    def __init__(self):
      self.enabled = True
      self.cursor = 3
      self.shape = 'Rectangle'
    
  12. onRectangle() 函数中,编写代码以在屏幕上绘制的矩形内生成一组随机点:

    import arcpy
    import pythonaddins
    
    def __init__(self):
      self.enabled = True
      self.cursor = 3
      self.shape = 'Rectangle'
    
    def onRectangle(self, rectangle_geometry):
        extent = rectangle_geometry
        arcpy.env.workspace = r'c:\ArcpyBook\Ch10'
        if arcpy.Exists('randompts.shp'):
            arcpy.Delete_management('randompts.shp')
            randompts = arcpy.CreateRandomPoints_management(arcpy.env.workspace,'randompts.shp',"",rectangle_geometry)
            arcpy.RefreshActiveView()
        return randompts
    
  13. 保存文件。

  14. 你可以通过检查 C:\ArcpyBook\code\Ch10\GenerateRandomPoints_addin.py 解决方案文件来检查你的工作。

  15. 通过在插件的 main 文件夹中双击 makeaddin.py 文件来生成 .esriaddin 文件。

  16. 通过双击 GenerateRandom_Points.esriaddin 来安装插件。

  17. 打开 ArcMap 并添加 Generate Random Points 工具栏,如果需要的话。

  18. BexarCountyBoundaries 特征类从 C:\ArcpyBook\data\CityOfSanAntonio.gdb 添加。

  19. 通过在地图上拖动矩形来测试插件。输出应类似于以下截图。你的地图可能会有所不同,因为点是以随机方式生成的:如何做...

它是如何工作的...

工具插件与按钮插件非常相似,区别在于工具插件在触发功能之前需要与地图进行某种形式的交互。与地图的交互可以包括多种操作,例如点击地图、绘制多边形或矩形,或执行各种鼠标或键盘事件。Python 代码编写用于响应这些事件中的一个或多个。在本菜谱中,你学习了如何编写响应 onRectangle() 事件的代码。你还在插件的构造函数中设置了各种属性,包括 cursorshape,这些将在地图上绘制。

还有更多...

你可以创建许多额外的插件。ComboBox 插件提供了一个下拉列表,用户可以从中选择值,或者也可以在可编辑字段中输入新值。与其他插件一样,你首先需要使用 Python 插件向导创建一个新项目,添加一个新的工具栏,然后创建一个组合框添加到工具栏中。

工具调色板提供了一种将相关工具分组的方法。它需要添加到一个现有的工具栏中。默认情况下,工具将以网格状模式添加到调色板中。

Menu 插件充当按钮和其他菜单的容器。除了在 ArcGIS for Desktop 插件管理器中显示外,菜单还会在 ArcGIS for Desktop 的 自定义 对话框中显示。

应用程序扩展用于向 ArcGIS for Desktop 添加特定的一组相关功能。一些例子包括空间分析器、3D 分析器和商业分析师。通常,应用程序扩展负责监听事件并处理它们。例如,你可以创建一个应用程序扩展,每次用户将图层添加到地图时都会保存地图文档文件。应用程序扩展还协调组件之间的活动。

第十一章. 错误处理和故障排除

在本章中,我们将涵盖以下菜谱:

  • 探索默认的 Python 错误信息

  • 添加 Python 异常处理结构(try/except/else)

  • 使用 GetMessages() 获取工具消息

  • 通过严重程度过滤工具消息

  • 测试并响应特定错误信息

简介

在执行 ArcGIS 地理处理工具和函数的过程中,会返回各种消息。这些消息可能是信息性的,或者指示警告或错误条件,可能导致工具无法创建预期的输出,或者导致工具执行失败。这些消息不会以消息框的形式出现。相反,你需要使用各种 ArcPy 函数来检索它们。到目前为止,本书中我们忽略了这些消息、警告和错误的存在。这主要是因为我想让你集中学习一些基本概念,而不添加创建能够优雅处理错误情况的健壮地理处理脚本的必要代码复杂性。话虽如此,现在是时候学习如何创建地理处理和 Python 异常处理结构,这将使你能够创建灵活的地理处理脚本。这些脚本可以处理在脚本运行时生成的指示警告、错误和一般信息的消息。这些代码细节将帮助使你的脚本更加灵活,减少错误发生的可能性。你已经使用基本的 tryexcept 块执行了一些基本的错误处理。然而,在本章中,我们将更详细地介绍为什么以及如何使用这些结构。

探索默认的 Python 错误信息

默认情况下,Python 遇到脚本中的问题时会生成错误信息。这些错误信息并不总是对运行脚本的最终用户非常有信息量。然而,查看这些原始消息是有价值的。在后面的菜谱中,我们将使用 Python 错误处理结构来更清晰地查看错误并按要求做出响应。

准备工作

在本菜谱中,我们将创建并运行一个故意包含错误条件的脚本。我们不会在脚本中包含任何地理处理或 Python 异常处理技术。我们故意这样做,因为我们想让你看到 Python 返回的错误信息。

如何做…

按照以下步骤查看在脚本执行过程中工具执行时生成的原始 Python 错误信息:

  1. 打开 IDLE 并创建一个新的脚本。

  2. 将脚本保存到 C:\ArcpyBook\Ch11\ErrorHandling.py

  3. 导入 arcpy 模块:

    import arcpy
    
  4. 设置工作空间:

    arcpy.env.workspace = "c:/ArcpyBook/data"
    
  5. 调用 Buffer 工具。Buffer 工具需要一个缓冲距离作为其参数之一。在这个代码块中,我们故意省略了距离参数:

    arcpy.Buffer_analysis("Streams.shp","Streams_Buff.shp")
    
  6. 你可以通过检查 C:\ArcpyBook\code\Ch11\ErrorHandling1.py 解决方案文件来检查你的工作。

  7. 运行脚本。你应该看到以下错误消息:

    Runtime error Traceback (most recent call last): File "<string>", line 1, in <module> File "c:\program files (x86)\arcgis\desktop10.1\arcpy\arcpy\analysis.py", line 687, in Buffer  raise e ExecuteError: Failed to execute. Parameters are not valid. ERROR 000735: Distance [value or field]: Value is required Failed to execute (Buffer).
    
    

它是如何工作的…

这个输出错误消息并不十分有用。如果你是一个相当有经验的程序员,你通常能够在这个情况下弄清楚问题所在(它没有包括缓冲距离)。然而,在许多情况下,返回的错误消息不会给你提供多少你可以用来解决问题的信息。代码中的错误是编程生活中一个简单的事实。然而,你的代码如何响应这些错误,也称为异常,是非常重要的。你应该计划使用 Python 错误处理结构来优雅地处理错误,这些结构检查 arcpy 生成的异常并相应地采取行动。如果没有这些结构,你的脚本将立即失败,从而让用户感到沮丧。

添加 Python 异常处理结构(try/except/else)

Python 有内置的异常处理结构,允许你捕获生成的错误消息。使用这些错误信息,你可以向最终用户显示更合适的消息,并根据需要响应情况。

准备工作

异常是在你的代码中发生的异常或错误条件。Python 中的异常语句使你能够捕获和处理代码中的错误,从而让你能够优雅地从错误条件中恢复。除了错误处理之外,异常还可以用于各种其他事情,包括事件通知和处理特殊情况。

Python 异常以两种方式发生。Python 中的异常可以是捕获的或触发的。当你的代码中发生错误条件时,Python 会自动触发一个异常,这个异常可能被你的代码处理,也可能不被处理。作为程序员,你有责任捕获自动触发的异常。异常也可以通过你的代码手动触发。在这种情况下,你还需要提供一个异常处理例程来捕获这些手动触发的异常。你可以通过使用 raise 语句来手动触发一个异常。

try/except 语句是一个完整的、复合的 Python 语句,用于处理异常。这种 try 语句以一个 try 标题行开始,后面跟着一个缩进的语句块,然后是一个或多个可选的 except 子句,这些子句命名了要捕获的异常,以及一个可选的 else 子句在末尾。

try/except/else 语句的工作方式如下。一旦进入 try 语句,Python 会标记你处于 try 块中,并且知道在这个块中发生的任何异常条件都将被转发到各种 except 语句进行处理。

try块内的每个语句都会被执行。假设没有发生异常的条件,代码指针将跳转到else语句并执行else语句中包含的代码块,然后再移动到try块下面的下一行代码。如果在try块内部发生异常,Python 将搜索匹配的异常代码。如果找到匹配的异常,将执行except块内的代码块。然后代码再次出现在完整的try语句下面。在这种情况下,不会执行else语句。如果没有找到匹配的异常头,Python 将把异常传播到这个代码块上面的try语句。如果在整个过程中没有找到匹配的except头,异常将出现在进程的最顶层。这会导致未处理的异常,最终你会得到我们在本章第一个菜谱中看到的错误消息类型。这如图所示:

准备就绪

在这个菜谱中,我们将添加一些基本的 Python 异常处理结构。try/except/else/finally异常处理结构有多种变体。在这个菜谱中,我们将从一个非常简单的try/except结构开始。

如何操作...

按照以下步骤将 Python 错误处理结构添加到脚本中。

  1. 如果需要,打开C:\ArcpyBook\Ch11\ErrorHandling.py文件在IDLE中。

  2. 修改您的脚本以包含一个try/except块:

    import arcpy
    try:
      arcpy.env.workspace = "c:/ArcpyBook/data"
      arcpy.Buffer_analysis("Streams.shp","Streams_Buff.shp")
    except:
      print("Error")
    
  3. 您可以通过检查C:\ArcpyBook\code\Ch11\ErrorHandling2.py解决方案文件来检查您的工作。

  4. 保存并运行脚本。你应该会看到简单的Error消息。这并不比我们在第一个菜谱中收到的输出更有帮助。事实上,它甚至更不实用。然而,这个菜谱的目的仅仅是向您介绍try/except错误处理结构。

它是如何工作的...

这是一个极其简单的结构。try块表示try语句下面的所有缩进内容都将受到异常处理的影响。如果找到任何类型的异常,代码处理的控制将跳转到except部分并打印错误消息(在这种情况下是简单的Error)。正如我提到的,这对用户来说几乎没有任何信息量,但希望这能给你一个基本的想法,了解try/except块是如何工作的,并且作为程序员,你会更好地理解用户报告的任何错误。在下一个菜谱中,你将学习如何向这个结构添加工具生成的消息。

还有更多...

另一种类型的 try 语句是 try/finally 语句,它允许执行最终化操作。当在 try 语句中使用 finally 子句时,其语句块始终在最后执行,无论是否发生错误条件。这就是 try/finally 语句的工作方式:如果发生异常,Python 将运行 except 块,然后运行 finally 块。如果在执行过程中没有发生异常,Python 将运行 try 块,然后运行 finally 块。这在您想要确保代码块运行后执行某个操作时非常有用,无论是否发生错误条件。

使用 GetMessages() 获取工具消息

ArcPy 包含一个 GetMessages() 函数,您可以使用它来检索在执行 ArcGIS 工具时生成的消息。消息可以包括信息性消息,例如工具执行的开始和结束时间,以及警告和错误,这些可能导致结果不如预期或工具执行失败。

准备工作

在工具执行期间,会生成各种消息。这些消息包括信息性消息,例如工具执行的开始和结束时间,传递给工具的参数值以及进度信息。此外,工具还可以生成警告和错误。这些消息可以通过您的 Python 脚本读取,并且您的代码可以设计为适当地处理已生成的任何警告或错误。

ArcPy 存储了最后执行的工具的消息,您可以使用 GetMessages() 函数检索这些消息,该函数返回一个包含最后执行的工具的所有消息的单个字符串。您可以根据严重性过滤此字符串,以返回仅包含某些类型的消息,例如警告或错误。第一条消息将始终包含执行的工具的名称,最后一条消息是开始和结束时间。

在这个菜谱中,您将在 except 语句中添加一行代码,这将打印有关当前工具运行的更多描述性信息。

如何操作…

按照以下步骤学习如何将 GetMessages() 函数添加到您的脚本中,以便从最后执行的工具生成消息列表:

  1. 如果需要,在 IDLE 中打开 C:\ArcpyBook\Ch11\ErrorHandling.py 文件。

  2. 修改您的脚本以包含 GetMessages() 函数:

    import arcpy
    try:
      arcpy.env.workspace = "c:/ArcpyBook/data"
      arcpy.Buffer_analysis("Streams.shp","Streams_Buff.shp")
    except:
      print(arcpy.GetMessages())
    
  3. 您可以通过检查 C:\ArcpyBook\code\Ch11\ErrorHandling3.py 解决方案文件来检查您的工作。

  4. 保存并运行脚本。这次,错误消息应该更加详细。同时请注意,还会生成其他类型的消息,包括脚本执行的开始和结束时间:

    Executing: Buffer c:/ArcpyBook/data\Streams.shp c:/ArcpyBook/data\Streams_Buff.shp # FULL ROUND NONE #
    Start Time: Tue Nov 13 22:23:04 2012
    Failed to execute. Parameters are not valid.
    ERROR 000735: Distance [value or field]: Value is required
    Failed to execute (Buffer).
    Failed at Tue Nov 13 22:23:04 2012 (Elapsed Time: 0.00 seconds)
    
    

它是如何工作的…

GetMessages() 函数返回最后运行的工具生成的所有消息。我想强调的是,它只返回最后运行的工具的消息。如果您有一个运行多个工具的脚本,请记住这一点。历史工具消息无法通过此函数访问。然而,如果您需要检索历史工具消息,可以使用一个 Result 对象。

通过严重程度过滤工具消息

如我在上一道菜谱中提到的,所有工具都会生成一些可以被分类为信息、警告或错误信息的消息。GetMessages() 方法接受一个参数,允许您过滤返回的消息。例如,您可能对脚本中的信息性或警告性消息不感兴趣。然而,您肯定会对错误消息感兴趣,因为它们表明了一个致命错误,这将阻止工具成功执行。使用 GetMessages(),您可以过滤返回的消息,只包括错误消息。

准备工作

消息被分类为三种类型之一,这由严重程度级别指示。信息性消息提供了有关事物描述性的信息,例如工具的进度、工具的开始和结束时间、输出数据特征等。信息性消息的严重程度由 0 的值表示。警告消息在执行过程中发生问题时生成,可能会影响输出。警告用严重程度级别 1 表示,通常不会阻止工具运行。最后一种消息是错误消息,由 2 的数值表示。这些指示阻止工具运行的事件。在工具执行过程中可能会生成多个消息,这些消息存储在列表中。有关消息严重程度的更多信息,请参阅以下图像。在本菜谱中,您将学习如何过滤 GetMessages() 函数生成的消息:

准备工作

如何操作…

通过严重程度过滤工具返回的消息实际上非常简单。您只需提供您想要返回的严重程度级别作为 GetMessages() 函数的参数。

  1. 如果需要,在 IDLE 中打开 C:\ArcpyBook\Ch11\ErrorHandling.py 文件。

  2. 修改 GetMessages() 函数,使其只传递一个值为 2 的参数:

    import arcpy
    try:
      arcpy.env.workspace = "c:/ArcpyBook/data"
      arcpy.Buffer_analysis("Streams.shp","Streams_Buff.shp")
    except:
      print(arcpy.GetMessages(2))
    
  3. 您可以通过检查 C:\ArcpyBook\code\Ch11\ErrorHandling4.py 解决方案文件来检查您的作业。

  4. 保存并运行脚本以查看输出:

    Failed to execute. Parameters are not valid.
    ERROR 000735: Distance [value or field]: Value is required
    Failed to execute (Buffer).
    
    

工作原理…

如我之前提到的,GetMessages()方法可以接受012的整数参数。传递0表示应返回所有消息,而传递1表示你想看到警告。在我们的情况下,我们传递了2,这意味着我们只想看到错误消息。因此,你不会看到其他信息消息,例如脚本的开始和结束时间。

测试和响应特定错误消息

所有错误和警告都会生成一个特定的错误代码。你可以在脚本中检查特定的错误代码,并根据这些错误执行某些操作。这可以使你的脚本更加灵活。

准备中

地理处理工具生成的所有错误和警告都包含一个六位代码和描述。你的脚本可以测试特定的错误代码并相应地做出反应。你可以在 ArcGIS for Desktop 帮助系统中通过导航到地理处理 | 工具错误和警告来获取所有可用错误消息和代码的列表。这在上面的屏幕截图中有所说明。所有错误都有一个独特的页面,简要描述了错误代码:

准备中

如何操作...

按照以下步骤学习如何编写代码,以响应由地理处理工具执行生成的特定错误代码:

  1. 通过导航到开始 | 所有程序 | ArcGIS | ArcGIS for Desktop 帮助来打开 ArcGIS for Desktop 帮助系统。

  2. 导航到地理处理 | 工具错误和警告 | 工具错误 1-10000 | 工具错误和警告 701-800

  3. 选择000735::Value is required。这个错误表示工具所需的参数尚未提供。你会记得在运行此脚本之前,我们没有提供缓冲距离,因此生成的错误消息包含我们在帮助系统中查看的错误代码。在以下代码中,你可以找到错误消息的完整文本。注意错误代码:

    ERROR000735:Distance[valueorfield]:Valueisrequired
    
  4. 如果需要,在 IDLE 中打开C:\ArcpyBook\Ch11\ErrorHandling.py文件。

  5. 在你的脚本中,修改except语句,使其如下所示:

    import arcpy
    try:
      arcpy.env.workspace = "c:/ArcpyBook/data"
      arcpy.Buffer_analysis("Streams.shp", "Streams_Buff.shp")
    except:
      print("Error found in Buffer tool \n")
      errCode = arcpy.GetReturnCode(3)
      if str(errCode) == "735":
        print("Distance value not provided \n")
        print("Running the buffer again with a default valuevalue \n")
        defaultDistance = "100 Feet"
        arcpy.Buffer_analysis("Streams.shp", "Streams_Buff", defaultDistance)
        print("Buffer complete")
    
  6. 你可以通过检查C:\ArcpyBook\code\Ch11\ErrorHandling5.py解决方案文件来验证你的工作。

  7. 保存并运行脚本。你应该会看到各种消息打印出来,如下所示:

    Error found in Buffer tool
    Distance value not provided for buffer
    Running the buffer tool again with a default distance value
    Buffer complete
    
    

它是如何工作的...

在这个代码块中,你使用arcpy.GetReturnCode()函数来返回工具生成的错误代码。然后,使用if语句测试错误代码是否包含735值,这是表示工具未提供所需参数的代码。然后,你为缓冲距离提供了默认值,并再次调用Buffer工具,这次提供默认的缓冲值。

第十二章. 使用 Python 进行高级 ArcGIS

在本章中,我们将介绍以下菜谱:

  • 开始使用 ArcGIS REST API

  • 使用 Python 发送 HTTP 请求并解析响应

  • 使用 ArcGIS REST API 和 Python 获取图层信息

  • 使用 ArcGIS REST API 和 Python 导出地图

  • 使用 ArcGIS REST API 和 Python 查询地图服务

  • 使用 Esri 世界地理编码服务进行地理编码

  • 使用 FieldMap 和 FieldMappings

  • 使用 ValueTable 向工具提供多值输入

简介

在本章中,我们将介绍一些更高级的主题。具体来说,你将学习如何使用 Python 的requests模块访问 ArcGIS REST API。通过这样做,你将学习如何访问由 ArcGIS Server 和 ArcGIS Online 发布的数据和服务。Python 的requests模块包括允许你的脚本向 URL 端点提交请求并接收各种格式的响应的能力,包括流行的 JSON 格式。在本章的末尾,我们还将介绍几个 ArcPy 的相关主题,包括使用FieldMapFieldMappings对象合并数据集,以及处理具有接受多个输入能力的工具的ValueTables

开始使用 ArcGIS REST API

在我们深入编码之前,你需要了解一些 ArcGIS REST API 的基本概念。你需要特别了解如何构造 URL 和解释返回的响应。

准备工作

ArcGIS REST API 的所有资源和操作都通过端点层次结构公开,随着我们阅读本书的进程,我们将检查这些端点。现在,让我们检查你需要了解的具体步骤,以便通过 Python 向 API 提交请求。在这个菜谱中,你将学习如何使用 ArcGIS Server 的Services目录来构造 URL 请求。

如何操作…

我们将使用一个公开可用的 ArcGIS Server 实例来学习如何使用Services目录中提供的工具来构造 URL 请求:

  1. 打开一个网络浏览器(最好是 Google Chrome 或 Firefox)。

  2. 前往sampleserver1.arcgisonline.com/arcgis/rest/services如何操作…

  3. 接下来,我们需要确定已知的端点。这代表了一个服务器目录,它是一组 ArcGIS Server 可以执行的操作以及特定的服务。导航到人口统计 | ESRI_Census_USA。这是一个已知的端点。如果你查看浏览器中的地址栏,你应该能看到这个:

    sampleserver1.arcgisonline.com/ArcGIS/rest/services/Demographics/ESRI_Census_USA/MapServer

    注意,这遵循了这里看到的模式:

    http://<host>/<site>/rest/services/<folder>/<serviceName>/<serviceType>

  4. 花些时间点击各种链接。在这样做的时候,注意地址栏中的 URL 如何变化。这个 URL 非常重要,因为它提供了您将通过 Python 请求提交的内容:如何操作…

  5. 接下来,您将学习如何进一步构建可以提交给 ArcGIS REST API 的 URL。这是一个非常重要的步骤。请求的语法包括资源的路径以及一个操作名称,后面跟着参数列表。操作名称指示将对资源执行的操作类型。例如,您可能希望将地图导出为图像文件。

  6. 问号开始参数列表。然后,每个参数都作为由 ampersand 分隔的键/值对提供。所有这些信息都组合成一个单一的 URL 字符串。以下 URL 说明了这一点:

    http://<资源 URL>/<操作>?<参数 1=值 1>&<参数 2=值 2>

    目前,我们只需将 URL 输入到浏览器的地址栏中。将 http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/Demographics/ESRI_Census_USA/MapServer/3/query?text=&geometry=&geometryType=esriGeometryPoint&inSR=&spatialRel=esriSpatialRelIntersects&relationParam=&objectIds=&where=name+%3D+%27Bexar%27&time=&returnCountOnly=false&returnIdsOnly=false&returnGeometry=true&maxAllowableOffset=&outSR=&outFields=&f=json 复制并粘贴到您的浏览器地址栏中。您可能想使用这本书的数字版本来复制和粘贴此 URL,而不是尝试将其键入到地址栏中。按回车键查看此输出:

    如何操作…

    您可以使用 Python 的 requests 模块来简化此过程,并在您的地理处理脚本中直接访问响应信息。requests 模块允许您将参数列表定义为 Python 字典,然后它将处理 URL 查询字符串的创建,包括 URL 编码。您将在本练习的末尾学习如何做到这一点。

  7. 服务目录包含您可以使用来生成参数值的对话框。您可以在服务页面底部找到这些对话框的链接。在您的浏览器中,导航到 sampleserver1.arcgisonline.com/ArcGIS/rest/services/Demographics/ESRI_Census_USA/MapServer/1

  8. 滚动到页面底部并点击 查询 链接以显示对话框,如图所示:如何操作…

  9. 添加一个 where 子句,如图所示。将 返回字段(逗号分隔) 设置为 POP2000, POP2007BLKGRP。将 格式 更改为 JSON 并将 返回几何形状 更改为 False。然后,点击 查询(GET)如何操作…

  10. 查询将会运行,并将返回以下结果:如何操作…

  11. 查看浏览器地址栏以查看生成的 URL:http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/Demographics/ESRI_Census_USA/MapServer/1/query?text=&geometry=&geometryType=esriGeometryPolygon&inSR=&spatialRel=esriSpatialRelIntersects&relationParam=&objectIds=&where=STATE_FIPS+%3D+%2748%27+and+CNTY_FIPS+%3D+%27021%27&time=&returnCountOnly=false&returnIdsOnly=false&returnGeometry=false&maxAllowableOffset=&outSR=&outFields=POP2000%2CPOP2007%2CBLKGRP&f=pjson

  12. 在即将到来的菜谱中,你将使用相同的 URL,提交请求,并使用 Python 处理结果。

它是如何工作的…

ArcGIS 服务器实例的服务目录提供了各种工具,你可以使用这些工具来生成 URL 请求并检查这些请求产生的响应。在这个菜谱中,你学习了如何使用查询任务来构建属性查询。在这个过程中,你学习了如何构建 URL 请求。

使用 Python 发送 HTTP 请求并解析响应

你可以使用许多 Python 模块来制作 REST 请求。实际上,太多了!模块包括urllib2httplib2pycurlrequests。在我看来,requests无疑是其中最好的。它更简洁,更容易用于与 RESTful API 的重复交互。一旦你发出了请求,你就可以使用 Python 的json模块来解析 JSON 响应。在这个菜谱中,你将学习如何做到这一点。

准备工作

Python 的requests模块可以用来向 ArcGIS 服务器资源提交请求并处理返回的响应。按照以下步骤学习使用requests模块提交请求和处理响应的基本步骤:

如何操作…

在我们开始之前,请确保你已经下载并安装了requests模块,使用pip。如果你还没有这样做,我提供了以下安装piprequests模块的说明:

注意

这个菜谱以及本章中随后的所有菜谱都使用 Python 的requests模块。如果你还没有在你的计算机上安装这个模块,你将需要现在安装它。requests模块是通过pip安装的,在安装requests模块之前需要在你的计算机上安装pip。Python 2.7.9(Python 2 系列)和 Python 3.4 的后续版本默认包含pip,所以你可能已经有了它。为了测试你是否已经安装了pip,你可以在 DOS 提示符下输入以下内容:

pip install requests

如果你没有安装pip,你会收到一个错误消息,你需要安装 pip(pip.pypa.io/en/latest/installing.html)。一旦安装,你可以使用前面的安装命令下载并安装requests模块。

  1. 打开IDLE(或另一个 Python 开发环境)并选择文件 | 新建窗口。将文件保存为C:\ArcpyBook\Ch12\ReqJSON.py

  2. 导入requestsjson模块:

    import requests
    import json
    
  3. 创建一个包含 ArcGIS Online 提供的服务列表的 URL 的新变量。此 URL 包含输出格式为pjson的输出,这是一个包含在美观格式中的 JSON 格式,以提供易于阅读性:

    import requests
    import json
    agisurl = "http://server.arcgisonline.com/arcgis/rest/services?f=pjson"
    
    
  4. 使用requests模块中的get()方法向 ArcGIS REST API 提交 HTTP 请求。您将响应存储在一个名为r的变量中:

    import requests
    import json
    agisurl = "http://server.arcgisonline.com/arcgis/rest/services?f=pjson"
    r = requests.get(agisurl)
    
    
  5. 现在,让我们打印出返回的响应:

    import requests
    import json
    agisurl = "http://server.arcgisonline.com/arcgis/rest/services?f=pjson"
    r = requests.get(agisurl)
    print(r.text)
    
    
  6. 保存您的脚本。

  7. 运行您的脚本,您将看到以下输出。这是由 ArcGIS REST API 返回的 JSON 响应:如何操作…

  8. 使用json.loads()方法将返回的json解析为 Python 字典对象。现在,请删除之前的打印语句:

    import requests
    import json
    agisurl = "http://server.arcgisonline.com/arcgis/rest/services?f=pjson"
    r = requests.get(agisurl)
    decoded = json.loads(r.text)
    print(decoded)
    
    
  9. 您可以通过检查C:\ArcpyBook\code\Ch12\ReqJSON.py解决方案文件来验证您的作品。

  10. 保存并运行您的脚本以查看输出。loads()方法已将json输出转换为 Python 字典:

    {u'folders': [u'Canvas', u'Demographics', u'Elevation', u'Ocean', u'Reference', u'Specialty', u'Utilities'], u'services': [{u'type': u'MapServer', u'name': u'ESRI_Imagery_World_2D'}, {u'type': u'MapServer', u'name': u'ESRI_StreetMap_World_2D'}, {u'type': u'GlobeServer', u'name': u'I3_Imagery_Prime_World'}, {u'type': u'GlobeServer', u'name': u'NASA_CloudCover_World'}, {u'type': u'MapServer', u'name': u'NatGeo_World_Map'}, {u'type': u'MapServer', u'name': u'NGS_Topo_US_2D'}, {u'type': u'MapServer', u'name': u'Ocean_Basemap'}, {u'type': u'MapServer', u'name': u'USA_Topo_Maps'}, {u'type': u'MapServer', u'name': u'World_Imagery'}, {u'type': u'MapServer', u'name': u'World_Physical_Map'}, {u'type': u'MapServer', u'name': u'World_Shaded_Relief'}, {u'type': u'MapServer', u'name': u'World_Street_Map'}, {u'type': u'MapServer', u'name': u'World_Terrain_Base'}, {u'type': u'MapServer', u'name': u'World_Topo_Map'}], u'currentVersion': 10.2}
    
    

它是如何工作的…

在这个简单的菜谱中,您学习了如何使用 Python requests模块通过requests.get()方法向 ArcGIS 服务器实例提交请求,然后处理来自服务器的响应。json.loads()方法用于将响应转换为 Python 字典对象,以便更容易处理。响应包含有关 ArcGIS 服务器实例的基本数据,包括文件夹、服务和版本。在接下来的菜谱中,我们将查看更复杂的示例。

使用 ArcGIS REST API 和 Python 获取图层信息

地图服务资源包含数据集,这些数据集可以包括表格或图层。它包含有关服务的基本信息,包括要素图层、表格和服务描述。在本菜谱中,您将学习如何使用 Python 和 ArcGIS REST API 从地图服务中返回图层信息。

准备工作

要获取地图服务中特定图层的信息,您需要引用与该图层关联的索引号。当您检查服务的服务目录页面时,您将找到一个列表,其中包含地图服务中的图层及其每个图层的索引号。索引号在请求图层信息时用于代替图层名称。正如我们在过去几个菜谱中所做的那样,我们将使用 Python requests模块来发出请求并处理响应。

如何操作…

按照以下步骤学习如何从地图服务中获取图层信息:

  1. 在 IDLE 或另一个 Python 开发环境中,创建一个名为GetLayerInformation.py的新 Python 脚本,并将其保存到C:\ArcpyBook\Ch12文件夹。

  2. 导入requestsjson模块:

    import requests
    import json
    
  3. 创建以下 agisurl 变量。这将成为引用 ESRI_CENSUS_USA 地图服务中特定层的基准 URL。在这里,我们引用了一个索引号为 1 的层。还包括一个输出格式 pjson

    import requests
    import json
    agisurl = "http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/Demographics/ESRI_Census_USA/MapServer/1?f=pjson"
    
    
  4. 创建一个 payload 变量。该变量将包含一个 Python 字典对象,其中包含作为请求一部分传递的参数。我们将包括一个 where 子句并设置一些其他属性:

    import requests
    import json
    
    agisurl = "http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/Demographics/ESRI_Census_USA/MapServer/1"
    payload = { 'where': 'STATE_FIPS = \'48\' and CNTY_FIPS = \'021\'','returnCountyOnly': 'false', 
    'returnIdsOnly': 'false', 'returnGeometry': 'false', 
    'f': 'pjson'}
    
    
  5. 调用 requests.get() 方法并传递 agisurl 变量。响应将存储在名为 r 的变量中:

    import requests
    import json
    agisurl = http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/Demographics/ESRI_Census_USA/MapServer/1?f=pjson
    payload = { 'where': 'STATE_FIPS = \'48\' and CNTY_FIPS = \'021\'','returnCountyOnly': 'false', \
                'returnIdsOnly': 'false', 'returnGeometry': 'false', \
                'f': 'pjson'}
    
    r = requests.get(agisurl, params=payload)
    
    
  6. 将 JSON 转换为 Python 字典:

    r = requests.get(agisurl, params=payload)
    decoded = json.loads(r.text)
    
  7. 打印出层的名称、地理范围和字段:

    r = requests.get(agisurl, params=payload)
    
    decoded = json.loads(r.text)
    
    print("The layer name is: " + decoded['name'])
    print("The xmin: " + str(decoded['extent']['xmin']))
    print("The xmax: " + str(decoded['extent']['xmax']))
    print("The ymin: " + str(decoded['extent']['ymin']))
    print("The ymax: " + str(decoded['extent']['ymax']))
    print("The fields in this layer: ")
    for rslt in decoded['fields']:
     print(rslt['name'])
    
    
  8. 您可以通过检查 C:\ArcpyBook\code\Ch12\GetLayerInformation.py 解决方案文件来验证您的作品。

  9. 保存脚本并运行它以查看以下输出:如何操作…

它是如何工作的…

在这个配方中,我们传递了一个包含指向地图服务中特定层路径的 URL 的引用。该层通过使用索引号(在这种情况下为 1)指定。此 URL 被传递给 Python requests.get() 方法。响应以 json 格式返回,然后我们将其转换为 Python 字典。该字典包含层的名称、范围和字段的键/值对。这些信息被打印到控制台。

使用 ArcGIS REST API 和 Python 导出地图

ArcGIS REST API 有一个庞大的操作集,您可以在请求 ArcGIS 服务器实例的信息时使用。例如,您可以导出地图、查询图层、地理编码地址等等。在这个配方中,您将学习如何从地图服务中导出地图图像。

准备工作

export 操作可用于从地图服务创建地图图像。此请求的响应包括图像的 URL、宽度、高度、范围和比例。在这个配方中,您将使用导出操作将地图导出为图像文件。

如何操作…

  1. 在您的 Python 开发环境中创建一个新的脚本,将其保存为 C:\ArcpyBook\Ch12\ExportMapToImage.py

  2. 导入 requestsjson 模块:

    import requests
    import json
    
  3. 创建一个新的变量 agisurl,分配 URL,并执行导出操作,如下所示:

    import requests
    import json
    agisurl = "http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/Specialty/ESRI_StateCityHighway_USA/MapServer/export"
    
    
  4. 创建一个新的字典对象,该对象将包含帮助定义查询字符串的键/值对。这些是传递给导出操作的参数:

    import requests
    import json
    agisurl = "http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/Specialty/ESRI_StateCityHighway_USA/MapServer/export"
    payload = { 'bbox':'-115.8,30.4, 85.5,50.5', 
     'size':'800,600', 
     'imageSR': '102004', 
     'format':'gif', 
     'transparent':'false', 
     'f': 'pjson'}
    
    
  5. 调用 requests.get() 方法,传递 URL 和 Python 字典参数。响应将存储在名为 r 的变量中:

    import requests
    import json
    agisurl = "http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/Specialty/ESRI_StateCityHighway_USA/MapServer/export"
    payload = { 'bbox':'-115.8,30.4, 85.5,50.5', 'size':'800,600', 'imageSR': '102004', 'format':'gif', 'transparent':'false', 'f': 'pjson'}
    r = requests.get(agisurl, params=payload)
    
    
  6. 打印出 response 对象的内容:

    import requests
    import json
    agisurl = "http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/Specialty/ESRI_StateCityHighway_USA/MapServer/export"
    payload = { 'bbox':'-115.8,30.4, 85.5,50.5', 
                'size':'800,600', 
                'imageSR': '102004', 
                'format':'gif', 
                'transparent':'false', 
                      'f': 'pjson'}
    r = requests.get(agisurl, params=payload)
    print(r.text)
    
    
  7. 您可以通过检查 C:\ArcpyBook\code\Ch12\ExportMapToImage.py 解决方案文件来验证您的作品。

  8. 保存并运行脚本,查看类似以下输出:如何操作…

  9. 将生成的 .gif 文件的 URL 复制并粘贴到浏览器地址栏中,然后在键盘上点击回车键查看文件:如何操作…

它是如何工作的…

ArcGIS REST API 中的导出操作可以用来从地图服务中导出图像文件。如果您检查sampleserver1.arcgisonline.com/ArcGIS/rest/services/Specialty/ESRI_StateCityHighway_USA/MapServer/export,这是我们用来生成本食谱中地图图像的,您会看到 URL 末尾的术语 export。这就是触发 export 操作执行的原因。除此之外,我们还在有效载荷变量中附加了一个边界框(地图范围)、大小、图像的空间参考和格式。

使用 ArcGIS REST API 和 Python 查询地图服务

ArcGIS REST API 中的 query 操作对地图服务执行查询并返回一个要素集。要素集包括用户请求的字段值,如果请求,还可以返回几何形状。

准备工作

在本食谱中,您将基于第一个食谱,在该食谱中,您使用 ArcGIS 服务页面对话框生成 URL 来生成结果。在本食谱中,您将使用 ArcGIS 服务器服务页面对话框生成一个查询地图服务层并返回结果的 URL 请求。您可能还记得 URL 是 http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/Demographics/ESRI_Census_USA/MapServer/1/query?text=&geometry=&geometryType=esriGeometryPolygon&inSR=&spatialRel=esriSpatialRelIntersects&relationParam=&objectIds=&where=STATE_FIPS+%3D+%2748%27+and+CNTY_FIPS+%3D+%27021%27&time=&returnCountOnly=false&returnIdsOnly=false&returnGeometry=false&maxAllowableOffset=&outSR=&outFields=POP2000%2CPOP2007%2CBLKGRP&f=pjson

现在,让我们学习如何使用 Python 提交此请求。

如何操作…

  1. 在 IDLE 或另一个 Python 开发环境中,创建一个新的 Python 脚本,命名为 QueryMapService.py,并将其保存到 C:\ArcpyBook\Ch12 文件夹。

  2. 在您的浏览器中,导航到:resources.arcgis.com/en/help/arcgis-rest-api/index.html#//02r3000000p1000000。这是对地图服务中图层执行 query 操作的 REST API 页面。当您滚动到 help 页面时,您应该看到与对话框生成的相同参数,例如 geometrygeometryTypeinSRspatialRelwhere 等。

  3. 在您的脚本中,导入 requestsjson 模块:

    import requests
    import json
    
  4. 创建以下 agisurl 变量。这将作为基 URL,引用 ESRI_Census_USA 地图服务中 census block group 层(在 URL 中通过标识符 1 识别)上的 query 操作:

    import requests
    import json
    agisurl = "http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/Demographics/ESRI_Census_USA/MapServer/1/query"
    
    
  5. 现在,创建一个 Python 字典对象,如下面的代码所示。我们将省略在对话框中没有定义或使用的某些参数。在这个例子中,我们只是创建一个属性查询,以便可以删除所有几何参数:

    import requests
    import json
    agisurl = "http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/Demographics/ESRI_Census_USA/MapServer/1/query"
    payload = { 'where':'STATE_FIPS = \'48\' and CNTY_FIPS =       \'021\'','returnCountOnly':'false',
    'returnIdsOnly': 'false', 'returnGeometry':'false', 
    'outFields':'POP2000,POP2007,BLKGRP',
    'f': 'pjson'}
    
    
  6. requests.get() 方法可以接受一个 Python 字典对象作为第二个参数。此字典定义了一组键/值对,有助于定义查询字符串。添加 requests.get() 方法:

    import requests
    import json
    agisurl = "http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/Demographics/ESRI_Census_USA/MapServer/1/query"
    payload = { 'where':'STATE_FIPS = \'48\' and CNTY_FIPS =       \'021\'','returnCountOnly':'false', \
    'returnIdsOnly': 'false', 'returnGeometry':'false', \
    'outFields':'POP2000,POP2007,BLKGRP', \
    'f': 'pjson'}
    r = requests.get(agisurl, params=payload)
    
    
  7. 包含一个 print 语句以打印返回的响应。

    import requests, json
    agisurl = "http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/Demographics/ESRI_Census_USA/MapServer/1/query"
    payload = { 'where':'STATE_FIPS = \'48\' and CNTY_FIPS =       \'021\'','returnCountOnly':'false', \
    'returnIdsOnly': 'false', 'returnGeometry':'false', \
    'outFields':'POP2000,POP2007,BLKGRP', \
    'f': 'pjson'}
    r = requests.get(agisurl, params=payload)
    print(r.text)
    
    
  8. 保存脚本并运行它以查看此输出:如何操作…

  9. 现在,将此 JSON 对象转换为 Python 字典。同时,注释掉您在上一步中添加的 print 语句:

    r = requests.get(agisurl, params=payload)
    #print(r.text)
    decoded = json.loads(r.text)
    
  10. json.loads() 方法返回的 Python 字典对象将包含 JSON 对象的内容。然后,您可以从中提取单独的数据元素。在这种情况下,我们想要提取返回的每个要素的属性(BLKGRPPOP2007POP2000)。我们可以通过以下代码来实现,您需要将其添加到脚本中:

    r = requests.get(agisurl, params=payload)
    #print(r.text)
    decoded = json.loads(r.text)
    for rslt in decoded['features']:
     print("Block Group: " + str(rslt['attributes']['BLKGRP']))
     print("Population 2000: " + str(rslt['attributes']['POP2000']))
     print("Population 2007: " + str(rslt['attributes']['POP2007']))
    
    
  11. 您可以通过检查 C:\ArcpyBook\code\Ch12\QueryMapService.py 解决方案文件来检查您的工作。

  12. 保存并执行您的脚本以查看这些结果:如何操作…

它是如何工作的…

在 ArcGIS REST API 中的 query 操作可以用来对 ArcGIS 服务器地图服务中的图层进行空间和属性查询。我们使用了 requests.get() 方法对 census block groups 图层进行属性查询。我们包含了各种参数,包括一个 where 子句,它将只返回 ST_FIPS 代码为 48CNTY_FIPS 代码为 021(德克萨斯州的贝克斯县)的记录。然后,将 response 对象转换为 Python 字典,并包含一个 for 循环来遍历返回的每条记录,并打印出区块组名称以及 2000 年和 2007 年的人口。

使用 Esri 世界地理编码服务进行地理编码

Esri 世界地理编码服务可以用于在支持的国家中查找地址和地点。此服务包含免费和付费操作。每次请求查找一个地址的 find 操作始终是免费服务。geocodeAddresses 操作接受一个地址列表进行地理编码,并且仅是付费服务。其他操作可以是免费或付费。如果您是临时使用这些操作,它们是免费的。临时意味着您不会存储结果以供以后使用。如果是这种情况,那么它是一个付费服务。在这个菜谱中,您将使用 Esri 世界地理编码服务来地理编码一个地址。

准备工作

ArcGIS REST API 的 find 操作可以用来查找单个地址的地理坐标。正如我们在过去几个菜谱中所做的那样,我们将使用 Python requests 模块来发出请求并处理响应。

如何操作…

  1. 在 IDLE 或其他 Python 开发环境中,创建一个名为 GeocodeAddress.py 的新 Python 脚本,并将其保存到 C:\ArcpyBook\Ch12 文件夹中。

  2. 导入 requestsjson 模块:

    import requests
    import json
    
  3. 创建以下 agisurl 变量。这将指向 Esri World Geocoding 服务和特定服务的 find 操作。同时,定义一个 Python 字典,它将包含要提交的地址和输出格式。如果您愿意,可以更改地址:

    import requests
    import json
    agisurl = "http://geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer/find"
    payload = { 'text': '1202 Sand Wedge, San Antonio, TX, 78258','f':'pjson'}
    
    
  4. 调用 requests.get() 方法并传递 URL 和参数。响应将存储在一个名为 r 的变量中。然后,将返回的 JSON 对象转换为 Python 字典:

    import requests
    import json
    agisurl = "http://geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer/find"
    payload = { 'text': '1202 Sand Wedge, San Antonio, TX, 78258','f':'pjson'}
    
    r = requests.get(agisurl, params=payload)
    
    decoded = json.loads(r.text)
    
    
  5. 打印一些结果:

    import requests
    import json
    agisurl = "http://geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer/find"
    payload = { 'text': '1202 Sand Wedge, San Antonio, TX, 78258','f':'pjson'}
    
    r = requests.get(agisurl, params=payload)
    
    decoded = json.loads(r.text)
    
    print("The geocoded address: " + decoded['locations'][0]['name'])
    print("The longitude: " + str(decoded['locations'][0]['feature']['geometry']['x']))
    print("The lattitude: " + str(decoded['locations'][0]['feature']['geometry']['y']))
    print("The geocode score: " + str(decoded['locations'][0]['feature']['attributes']['Score']))
    print("The address type: " + str(decoded['locations'][0]['feature']['attributes']['Addr_Type']))
    
    
  6. 您可以通过检查 C:\ArcpyBook\code\Ch12\GeocodeAddress.py 解决方案文件来检查您的作业。

  7. 保存脚本并运行,查看以下输出:

    The geocoded address: 1202 Sand Wedge, San Antonio, Texas, 78258
    The longitude: -98.4744442811
    The lattitude: 29.6618639681
    The geocode score: 100
    The address type: PointAddress
    
    

工作原理...

ArcGIS REST API 中的 find 操作可用于对单个地址执行地理编码操作。正如我们在过去几个配方中所做的那样,我们使用了 Python 的 requests.get() 方法来提交操作请求(在这种情况下为 find),并包括要地理编码的地址等参数。返回的响应包括地址的纬度和经度、地理编码分数和地址类型。

使用 FieldMap 和 FieldMappings

到目前为止,本章已介绍了如何使用 Python 与 ArcGIS REST API 访问 ArcGIS Server 服务。现在,我们将转换方向,回到 ArcPy 模块,并讨论 FieldMapFieldMappings 类。

准备工作

一个常见的 GIS 操作是将几个不同的数据集合并成一个更大区域的单个数据集。通常,要合并的数据集中的字段将是相同的,并且不会出现任何问题。然而,有时各种数据集的字段可能不匹配。在这种情况下,您需要将一个数据集中的字段与另一个数据集中的字段之间的关系进行映射。

准备工作

上述图示显示了用于定义字段映射的各种 ArcPy 类之间的关系。一个 FieldMap 对象包含字段定义和来自一个或多个表或要素类的输入字段列表,或提供字段值的要素类。您创建的每个 FieldMap 对象随后被添加到一个 FieldMappings 对象中,该对象作为这些对象的容器。最后,FieldMappings 对象可以被发送到各种地理处理工具,如 Merge 工具作为输入。

如何操作…

在本练习中,您将学习如何使用 FieldMap 和 FieldMappings 对象:

  1. 在 IDLE 或其他 Python 开发环境中,创建一个名为 UsingFieldMap.py 的新 Python 脚本,并将其保存到您的 C:\ArcpyBook\Ch12 文件夹中。

  2. 导入 arcpy:

    import arcpy
    
  3. 设置工作空间环境变量和一个指向输出要素类的变量:

    import arcpy
    
    arcpy.env.workspace = r"c:\ArcpyBook\data"
    outFeatureClass = r"c:\ArcpyBook\data\AllTracts.shp"
    
  4. 创建一个FieldMappings对象和三个FieldMap对象。FieldMap对象将持有州联邦信息处理标准FIPS)代码、县 FIPS 代码和地块字段的引用:

    arcpy.env.workspace = r"c:\ArcyBook\data"
    outFeatureClass = r"c:\ArcpyBook\data\AllTracts.shp"
    
    fieldmappings = arcpy.FieldMappings()
    fldmap_STFIPS = arcpy.FieldMap()
    fldmap_COFIPS = arcpy.FieldMap()
    fldmap_TRACT = arcpy.FieldMap()
    
    
  5. 获取当前工作空间中所有县多边形特征类的列表。每个县特征类都有一个名为STFID的字段,其中包含每个特征的州 FIPS 代码、县 FIPS 代码和一个地块。这些信息存储为一个长的字符串(例如48491020301),其中前两位是州代码,第三到第五位是县代码,其余字符是地块。作为合并操作的一部分,我们将提取每个单独的元素并将它们存储在单独的字段中:

    fieldmappings = arcpy.FieldMappings()
    fieldmap_STFIPS = arcpy.FieldMap()
    fieldmap_COFIPS = arcpy.FieldMap()
    fieldmap_TRACT = arcpy.FieldMap()
    
    #List all feature classes that start with 'County' and type Polygon
    fclss = arcpy.ListFeatureClasses("County*", "Polygon")
    
    
  6. 创建一个ValueTable对象来保存要合并的特征类。ValueTable作为一个容器对象。它将保存工作空间中每个特征类的映射信息。所有信息都从一个字段(STFID)中提取,但我们需要为STFIPSCOFIPSTRACT创建单独的FieldMap输入字段:

    fclss = arcpy.ListFeatureClasses("County*", "Polygon")
    
    vTab = arcpy.ValueTable()
    for fc in fclss:
     fieldmappings.addTable(fc)
     fldmap_STFIPS.addInputField(fc, "STFID")
     fldmap_COFIPS.addInputField(fc, "STFID")
     fldmap_TRACT.addInputField(fc, "STFID")
     vTab.addRow(fc)
    
    
  7. STFIPS字段添加内容。我们使用startTextPosition()函数从STFID列中提取前两个字符。第一个位置是0,因此我们需要使用setStartTextPosition(x,0)。在此步骤中,我们还定义了STFIPS FieldMap对象的输出字段,命名字段并定义输出字段名称:

    vTab = arcpy.ValueTable()
    for fc in fclss:
      fieldmappings.addTable(fc)
      fldmap_STFIPS.addInputField(fc, "STFID")
      fldmap_COFIPS.addInputField(fc, "STFID")
      fldmap_TRACT.addInputField(fc, "STFID")
      vTab.addRow(fc)
    
    # STFIPS field
    for x in range(0, fldmap_STFIPS.inputFieldCount):
     fldmap_STFIPS.setStartTextPosition(x, 0)
     fldmap_STFIPS.setEndTextPosition(x, 1)
    
    fld_STFIPS = fldmap_STFIPS.outputField
    fld_STFIPS.name = "STFIPS"
    fldmap_STFIPS.outputField = fld_STFIPS
    
    
  8. COFIPS字段添加内容。这三个字符的位置是从STFID列中提取的字符串的2-4位:

    # STFIPS field
    for x in range(0, fldmap_STFIPS.inputFieldCount):
      fldmap_STFIPS.setStartTextPosition(x, 0)
      fldmap_STFIPS.setEndTextPosition(x, 1)
    
    fld_STFIPS = fldmap_STFIPS.outputField
    fld_STFIPS.name = "STFIPS"
    fldmap_STFIPS.outputField = fld_STFIPS
    
    # COFIPS field
    for x in range(0, fldmap_COFIPS.inputFieldCount):
     fldmap_COFIPS.setStartTextPosition(x, 2)
     fldmap_COFIPS.setEndTextPosition(x, 4)
    
    fld_COFIPS = fldmap_COFIPS.outputField
    fld_COFIPS.name = "COFIPS"
    fldmap_COFIPS.outputField = fld_COFIPS
    
    
  9. TRACT字段添加内容:

    # COFIPS field
    for x in range(0, fldmap_COFIPS.inputFieldCount):
    	fldmap_COFIPS.setStartTextPosition(x, 2)
    	fldmap_COFIPS.setEndTextPosition(x, 4)
    
    fld_COFIPS = fldmap_COFIPS.outputField
    fld_STFIPS.name = "COFIPS"
    fldmap_COFIPS.outputField = fld_COFIPS
    
    # TRACT field
    for x in range(0, fldmap_TRACT.inputFieldCount):
     fldmap_TRACT.setStartTextPosition(x, 5)
     fldmap_TRACT.setEndTextPosition(x, 12)
    
    fld_TRACT = fldmap_TRACT.outputField
    fld_TRACT.name = "TRACT"
    fldmap_TRACT.outputField = fld_TRACT
    
    
  10. FieldMap对象添加到FieldMappings对象中:

    # TRACT field
    for x in range(0, fldmap_TRACT.inputFieldCount):
    	fldmap_TRACT.setStartTextPosition(x, 5)
    	fldmap_TRACT.setEndTextPosition(x, 12)
    
    fld_TRACT = fldmap_TRACT.outputField
    fld_TRACT.name = "TRACT"
    fldmap_TRACT.outputField = fld_TRACT
    
    #Add fieldmaps into the fieldmappings objec
    fieldmappings.addFieldMap(fldmap_STFIPS)
    fieldmappings.addFieldMap(fldmap_COFIPS)
    fieldmappings.addFieldMap(fldmap_TRACT)
    
    
  11. 运行Merge工具,传入vTab、输出特征类和fieldmappings对象:

    #Add fieldmaps into the fieldmappings objec
    fieldmappings.addFieldMap(fldmap_STFIPS)
    fieldmappings.addFieldMap(fldmap_COFIPS)
    fieldmappings.addFieldMap(fldmap_TRACT)
    
    arcpy.Merge_management(vTab, outFeatureClass,fieldmappings)
    print("Merge completed")
    
    
  12. 整个脚本应该如下所示:

    import arcpy
    
    Arcpy.env.workspace = r"c:\ArcyBook\data"
    outFeatureClass = r"c:\ArcpyBook\data\AllTracts.shp"
    
    fieldmappings = arcpy.FieldMappings()
    fldmap_STFIPS = arcpy.FieldMap()
    fldmap_COFIPS = arcpy.FieldMap()
    fldmap_TRACT = arcpy.FieldMap()
    
    #List all feature classes that start with 'County' and type Polygon
    fclss = arcpy.ListFeatureClasses("County*", "Polygon")
    
    vTab = arcpy.ValueTable()
    for fc in fclss:
      fieldmappings.addTable(fc)
      fldmap_STFIPS.addInputField(fc, "STFID")
      fldmap_COFIPS.addInputField(fc, "STFID")
      fldmap_TRACT.addInputField(fc, "STFID")
      vTab.addRow(fc)
    
    # STFIPS field
    for x in range(0, fldmap_STFIPS.inputFieldCount):
      fldmap_STFIPS.setStartTextPosition(x, 0)
      fldmap_STFIPS.setEndTextPosition(x, 1)
    
    fld_STFIPS = fldmap_STFIPS.outputField
    fld_STFIPS.name = "STFIPS"
    fldmap_STFIPS.outputField = fld_STFIPS
    
    # COFIPS field
    for x in range(0, fldmap_COFIPS.inputFieldCount):
      fldmap_COFIPS.setStartTextPosition(x, 2)
      fldmap_COFIPS.setEndTextPosition(x, 4)
    
    fld_COFIPS = fldmap_COFIPS.outputField
    fld_COFIPS.name = "COFIPS"
    fldmap_COFIPS.outputField = fld_COFIPS
    
    # TRACT field
    for x in range(0, fldmap_TRACT.inputFieldCount):
    	fldmap_TRACT.setStartTextPosition(x, 5)
    	fldmap_TRACT.setEndTextPosition(x, 12)
    
    fld_TRACT = fldmap_TRACT.outputField
    fld_TRACT.name = "TRACT"
    fldmap_TRACT.outputField = fld_TRACT
    
    #Add fieldmaps into the fieldmappings objec
    fieldmappings.addFieldMap(fldmap_STFIPS)
    fieldmappings.addFieldMap(fldmap_COFIPS)
    fieldmappings.addFieldMap(fldmap_TRACT)
    
    arcpy.Merge_management(vTab, outFeatureClass,fieldmappings)
    print("Merge completed")
    
  13. 您可以通过检查C:\ArcpyBook\code\Ch12\UsingFieldMap.py解决方案文件来检查您的工作。

  14. 保存脚本并运行它。

  15. 在 ArcMap 中添加由脚本创建的All_Tracts.shp文件。您应该看到一个合并后的县集合,如果您打开属性表,您将看到创建的新字段以及原始字段:如何操作…

  16. All_Tracts.shp文件的数据视图中,您现在应该看到一个单一的合并多边形层,如下面的截图所示。如何操作…

它是如何工作的…

ArcPy 模块中的FieldMapFieldMappings对象以及Merge工具,可用于需要合并具有不匹配字段的数据集的 GIS 操作。当您需要从较长的字符串值集中提取连续的字符串值序列时,也可以使用FieldMap对象。在本食谱中,您学习了如何使用FieldMap对象从单个字段中提取州、县和人口普查信息。我们创建了单独的FieldMap对象来保存这些信息,然后将它们添加到一个FieldMappings对象中,该对象随后被传递到Merge工具中,以创建一个新的图层,该图层包含三个不同的字段,用于保存这些信息。

使用 ValueTable 向工具提供多值输入

许多地理处理工具接受多个值的输入参数。例如,多环缓冲区工具接受多个缓冲距离,删除字段工具接受可以删除的多个字段,还有许多其他例子。在本食谱中,您将学习如何创建一个ValueTable对象,该对象作为工具的多值输入。

准备工作

有三种方式可以指定多值参数:作为 Python 列表、每个值由分号分隔的字符串,或 ArcPy ValueTable对象。在本食谱中,我们将查看如何使用ValueTable指定多值输入参数。

如何操作...

按以下步骤学习如何使用ValueTable向工具提交多个值:

  1. 打开IDLE(或您喜欢的 Python 开发环境)并创建一个名为ValueTable.py的新脚本。

  2. 导入arcpy并设置工作空间:

    import arcpy
    
    arcpy.env.workspace = r"c:\ArcyBook\data"
    
  3. 创建一个新的ValueTable对象:

    import arcpy
    
    arcpy.env.workspace = r"c:\ArcyBook\data"
    vTab = arcpy.ValueTable()
    
  4. 为表格创建三行并分配距离51020

    vTab = arcpy.ValueTable()
    vTab.setRow(0, "5")
    vTab.setRow(1, "10")
    vTab.setRow(2, "20")
    
  5. 定义输入要素类、输出要素类、距离和缓冲单元的变量。距离变量(dist)被创建为对已创建的ValueTable的引用:

    vTab = arcpy.ValueTable()
    vTab.setRow(0, "5")
    vTab.setRow(1, "10")
    vTab.setRow(2, "20")
    
    inFeature = 'Hospitals.shp'
    outFeature = 'HospitalMBuff.shp'
    dist = vTab
    bufferUnit = "meters"
    
  6. 调用MultipleRingBuffer工具并传递变量作为参数:

    inFeature = 'Hospitals.shp'
    outFeature = 'HospitalMBuff.shp'
    dist = vTab
    bufferUnit = "meters"
    
    arcpy.MultipleRingBuffer_analysis(inFeature, outFeature, dist, bufferUnit, '', 'ALL')
    print("Multi-Ring Buffer Complete")
    
  7. 您可以通过检查C:\ArcpyBook\code\Ch12\ValueTable.py解决方案文件来检查您的工作。

  8. 保存并运行脚本。检查输出以查看多个缓冲环。

工作原理...

ValueTable是一个简单的虚拟表,您可以用作接受多个值的工具的输入。在本食谱中,我们创建了一个ValueTable对象,添加了三个值,然后将此对象传递到MultipleRingBuffer工具中。MultipleRingBuffer工具使用这些信息根据ValueTable对象中提供的缓冲距离创建新的多边形图层。

第十三章:使用 ArcGIS Pro 中的 Python

在本章中,我们将介绍以下主题:

  • 在 ArcGIS Pro 中使用新的 Python 窗口

  • ArcGIS for Desktop 和 ArcGIS Pro 之间的编码差异

  • 为独立 ArcGIS Pro 脚本安装 Python

  • 将 ArcGIS for Desktop 的 Python 代码转换为 ArcGIS Pro

简介

在本章中,我们将简要介绍与在 ArcGIS Pro 中使用 Python 相关的几个概念。在 ArcGIS for Desktop 和 ArcGIS Pro 中使用 Python 之间存在许多相似之处,因此你到目前为止所学的知识几乎肯定可以迁移到新的 ArcGIS Pro 环境中。然而,ArcGIS for Desktop 和 ArcGIS Pro 之间也有一些差异,还有一个你可以使用的新 Python 窗口。

在 ArcGIS for Desktop 和 ArcGIS Pro 中使用 Python 之间存在一些差异。一般来说,你可以将差异归纳如下:

  • 功能性差异

  • 使用 Python 3 而不是版本 2

  • 不支持的数据格式

ArcGIS Pro 中 ArcPy 功能的变化包括移除一些地理处理工具,包括 Coverage、数据互操作性、地籍网、图表和追踪分析师工具箱。在其他工具箱中也有一些不可用的额外工具。未包含的地理处理工具的完整列表可以在pro.arcgis.com/en/pro-app/tool-reference/appendices/unavailable-tools.htm找到。

ArcGIS Pro 使用 Python 3.4 版本,而 ArcGIS for Desktop 10.3 使用 2.7 版本。这两个版本之间存在一些显著差异,并且它们是不兼容的。大部分语言是相同的,但与字符串、字典和其他对象相关的某些重大差异。

在新的 ArcGIS Pro 环境中,将不支持多种数据格式,包括个人地理数据库、栅格目录、几何网络、拓扑、图层和地图包等。如果你一直在 ArcGIS for Desktop 中使用这些数据格式之一,请记住它们不受支持,因此任何使用这些格式的脚本将无法执行。

在 ArcGIS Pro 中使用新的 Python 窗口

如果你一直在使用 ArcGIS for Desktop 中的 Python 窗口,那么你将非常熟悉 ArcGIS Pro 中的 Python 窗口。然而,两者之间有一些差异和一些改进。在本食谱中,你将学习如何使用 ArcGIS Pro 的 Python 窗口。

ArcGIS Pro 中的 Python 窗口在功能上与 ArcGIS for Desktop 中的窗口非常相似。它是一个集成工具,用于执行地理处理操作中的 Python 代码。使用 Python 窗口,你可以执行 Python 功能,包括 ArcPy、核心 Python 功能和第三方库。你可以在窗口中编写的 Python 代码可以保存或从现有的脚本源加载。自动完成功能使得完成编码操作变得更容易,包括调用工具和传递参数。在本菜谱中,你将学习如何使用 ArcGIS Pro 的 Python 窗口。

按照以下步骤学习如何使用 ArcGIS Pro 的 Python 窗口:

  1. 打开ArcGIS Pro并选择一个项目或创建一个新的项目。

  2. 在 ArcGIS Pro 中单击分析菜单项,然后选择Python工具,如图所示:使用 ArcGIS Pro 中的新 Python 窗口

  3. 这将在 ArcGIS Pro 窗口的底部显示Python窗口,如图所示:使用 ArcGIS Pro 中的新 Python 窗口

  4. Python 窗口可以被固定、取消固定和调整大小。

  5. ArcGIS Pro 中的 Python 窗口有两个基本部分:转储Python 提示。两者都在以下屏幕截图中显示。你将逐行在 Python 提示部分编写代码。转储部分提供了已执行的 Python 代码的记录。使用 ArcGIS Pro 中的新 Python 窗口

  6. 在输入一行代码后,你按下键盘上的Enter键,代码将被执行并移动到转储部分。打印消息作为错误写入转储窗口。输入以下代码行以导入 ArcPy 映射模块:

    import arcpy.mp as MAP
    
  7. ArcGIS Pro 的 Python 窗口具有代码自动完成功能,因此当你开始输入时,将提供各种匹配选项,以提供当前与所输入内容相匹配的选项。你可以从提供的列表中选择一个项目来完成输入。你可以通过在 Python 提示中输入arc来查看这一功能的说明。代码自动完成功能将提供两个选项:arcgisarcpy

  8. 你可以通过使用help()方法访问内置的帮助系统。输入help(arcpy.ListFeatureClasses())以查看提供的帮助文档的说明:使用 ArcGIS Pro 中的新 Python 窗口

  9. 你可以通过在转储部分右键单击并选择保存转储来保存你编写的任何 Python 代码。此外,你还可以通过在提示部分右键单击并选择加载代码将现有的 Python 脚本加载到窗口中。

ArcGIS Pro Python 窗口可用于编写基本的 Python 地理处理脚本、执行工具、访问 ArcPy 及其相关模块、Python 核心模块和第三方模块、加载和执行现有的 Python 脚本、保存 Python 脚本以供以后使用,以及获取 ArcPy 类和函数的帮助。但是,ArcGIS for Desktop 和 ArcGIS Pro 之间存在编码差异。

ArcGIS for Desktop 和 ArcGIS Pro 之间的编码差异

在本节中,我们将讨论 ArcGIS for Desktop 和 ArcGIS Pro 编写的 Python 代码之间的一些差异。幸运的是,差异并不多。

ArcPy 支持多种模块,包括数据访问、制图、空间分析、网络分析和时间模块。正如您已经学到的,要使用这些模块,您必须首先将它们导入到您的脚本中。对于这些模块中的大多数,您导入它们的方式将不取决于您是使用 ArcGIS for Desktop 还是 ArcGIS Pro。然而,在导入 ArcPy 制图模块时有一些差异。

在 ArcGIS Pro Python 环境中,您需要使用以下语法来导入制图模块。使用两个字符引用制图模块的方式与其他所有模块的导入方式一致:

import arcpy.mp

这与您在 ArcGIS for Desktop 中引用 ArcPy 制图模块的方式不同,如以下代码示例所示:

import arcpy.mapping

安装 Python 用于 ArcGIS Pro

你们中的许多人可能已经非常熟悉在独立环境中执行您的 Python ArcGIS for Desktop 地理处理脚本。这包括从集成开发环境(如 IDLE 作为计划任务)或从操作系统提示符中执行脚本。默认情况下,ArcGIS Pro 不包括此功能。ArcGIS Pro 包含一个嵌入的 Python 编辑器,允许您将代码作为脚本工具或地理处理工具在 Python 窗口中执行。但是,如果您需要能够从独立环境中访问 ArcGIS Pro 功能,您将需要从 My Esri (my.esri.com/#/downloads) 下载并安装一个 Python 设置文件。此安装文件将安装 Python 3.4.1 和 ArcGIS Pro 所需的其他要求。

将 ArcGIS for Desktop Python 代码转换为 ArcGIS Pro

如我在本章前面提到的,ArcGIS for Desktop 和 ArcGIS Pro 的 Python 代码之间没有太多差异。我们已经讨论了两者之间的主要差异。Python 的版本在 ArcGIS for Desktop 10.3 中有所不同,它运行 Python 2.7,而 ArcGIS Pro 1.0 运行 Python 3.4。这两个版本的 Python 不兼容,并且在将现有代码迁移到 ArcGIS Pro 时,您可以使用一些工具。

我们将要检查的第一个工具是 AnalyzeToolsForPro。这个地理处理工具可以在 Management 工具箱中找到。这个工具可以分析不支持 ArcGIS Pro 功能的 Python 脚本、自定义地理处理工具和工具箱。这个工具将识别任何不支持 ArcGIS Pro 的地理处理工具和环境设置,将 arcpy.mapping 替换为 arcpy.mp,以及任何不支持的数据格式,例如 ArcGIS Pro 不支持的个人地理数据库。对于与 Python 2 和 Python 3 相关的问题,该工具还使用 2to3 实用程序来识别任何 Python 特定问题。

以下是该工具的语法:

AnalyzeToolsForPro_management(input, {report})

该工具的输入可以是地理处理工具箱、Python 文件或工具名称,可选的报表参数是一个包含任何已识别问题的输出文本文件。

你还可以使用独立的 2to3 Python 工具,该工具可以识别与两种语言版本差异相关的任何 Python 特定编码问题。这是一个与 Python 2 和 3 安装一起提供的命令行实用程序。该实用程序可以在类似 C:\Python34\Tools\Scripts\2to3.pyC:\Python27\Tools\Scripts\2to3.py 的路径中找到。这不是一个完美的工具,但据估计可以识别大约 95% 的差异。

附录 A. 自动化 Python 脚本

在本章中,我们将涵盖以下主题:

  • 从命令行运行 Python 脚本

  • 使用 sys.argv[ ] 捕获命令行输入

  • 将 Python 脚本添加到批处理文件中

  • 安排批处理文件在指定时间运行

简介

Python 地理处理脚本可以在 ArcGIS 外部作为独立脚本或内部作为脚本工具执行。这两种方法都有其优缺点。到目前为止,本书中的所有脚本都是在 ArcGIS 内部作为脚本工具、从 Python 开发环境(如 IDLE)或 ArcGIS 中的 Python 窗口中运行的。然而,Python 脚本也可以从 Windows 操作系统命令行执行。命令行是一个可以输入命令的窗口,而不是 Windows 提供的常规点按操作。这种方法运行 Python 脚本对于安排脚本的执行很有用。你可能有很多理由想要安排你的脚本。许多地理处理脚本需要很长时间才能完全执行,需要定期在工作时间之外安排运行。此外,一些脚本需要定期执行(每天、每周、每月等),并且应该安排以提高效率。在本章中,你将学习如何从命令行执行脚本、将脚本放入批处理文件中,以及安排在指定时间执行脚本。请记住,任何从命令行运行的脚本仍然需要访问 ArcGIS for Desktop 许可证才能使用 arcpy 模块。

从命令行运行 Python 脚本

到目前为止,本书中您所有的 Python 脚本都是作为 ArcGIS 中的脚本工具或从 Python 开发环境中运行的。Windows 命令提示符提供了执行 Python 脚本的另一种方式。命令提示符主要用于执行作为批处理文件的一部分或作为计划任务运行的脚本。

准备工作

从命令提示符运行 Python 地理处理脚本有几个优点。这些脚本可以安排在非工作时间批量处理您的数据,以提高处理效率,并且由于内置的 Python 错误处理和调试功能,它们更容易调试。

在本食谱中,您将学习如何使用 Windows 命令提示符来执行 Python 脚本。您需要管理员权限才能完成此食谱,因此您可能需要联系您的信息技术支持团队以进行此更改。

如何操作…

按照以下步骤学习如何在 Windows 命令提示符中运行脚本:

  1. 在 Windows 中,导航到开始 | 所有程序 | 附件 | 命令提示符,这将显示与以下截图类似的窗口:如何操作…

    窗口将显示当前目录。您的目录可能会有所不同。让我们切换到本附录的目录。

  2. 输入cd c:\ArcpyBook\Appendix1

  3. 输入dir以查看文件和子目录的列表。您应该只看到一个名为ListFields.py的单个 Python 文件:如何操作…

  4. 您需要确保 Python 解释器可以从目录结构中的任何位置运行。按照以下截图所示,导航到开始 | 所有程序 | 附件 | 系统工具 | 控制面板如何操作…

  5. 点击系统和安全

  6. 点击系统

  7. 点击高级系统设置

  8. 系统属性对话框中,选择高级选项卡,然后点击环境变量按钮,如图所示:如何操作…

  9. 查找路径系统变量,如图所示,并点击编辑…如何操作…

  10. 检查整个文本字符串中是否存在C:\Python27\ArcGIS10.3目录。如果找不到文本字符串,请将其添加到末尾。确保在添加路径之前添加一个分号,如图所示。现在,当您在命令提示符中输入python时,它将遍历路径系统变量中的每个目录,检查是否存在名为python.exe的可执行文件。如何操作…

  11. 点击确定以关闭编辑系统变量对话框。

  12. 点击确定以关闭环境变量对话框。

  13. 点击确定以关闭系统属性对话框。

  14. 返回到命令提示符。

  15. 输入python ListFields.py。这将运行ListFields.py脚本。在短暂的延迟后,你应该看到以下输出:如何操作…

延迟是由导入arcpy模块的第一行代码引起的。

小贴士

考虑在import之前添加一个print语句,以通知用户延迟。

工作原理…

本菜谱中提供的ListFields.py脚本是一个简单的脚本,用于列出Burglary要素类的属性字段。脚本中的工作空间和要素类名称是硬编码的。输入python后跟脚本名称,在本例中为ListFields.py,将触发使用 Python 解释器执行脚本。如我之前提到的,此脚本中的工作空间和要素类名称是硬编码的。在下一个菜谱中,你将学习如何向脚本传递参数,以便你可以移除硬编码并使你的脚本更加灵活。

使用sys.argv[ ]捕获命令行输入

您可以通过允许脚本接受来自命令行的参数形式输入来使脚本更加灵活,而不是将脚本硬编码为特定数据集的路径。您可以使用 Python 的sys.argv[]对象捕获这些输入参数。

准备工作

Python 的sys.argv[]对象允许您在脚本执行时从命令行捕获输入参数。我们将通过一个示例来说明它是如何工作的。请看以下截图:

准备工作

每个单词必须由空格分隔。这些单词存储在一个以零为基础的列表对象中,称为sys.argv[]。在sys.argv[]对象中,通过0索引引用的列表中的第一个项目存储了脚本的名称。在这种情况下,它将是ListFields.py。每个后续的单词通过下一个整数引用。因此,第一个参数(c:\ArcpyBook\data)将存储在sys.argv[1]中,第二个参数(Burglaries.shp)将存储在sys.argv[2]中。sys.argv[]对象中的每个参数都可以在您的地理处理脚本中访问和使用。在本菜谱中,您将更新ListFields.py脚本,使其能够从命令行接受输入参数。

如何操作…

按照以下步骤创建一个 Python 脚本,该脚本可以使用sys.argv[]从命令行接受输入参数:

  1. 在 IDLE 中打开C:\ArcpyBook\Appendix1\ListFields.py

  2. 导入sys模块:

    import arcpy
    import sys
    
  3. 创建一个变量来保存将要传递到脚本中的工作空间:

    wkspace = sys.argv[1]
    
  4. 创建一个变量来保存将要传递到脚本中的要素类:

    fc = sys.argv[2]
    
  5. 更新设置工作空间和调用ListFields()函数的代码行:

    arcpy.env.workspace = wkspace
    fields = arcpy.ListFields(fc)
    

    您完成的脚本应如下所示:

    import arcpy
    import sys
    wkspace = sys.argv[1]
    fc = sys.argv[2]
    try:
      arcpy.env.workspace = wkspace
      fields = arcpy.ListFields(fc)
      for fld in fields:
        print(fld.name)
    except Exception as e:
      print(e.message)
    
  6. 您可以通过检查C:\ArcpyBook\code\Appendix1\ListFields_Step2.py解决方案文件来验证您的作品。

  7. 保存脚本。

  8. 如果需要,打开命令提示符并导航到C:\ArcpyBook\Appendix1

  9. 在命令行中键入以下内容并按 Enter 键:

    python ListFields.py c:\ArcpyBook\data Burglaries_2009.shp
    
  10. 再次,您应该会看到输出详细说明 Burglaries_2009.shp 文件的属性字段。不同之处在于您的脚本不再有硬编码的工作空间和要素类名称。现在您有一个更灵活的脚本,能够列出任何要素类的属性字段。

工作原理...

sys 模块包含一个名为 argv[] 的列表对象,用于存储 Python 脚本命令行执行的输入参数。列表中存储的第一个项目总是脚本的名称。因此,在这种情况下,sys.argv[0] 包含 ListFields.py。将两个参数传递到脚本中,包括工作空间和要素类。这些值分别存储在 sys.argv[1]sys.argv[2] 中。然后,将这些值分配给变量并在脚本中使用。

将 Python 脚本添加到批处理文件中

安排您的 Python 脚本在指定时间运行需要您创建包含一个或多个脚本和/或操作系统命令的批处理文件。然后可以将这些批处理文件添加到 Windows 计划任务中,以在特定时间间隔运行。

准备工作

批处理文件是包含运行 Python 脚本或执行操作系统命令的命令行序列的文本文件。它们具有 .bat 扩展名,Windows 识别为可执行文件。由于批处理文件仅包含命令行序列,因此可以使用任何文本编辑器编写,尽管建议您使用基本的文本编辑器,如记事本。这样做是为了避免包含由程序(如 Microsoft Word)有时插入的不可见特殊字符。在本食谱中,您将创建一个简单的批处理文件,该文件将导航到包含您的 ListFields.py 脚本的目录并执行它。

如何操作...

按照以下步骤创建批处理文件:

  1. 打开记事本。

  2. 将以下文本行添加到文件中:

    cd c:\ArcpyBook\Appendix1
    python ListFields.py c:\ArcpyBook\data Burglaries_2009.shp
    
  3. 将文件保存到您的桌面上,命名为 ListFields.bat。确保您将 另存为类型 下拉列表更改为 所有文件,否则您将得到一个名为 ListFields.bat.txt 的文件。

  4. 在 Windows 中,导航到您的桌面,双击 ListFields.bat 以执行命令序列。

  5. 执行过程中将显示命令提示符。命令执行完毕后,命令提示符将自动关闭。

工作原理...

Windows 将批处理文件视为可执行文件,因此双击文件将在新的命令提示符窗口中自动执行文件中包含的命令序列。所有的 print 语句都将写入窗口。命令执行完毕后,命令提示符将自动关闭。如果您需要跟踪输出,可以将这些语句写入输出日志文件。

更多内容...

批处理文件可以包含变量、循环、注释和条件逻辑。这些功能超出了本教程的范围。然而,如果你为你的组织编写和运行了许多脚本,花些时间学习更多关于批处理文件的知识是值得的。批处理文件已经存在很长时间了,因此关于这些文件的网上信息并不匮乏。有关批处理文件的更多信息,请参阅此主题的维基百科页面。

在指定时间安排批处理文件运行

一旦创建,你的批处理文件就可以使用 Windows 计划任务安排在指定时间运行。

准备工作

许多地理处理脚本需要花费大量时间,最好在非工作时间运行,这样它们可以充分利用系统资源,并为你腾出时间来专注于其他任务。在本教程中,你将学习如何使用 Windows 计划任务来安排批处理文件的执行。

如何操作...

按以下步骤使用 Windows 计划任务安排批处理文件:

  1. 通过导航到开始 | 所有程序 | 附件 | 系统工具 | 控制面板 | 管理工具来打开 Windows 计划任务。选择任务计划程序。计划任务应该会显示,如下面的截图所示:如何操作...

  2. 选择操作菜单项,然后选择创建基本任务以显示创建基本任务向导对话框,如下面的截图所示。

  3. 给你的任务命名。在这种情况下,我们将称之为从要素类列出字段。点击下一步如何操作...

  4. 选择任务执行的时间触发器。这可以,并且通常是一个基于时间的触发器,但也可以有其他类型的触发器,例如用户登录或计算机启动。在这种情况下,我们只需选择每日。点击下一步如何操作...

  5. 选择开始日期/时间和重复间隔。在下面的截图中,我选择了日期为12/3/2012,时间为凌晨 1:00:00,重复间隔为1天。因此,每天凌晨 1:00,这个任务将被执行。点击下一步如何操作...

  6. 选择启动程序作为操作:如何操作...

  7. 浏览到你的脚本并添加参数。点击下一步如何操作...

  8. 点击完成将任务添加到计划任务中:如何操作...

  9. 任务现在应该显示在活动任务列表中:如何操作...

工作原理...

Windows 任务计划程序跟踪所有活动任务,并在预定触发器被激活时处理这些任务的执行。在本配方中,我们已将任务计划为每天凌晨 1:00 执行。此时,我们创建的批处理文件将被触发,并在创建任务时指定的参数将被传递到脚本中。使用计划程序在非工作时间自动执行地理处理任务,无需 GIS 人员与脚本交互,这为您提供了更大的灵活性并提高了效率。您还可能希望考虑将 Python 脚本中的错误记录到日志文件中,以获取有关特定问题的更多信息。

附录 B. 每个 GIS 程序员都应该知道的五个 Python 配方

在本章中,我们将涵盖以下主题:

  • 从分隔符文本文件中读取数据

  • 发送电子邮件

  • 从 FTP 服务器检索文件

  • 创建 ZIP 文件

  • 读取 XML 文件

简介

在本章中,您将学习如何使用 Python 编写执行通用任务的脚本。这些任务,例如读取和写入分隔符文本文件、发送电子邮件、与 FTP 服务器交互、创建.zip文件以及读取和写入 JSON 和 XML 文件,都是常见的。每个 GIS 程序员都应该知道如何编写包含这些功能的 Python 脚本。

从分隔符文本文件中读取数据

使用 Python 进行文件处理是 GIS 程序员非常重要的一个主题。文本文件已被用作系统间数据交换的互交换格式。它们简单、跨平台且易于处理。逗号和制表符分隔的文本文件是文本文件中最常用的格式之一,因此我们将详细探讨可用于处理这些文件的 Python 工具。GIS 程序员的一个常见任务是读取包含xy坐标以及其他属性信息的逗号分隔的文本文件。然后,这些信息被转换为 GIS 数据格式,如 shapefile 或地理数据库。

准备工作

要使用 Python 内置的文件处理功能,您必须首先打开文件。一旦打开,文件内的数据将使用 Python 提供的函数进行处理,最后关闭文件。

小贴士

总是记得在完成时关闭文件。Python 并不一定为您关闭文件,因此您可能会耗尽资源或覆盖某些内容。此外,某些操作系统平台不允许同时以只读和写入方式打开同一文件。

在本配方中,您将学习如何打开、读取和处理逗号分隔的文本文件。

如何操作…

按照以下步骤创建一个读取逗号分隔的文本文件的 Python 脚本:

  1. 在您的C:\ArcpyBook\data文件夹中,您将找到一个名为N_America.A2007275.txt的文件。在文本编辑器中打开此文件。它应该如下所示:

    18.102,-94.353,310.7,1.3,1.1,10/02/2007,0420,T,72
    19.300,-89.925,313.6,1.1,1.0,10/02/2007,0420,T,82
    19.310,-89.927,309.9,1.1,1.0,10/02/2007,0420,T,68
    26.888,-101.421,307.3,2.7,1.6,10/02/2007,0425,T,53
    26.879,-101.425,306.4,2.7,1.6,10/02/2007,0425,T,45
    36.915,-97.132,342.4,1.0,1.0,10/02/2007,0425,T,100
    
    

    注意

    此文件包含与 2007 年某一天卫星传感器收集的野火事件相关的数据。每一行包含火灾的纬度和经度信息,以及额外的信息,包括日期和时间、卫星类型、置信值和其他细节。在这个菜谱中,您将只提取纬度、经度和置信值。第一个条目包含纬度,第二个条目包含经度,最后一个值包含置信值。

  2. 打开IDLE并创建一个名为C:\ArcpyBook\Appendix2\ReadDelimitedTextFile.py的文件。

  3. 使用 Python 的open()函数打开文件以读取它:

    f = open("c:/ArcpyBook/data/N_America.A2007275.txt','r')
    
  4. 添加一个for循环来迭代所有行:

    for fire in f:
    
  5. 使用split()函数将值拆分为一个列表,使用逗号作为分隔符。这个列表将被分配给一个名为lstValues的变量。确保将此行代码缩进到您刚刚创建的 for 循环中:

    lstValues = fire.split(",")
    
  6. 使用引用纬度、经度和置信值的索引值,创建新的变量:

    latitude = float(lstValues[0])
    longitude = float(lstValues[1])
    confid = int(lstValues[8])
    
  7. 使用print语句打印每个变量的值:

    print("The latitude is: " + str(latitude) + " The longitude is: " + str(longitude) + " The confidence value is: " + str(confid))
    
  8. 关闭文件:

    f.close()
    
  9. 整个脚本应如下所示:

    f = open('c:/ArcpyBook/data/N_America.A2007275.txt','r')
    for fire in f.readlines():
      lstValues = fire.split(',')
      latitude = float(lstValues[0])
      longitude = float(lstValues[1])
      confid = int(lstValues[8])
      print("The latitude is: " + str(latitude) + " The longitude is: " + str(longitude) + " The confidence value is: " + str(confid))
    f.close()
    
  10. 您可以通过检查C:\ArcpyBook\code\Appendix2`ReadDelimitedTextFile.py`解决方案文件来验证您的操作。

  11. 保存并运行脚本。您应该看到以下输出:

    The latitude is: 18.102 The longitude is: -94.353 The confidence value is: 72
    The latitude is: 19.3 The longitude is: -89.925 The confidence value is: 82
    The latitude is: 19.31 The longitude is: -89.927 The confidence value is: 68
    The latitude is: 26.888 The longitude is: -101.421 The confidence value is: 53
    The latitude is: 26.879 The longitude is: -101.425 The confidence value is: 45
    The latitude is: 36.915 The longitude is: -97.132 The confidence value is: 100
    
    

它是如何工作的...

Python 的open()函数创建一个文件对象,该对象作为您计算机上文件的链接。在读取或写入文件数据之前,您必须在文件上调用open()函数。open()函数的第一个参数是要打开的文件的路径。open()函数的第二个参数对应于一个模式,通常是读取(r)、写入(w)或追加(a)。r的值表示您希望以只读方式打开文件,而w的值表示您希望以写入方式打开文件。如果您以写入模式打开的文件已存在,它将覆盖文件中的任何现有数据,因此在使用此模式时要小心。追加(a)模式将以写入方式打开文件,但不会覆盖任何现有数据,而是将数据追加到文件末尾。因此,在这个菜谱中,我们以只读模式打开了N_America.A2007275.txt文件。

for循环内部,该循环用于逐行遍历文本文件中的每个值,使用split()函数将一行文本(以某种方式分隔)创建为一个列表对象。我们的文件是以逗号分隔的,因此我们可以使用split(",")。您也可以根据其他分隔符进行分割,例如制表符、空格或任何其他分隔符。由split()创建的这个新列表对象存储在一个名为lstValues的变量中。这个变量包含每个野火值。这在下图中得到了说明。您会注意到纬度位于第一个位置,经度位于第二个位置,依此类推。列表是从零开始的:

如何工作…

使用索引值(这些值引用纬度、经度和置信度值),我们创建了新的变量latitudelongitudeconfid。最后,我们打印出每个值。一个更健壮的地理处理脚本可能会使用InsertCursor对象将此信息写入要素类。我们实际上在第八章的先前的配方中做了这件事,使用 ArcPy 数据访问模块与要素类和表

使用readlines()函数将整个文件内容读入 Python 列表中是可能的,然后可以遍历。文本文件中的每一行都将成为列表中的一个唯一值。由于这个函数将整个文件读入列表中,因此在使用此方法时需要谨慎,因为大文件可能会引起显著的性能问题。

还有更多...

与读取文件实例类似,有几种方法可以将数据写入文件。write()函数可能是最容易使用的。它接受一个字符串参数并将其写入文件。writelines()函数可以用来将列表结构的内容写入文件。在将数据写入文本文件之前,您需要以写入或追加模式打开文件。

发送电子邮件

在某些情况下,您可能需要从 Python 脚本中发送电子邮件。这可能是一个长时间运行的地理处理操作成功完成或发生错误的警报的例子。在这些和其他情况下,发送电子邮件可能会有所帮助。

准备工作

通过 Python 脚本发送电子邮件需要您有权访问邮件服务器。这可能是一个公共电子邮件服务,如 Yahoo、Gmail 或其他服务。它也可以使用配置了应用程序的出站邮件服务器,例如 Microsoft Outlook。在任一情况下,您都需要知道电子邮件服务器的主机名和端口号。Python 的smtplib模块用于创建到邮件服务器的连接并发送电子邮件。

Python 的email模块包含一个Message类,它表示电子邮件消息。每个消息都包含标题和正文。这个类不能用来发送电子邮件,它只是处理其对象表示。在本食谱中,你将学习如何使用smtp类通过你的脚本发送包含附件的电子邮件。Message类可以使用message_from_file()message_from_string()函数解析字符流或包含电子邮件的文件。两者都将创建一个新的Message对象。可以通过调用Message.getpayload()来获取邮件的正文。

注意

我们在这个练习中使用 Google Mail 服务。如果你已经有了 Gmail 账户,那么只需简单地提供你的用户名和密码作为这些变量的值。如果你没有 Gmail 账户,你需要创建一个或使用不同的邮件服务来完成这个练习。Gmail 账户是免费的。Google 可能会阻止通过脚本发送电子邮件的尝试,所以如果你使用 Gmail,请注意这可能不会按预期工作。

如何做到这一点…

按照以下步骤创建一个可以发送电子邮件的脚本:

  1. 打开IDLE并创建一个名为C:\ArcpyBook\Appendix2\SendEmail.py的文件。

  2. 为了发送带有附件的电子邮件,你需要导入smtplib模块以及os模块,以及电子邮件模块中的几个类。将以下导入语句添加到你的脚本中:

    import smtplib
    from email.MIMEMultipart import MIMEMultipart
    from email.MIMEBase import MIMEBase
    from email.MIMEText import MIMEText
    from email import Encoders
    import os
    
  3. 创建以下变量,并将你的 Gmail 用户名和密码作为值分配。请记住,从你的 Python 脚本中发送电子邮件可能会引起问题,因为它需要你包含你的用户名和密码:

    gmail_user = "<username>"
    gmail_pwd = "<password>"
    

    小贴士

    注意,在脚本中包含电子邮件用户名密码是不安全的,因此你不会想在生产脚本中包含这些信息。有加密这些值的方法,但这超出了本食谱的范围。

  4. 创建一个新的 Python 函数mail()。这个函数将接受四个参数:tosubjecttextattach。每个参数都应该很容易理解。创建一个新的MIMEMultipart对象,并分配fromtosubject键。你也可以使用MIMEMultipart.attach()将电子邮件文本附加到这个新的msg对象上:

    def mail(to, subject, text, attach):
      msg = MIMEMultipart()
      msg['From'] = gmail_user
      msg['To'] = to
      msg['Subject'] = subject
    
      msg.attach(MIMEText(text))
    
  5. 将文件附加到电子邮件中:

      part = MIMEBase('application', 'octet-stream')
      part.set_payload(open(attach, 'rb').read())
      Encoders.encode_base64(part)
      part.add_header('Content-Disposition',
        'attachment; filename="%s"' % os.path.basename(attach))
      msg.attach(part)
    
  6. 创建一个新的 SMTP 对象,该对象引用 Google Mail 服务,传入用户名和密码以连接到邮件服务,发送电子邮件,并关闭连接:

      mailServer = smtplib.SMTP("smtp.gmail.com", 587)
      mailServer.ehlo()
      mailServer.starttls()
      mailServer.ehlo()
      mailServer.login(gmail_user, gmail_pwd)
      mailServer.sendmail(gmail_user, to, msg.as_string())
      mailServer.close()
    
  7. 调用mail()函数,传入电子邮件的收件人、电子邮件的主题、电子邮件文本和附件:

      mail("<email to send to>",
      "Hello from python!",
      "This is an email sent with python",
      "c:/ArcpyBook/data/bc_pop1996.csv")
    
  8. 整个脚本应该如下所示:

    import smtplib
    from email.MIMEMultipart import MIMEMultipart
    from email.MIMEBase import MIMEBase
    from email.MIMEText import MIMEText
    from email import Encoders
    import os
    
    gmail_user = "<username>"
    gmail_pwd = "<password>"
    
    def mail(to, subject, text, attach):
     msg = MIMEMultipart()
    
     msg['From'] = gmail_user
     msg['To'] = to
     msg['Subject'] = subject
    
     msg.attach(MIMEText(text))
    
     part = MIMEBase('application', 'octet-stream')
     part.set_payload(open(attach, 'rb').read())
     Encoders.encode_base64(part)
     part.add_header('Content-Disposition',
         'attachment; filename="%s"' % os.path.basename(attach))
     msg.attach(part)
    
     mailServer = smtplib.SMTP("smtp.gmail.com", 587)
     mailServer.ehlo()
     mailServer.starttls()
     mailServer.ehlo()
     mailServer.login(gmail_user, gmail_pwd)
     mailServer.sendmail(gmail_user, to, msg.as_string())
     mailServer.close()
    
    mail("<email to send to>", "Hello from python!", "This is an email sent with python", "bc_pop1996.csv")
    
  9. 你可以通过检查C:\ArcpyBook\code\Appendix2`SendEmail`.py 解决方案文件来检查你的工作。

  10. 保存并运行脚本。为了测试,我使用了我的个人 Yahoo 账户作为收件人。你会注意到我的收件箱中有一个来自我的 Gmail 账户的新消息;同时,注意附件:如何做到这一点…

工作原理...

传递给mail()函数的第一个参数是接收电子邮件的电子邮件地址。这可以是任何有效的电子邮件地址,但您可能希望提供一个您实际上可以检查的邮箱账户,以确保您的脚本运行正确。第二个参数是电子邮件的主题行。第三个参数是文本内容。最后一个参数是要附加到电子邮件上的文件的名称。在这里,我简单地定义了应该将bc_pop1996.csv文件附加到电子邮件中。您可以使用您有权访问的任何文件,但您可能只想使用这个文件进行测试。

我们然后在mail()函数内部创建一个新的MIMEMultipart对象,并分配fromtosubject键。您还可以使用MIMEMultipart.attach()将电子邮件的文本附加到这个新的msg对象上。然后,使用MIMEBase对象将bc_pop1996.csv文件附加到电子邮件上,并通过msg.attach(part)将其附加到电子邮件中。

到目前为止,我们已经探讨了如何发送基本的文本电子邮件。然而,我们想要发送一个包含文本和附件的更复杂的电子邮件消息。这需要使用 MIME 消息,它提供了处理多部分电子邮件的功能。MIME 消息需要在电子邮件的多个部分之间设置边界,并添加额外的标题来指定发送的内容。《MIMEBase类是Message的抽象子类,使得发送这种类型的电子邮件成为可能。由于它是一个抽象类,您不能创建这个类的实际实例。相反,您可以使用其子类之一,例如MIMETextmail()`函数的最后一步是创建一个新的 SMTP 对象,该对象引用 Google Mail 服务,传入用户名和密码以连接到邮件服务,发送电子邮件,然后关闭连接。

从 FTP 服务器检索文件

从 FTP 服务器检索文件进行处理的操作对于 GIS 程序员来说非常常见,可以使用 Python 脚本来自动化。

准备工作

通过ftplib模块连接到 FTP 服务器并下载文件是完成操作。通过 FTP 对象创建对 FTP 服务器的连接,该对象接受主机、用户名和密码来建立连接。一旦建立了连接,您就可以搜索并下载文件。

在这个菜谱中,您将连接到国家机构火灾中心事件FTP 站点,并下载一份科罗拉多州野火事件的 PDF 文件。在运行以下脚本之前,您需要通过gis.nwcg.gov/data_nifcftp.html创建一个用户名/密码。

如何操作...

按照以下步骤创建一个连接到 FTP 服务器并下载文件的脚本:

  1. 打开IDLE并创建一个名为C:\ArcpyBook\Appendix2\ftp.py的文件。

  2. 我们将连接到 NIFC 的 FTP 服务器。有关更多信息,请访问他们的网站 gis.nwcg.gov/data_nifcftp.html

  3. 导入 ftplibossocket 模块:

    import ftplib
    import os
    import socket
    
  4. 添加以下定义 URL、目录和文件名的变量:

    HOST = 'ftp.nifc.gov'
    USER = '<your username here>'
    PASSW = '<your password here>'
    DIRN = '/Incident_Specific_Data/2012 HISTORIC/ROCKY_MTN/Arapaho/GIS/20120629'
    FILE = '20120629_0600_Arapaho_PIO_0629_8x11_land.pdf'
    
  5. 添加以下代码块以创建连接。如果发生连接错误,将生成一条消息。如果连接成功,将打印成功消息:

    try:
    
      f = ftplib.FTP(HOST,USER,PASS)
    except (socket.error, socket.gaierror), e:
      print('ERROR: cannot reach "%s"' % HOST)
    print('*** Connected to host "%s"' % HOST)
    
  6. 添加以下代码块以匿名登录到服务器:

    try:
      f.login()
    except ftplib.error_perm:
      print('ERROR: cannot login')
      f.quit()
    print('*** Logged in ')
    
  7. 添加以下代码块以切换到我们 DIRN 变量中指定的目录:

    try:
      f.cwd(DIRN)
    except ftplib.error_perm:
      print('ERROR: cannot CD to "%s"' % DIRN)
      f.quit()
    print('*** Changed to "%s" folder' % DIRN)
    
  8. 使用 FTP.retrbinary() 函数检索 PDF 文件:

    try:
      f.retrbinary('RETR %s' % FILE,
         open(FILE, 'wb').write)
    except ftplib.error_perm:
      print('ERROR: cannot read file "%s"' % FILE)
      os.unlink(FILE)
    else:
      print('*** Downloaded "%s" to CWD' % FILE)
    
  9. 确保您从服务器断开连接:

    f.quit()
    
  10. 整个脚本应如下所示:

    import ftplib
    import os
    import socket
    
    HOST = 'ftp.nifc.gov'
    USER = '<your username here>'
    PASSW = '<your password here>'
    DIRN = '/Incident_Specific_Data/2012 HISTORIC/ROCKY_MTN/Arapaho/GIS/20120629'
    FILE = '20120629_0600_Arapaho_PIO_0629_8x11_land.pdf'
    
    try:
      f = ftplib.FTP(HOST,USER,PASSW)
    except (socket.error, socket.gaierror), e:
      print('ERROR: cannot reach "%s"' % HOST)
    print('*** Connected to host "%s"' % HOST)
    
    try:
      f.login()
    except ftplib.error_perm:
      print('ERROR: cannot login')
      f.quit()
    print('*** Logged in ')
    
    try:
      f.cwd(DIRN)
    except ftplib.error_perm:
      print('ERROR: cannot CD to "%s"' % DIRN)
      f.quit()
    print('*** Changed to "%s" folder' % DIRN)
    
    try:
      f.retrbinary('RETR %s' % FILE,
         open(FILE, 'wb').write)
    except ftplib.error_perm:
      print('ERROR: cannot read file "%s"' % FILE)
      os.unlink(FILE)
    else:
      print('*** Downloaded "%s" to CWD' % FILE)
    f.quit()
    
  11. 您可以通过检查 C:\ArcpyBook\code\Appendix2\ftp.py 解决方案文件来验证您的操作。

  12. 保存并运行脚本。如果一切顺利,您应该看到以下输出:

    *** Connected to host "ftp.nifc.gov"
    *** Logged in as "anonymous"
    *** Changed to "'/Incident_Specific_Data/2012 HISTORIC/ROCKY_MTN/Arapaho/GIS/20120629'" folder
    *** Downloaded "'20120629_0600_Arapaho_PIO_0629_8x11_land.pdf " to CWD
    
    
  13. 检查您的 C:\ArcpyBook\Appendix2 目录中的文件。默认情况下,FTP 将文件下载到当前工作目录。

它是如何工作的…

要连接到 FTP 服务器,您需要知道 URL。您还需要知道要下载的文件的目录和文件名。在此脚本中,我们硬编码了此信息,以便您可以专注于实现 FTP 特定的功能。使用此信息,我们创建了与 NIFC FTP 服务器的连接。这是通过 ftplib.FTP() 函数完成的,该函数接受主机的 URL。

请记住,您需要获取用户名/密码以登录并下载数据。登录后,脚本将更改目录,从 FTP 服务器的根目录切换到 DIRN 变量中定义的路径。这是通过 cwd(<path>) 函数实现的。PDF 文件是通过使用 retrbinary() 函数检索的。最后,完成操作后,您将想要关闭与 FTP 服务器的连接。这可以通过 quit() 方法完成。

更多内容…

有许多其他与 FTP 相关的方法,您可以使用它们执行各种操作。通常,这些可以分为目录级操作和文件级操作。目录级方法包括 dir() 方法以获取目录中的文件列表,mkd() 创建新目录,pwd() 获取当前工作目录,以及 cwd() 更改当前目录。请记住,您通过脚本尝试执行的操作将由分配给您的账户的权限控制,因此您可能无法成功执行我提到的每个方法。

ftplib 模块还包括各种用于处理文件的方法。您可以使用二进制或纯文本格式上传和下载文件。retrbinary()storbinary() 方法分别用于检索和存储二进制文件。纯文本文件可以使用 retrlines()storlines() 检索和存储。

FTP 类有几个其他方法你应该知道。删除文件可以使用delete()方法完成,而重命名文件可以使用rename()方法完成。你还可以通过sendcmd()方法向 FTP 服务器发送命令。

创建 ZIP 文件

GIS 通常需要使用大文件,这些文件将被压缩成.zip格式以便于分享。Python 包含一个模块,你可以使用它来解压缩和压缩这种格式的文件。

准备工作

ZIP 是一种常见的压缩和存档格式,在 Python 中通过zipfile模块实现。ZipFile类可用于创建、读取和写入.zip文件。要创建一个新的.zip文件,只需提供文件名以及模式w,这表示你想要向文件写入数据。在以下代码示例中,我们正在创建一个名为datafile.zip.zip文件。第二个参数w表示将创建一个新文件。在写入模式下,将创建一个新文件或截断具有相同名称的现有文件。在创建文件时还可以使用可选的压缩参数。此值可以设置为ZIP_STOREDZIP_DEFLATED

zipfile.ZipFile('dataFile.zip', 'w',zipfile.ZIP_STORED)

在这个练习中,你将使用 Python 创建文件,添加文件,并将压缩应用于.zip文件。你将存档位于C:\ArcpyBook\data目录中的所有 shapefiles。

如何操作…

按照以下步骤学习如何创建一个构建.zip文件的脚本:

  1. 打开IDLE并创建一个名为C:\ArcpyBook\Appendix2\CreateZipfile.py的脚本。

  2. 导入zipfileos模块:

    import os
    import zipfile
    
  3. 以写入模式创建一个名为shapefiles.zip的新.zip文件并添加压缩参数:

    zfile = zipfile.ZipFile("shapefiles.zip", "w", zipfile.ZIP_STORED)
    
  4. 接下来,我们将使用os.listdir()函数来创建数据目录中的文件列表:

    files = os.listdir("c:/ArcpyBook/data")
    
  5. 遍历所有文件的列表,如果文件以shpdbfshx结尾,则将其写入.zip文件:

    for f in files:
      if f.endswith("shp") or f.endswith("dbf") or f.endswith("shx"):
        zfile.write("C:/ArcpyBook/data/" + f)
    
  6. 打印出添加到 ZIP 存档中的所有文件的列表。你可以使用ZipFile.namelist()函数创建存档中的文件列表。

    for f in zfile.namelist():
        print "Added %s" % f
    
  7. 关闭.zip存档:

    zfile.close()
    
  8. 整个脚本应如下所示:

    import os
    import zipfile
    
    #create the zip file
    zfile = zipfile.ZipFile("shapefiles.zip", "w", zipfile.ZIP_STORED)
    files = os.listdir("c:/ArcpyBook/data")
    
    for f in files:
      if f.endswith("shp") or f.endswith("dbf") or f.endswith("shx"):
        zfile.write("C:/ArcpyBook/data/" + f)
    
    #list files in the archive
    for f in zfile.namelist():
        print("Added %s" % f)
    
    zfile.close()
    
  9. 你可以通过检查C:\ArcpyBook\code\Appendix2`CreateZipfile_Step1`.py 解决方案文件来验证你的工作。

  10. 保存并运行脚本。你应该看到以下输出:

    Added ArcpyBook/data/Burglaries_2009.dbf
    Added ArcpyBook/data/Burglaries_2009.shp
    Added ArcpyBook/data/Burglaries_2009.shx
    Added ArcpyBook/data/Streams.dbf
    Added ArcpyBook/data/Streams.shp
    Added ArcpyBook/data/Streams.shx
    
    
  11. 在 Windows 资源管理器中,你应该能够看到以下截图所示的输出.zip文件。注意存档的大小。此文件未进行压缩:如何操作…

  12. 现在,我们将创建.zip文件的压缩版本以查看差异。对创建.zip文件的代码行进行以下更改:

    zfile = zipfile.ZipFile("shapefiles2.zip", "w", zipfile.ZIP_DEFLATED)
    
  13. 你可以通过检查C:\ArcpyBook\code\Appendix2`CreateZipfile_Step2`.py 解决方案文件来验证你的工作。

  14. 保存并重新运行脚本。

  15. 看看您刚刚创建的shapefiles2.zip文件的大小。注意由于压缩导致的文件大小减少:如何操作…

工作原理…

在这个菜谱中,您以写入模式创建了一个名为shapefiles.zip的新.zip文件。在脚本的第一轮迭代中,您没有压缩文件内容。然而,在第二轮迭代中,您通过将DEFLATED参数传递给ZipFile对象的构造函数来执行压缩。然后脚本获取数据目录中的文件列表,并遍历每个文件。每个具有.shp.dbf.shx扩展名的文件随后使用write()函数写入归档文件。最后,将写入归档的每个文件的名称打印到屏幕上。

更多内容…

可以使用read()方法读取存储在 ZIP 存档中的现有文件的内容。首先应以读取模式打开文件,然后您可以调用read()方法,传递一个参数,表示要读取的文件名。然后可以将文件内容打印到屏幕上,写入另一个文件,或存储为列表或字典变量。

阅读 XML 文件

XML 文件被设计为一种传输和存储数据的方式。由于数据存储在纯文本文件中,因此它们是平台无关的。尽管与 HTML 相似,但 XML 与 HTML 不同,因为前者是为显示目的而设计的,而 XML 数据是为数据设计的。XML 文件有时被用作 GIS 数据在不同软件系统之间交换的格式。

准备工作

XML 文档具有由root元素、child元素和元素属性组成的树状结构。元素也被称为节点。所有 XML 文件都包含一个root元素。这个root元素是所有其他元素或子节点的父元素。以下代码示例说明了 XML 文档的结构。与 HTML 文件不同,XML 文件是区分大小写的:

<root>
 <child att="value">
 <subchild>.....</subchild>
 </child>
</root>

小贴士

Python 提供了几个编程模块,您可以使用它们来处理 XML 文件。您应该使用的模块应由适合工作的模块决定。不要试图强迫单个模块做所有事情。每个模块都有它们擅长执行的具体功能。

在这个菜谱中,您将学习如何使用文档中的nodeselement属性从 XML 文件中读取数据。

有多种方法可以访问 XML 文档中的节点。也许,最简单的方法是通过标签名查找节点,然后遍历包含子节点列表的树。在这样做之前,你将想要使用 minidom.parse() 方法解析 XML 文档。一旦解析,你可以使用 childNodes 属性来获取从树根开始的所有 child 节点的列表。最后,你可以使用接受标签名作为参数的 getElementsByTagName(tag) 函数来搜索节点,这将返回与标签相关联的所有 child 节点的列表。

你也可以通过调用 hasAttribute(name) 来确定一个节点是否包含属性,这将返回一个 true/false 值。一旦确定属性存在,调用 getAttribute(name) 将获取属性的值。

在这个练习中,你将解析一个 XML 文件,并提取与特定元素(节点)和属性相关的值。我们将加载一个包含野火数据的 XML 文件。在这个文件中,我们将寻找 <fire> 节点和每个这些节点的 address 属性。地址将被打印出来。

如何操作...

  1. 打开 IDLE 并创建一个名为 C:\ArcpyBook\Appendix2\XMLAccessElementAttribute.py 的脚本。

  2. 将使用 WitchFireResidenceDestroyed.xml 文件。该文件位于你的 C:\ArcpyBook\Appendix2 文件夹中。你可以看到其内容的样本,如下所示:

    <fires>
      <fire address="11389 Pajaro Way" city="San Diego" state="CA" zip="92127" country="USA" latitude="33.037187" longitude="-117.082299" />
      <fire address="18157 Valladares Dr" city="San Diego" state="CA" zip="92127" country="USA" latitude="33.039406" longitude="-117.076344" />
      <fire address="11691 Agreste Pl" city="San Diego" state="CA" zip="92127" country="USA" latitude="33.036575" longitude="-117.077702" />
      <fire address="18055 Polvera Way" city="San Diego" state="CA" zip="92128" country="USA" latitude="33.044726" longitude="-117.057649" />
    </fires>
    
  3. xml.dom 导入 minidom

    from xml.dom import minidom
    
  4. 解析 XML 文件:

    xmldoc = minidom.parse("WitchFireResidenceDestroyed.xml")
    
  5. 从 XML 文件生成节点列表:

    childNodes = xmldoc.childNodes
    
  6. 生成所有 <fire> 节点的列表:

    eList = childNodes[0].getElementsByTagName("fire")
    
  7. 遍历元素列表,检查 address 属性是否存在,如果存在则打印属性值:

    for e in eList:
      if e.hasAttribute("address"):
        print(e.getAttribute("address"))
    
  8. 你可以通过检查 C:\ArcpyBook\code\Appendix2 文件夹下的 XMLAccessElementAttribute.py 解决方案文件来验证你的工作。

  9. 保存并运行脚本。你应该看到以下输出:

    11389 Pajaro Way
    18157 Valladares Dr
    11691 Agreste Pl
    18055 Polvera Way
    18829 Bernardo Trails Dr
    18189 Chretien Ct
    17837 Corazon Pl
    18187 Valladares Dr
    18658 Locksley St
    18560 Lancashire Way
    
    

工作原理...

将 XML 文档加载到你的脚本中可能是你可以用 XML 文件做的最基本的事情。你可以使用 xml.dom 模块通过 minidom 对象来完成这项操作。minidom 对象有一个名为 parse() 的方法,它接受一个 XML 文档的路径,并从 WitchFireResidenceDestroyed.xml 文件创建一个 文档对象模型DOM)树对象。

DOM 树的 childNodes 属性生成 XML 文件中所有节点的列表。然后你可以使用 getElementsByTagName() 方法访问每个节点。最后一步是遍历 eList 变量中包含的所有 <fire> 节点。对于每个节点,我们使用 hasAttribute() 方法检查 address 属性,如果存在,则调用 getAttribute() 函数并将地址打印到屏幕上。

还有更多...

有时会需要搜索一个 XML 文档以查找特定的文本字符串。这需要使用 xml.parsers.expat 模块。您需要定义一个从基本 expat 类派生的搜索类,然后从这个类创建一个对象。一旦创建,您就可以在 search 对象上调用 parse() 方法来搜索数据。最后,您可以使用 getElementsByTagName(tag) 函数通过标签名称搜索节点,该函数接受一个标签名称作为参数。这将返回与该标签相关联的所有子节点的列表。

posted @ 2025-10-01 11:27  绝不原创的飞龙  阅读(8)  评论(0)    收藏  举报