ArcGIS-10-1-Python-编程秘籍-全-

ArcGIS 10.1 Python 编程秘籍(全)

原文:zh.annas-archive.org/md5/2d89f21f24acbf4b6fbaaa544942ae71

译者:飞龙

协议:CC BY-NC-SA 4.0

前言

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

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

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

使用 Python 编程 ArcGIS 10.1 烹饪书 从在 ArcGIS Desktop 环境中介绍基本的 Python 编程概念开始。使用如何操作的指导风格,然后你将学习如何使用 Python 自动化常见的 ArcGIS 地理处理任务。

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

使用 Python 编程 ArcGIS 10.1 烹饪书 中,你将学习如何使用一种实用方法编写地理处理脚本,该方法围绕在烹饪书风格格式中完成特定任务而设计。

本书涵盖的内容

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

第二章,使用 ArcPy 编写基本地理处理脚本,将教授 ArcPy Python 站点包的基本概念,包括基本模块、函数和类的概述。读者将能够使用 ArcPy 和 Python 编写地理处理脚本。

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

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

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

第六章, 从脚本中执行地理处理工具,将教授如何编写脚本以访问和运行 ArcGIS 提供的地理处理工具。

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

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

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

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

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

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

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

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

阅读这本书你需要什么

要完成本书中的练习,你需要安装 ArcGIS Desktop 10.1,无论是基本、标准还是高级许可级别。安装 ArcGIS Desktop 10.1 还将安装 Python 2.7 以及 IDLE Python 代码编辑器。

这本书面向谁

使用 Python 编程 ArcGIS 10.1 食谱是为希望用 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 layer u'2000 Census Tracts'>, <map layer u'City Limits'>, <map layer u'Travis County'>]

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

注意

警告或重要提示以如下方式显示在框中。

提示

技巧和窍门显示如下。

读者反馈

我们始终欢迎读者的反馈。告诉我们您对这本书的看法——您喜欢什么或可能不喜欢什么。读者反馈对我们开发您真正从中获得最大收益的标题非常重要。

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

如果您有一本书需要我们出版,并希望看到我们出版,请通过www.packtpub.com上的建议书名表单或发送电子邮件至<suggest@packtpub.com>给我们留言。

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

客户支持

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

下载示例代码

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

勘误

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

侵权

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

请通过 <copyright@packtpub.com> 联系我们,并提供涉嫌盗版材料的链接。

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

问题

如果您在本书的任何方面遇到问题,可以通过 <questions@packtpub.com> 联系我们,我们将尽力解决。

第一章:ArcGIS 的 Python 语言基础

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

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

此外,我们将介绍包括决策支持和循环结构在内的语句,用于在代码中做出决策和/或多次遍历代码块,以及与 Arcpy 数据访问模块中的新cursor对象广泛使用的with语句。最后,您将学习如何访问提供 Python 语言额外功能的模块。到本章结束时,您将学习以下内容:

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

  • Python 语言特性

  • 注释和数据变量

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

  • 复杂数据结构

  • 循环结构

  • 额外的 Python 功能

使用 IDLE 进行 Python 脚本开发

正如我在前言中提到的,当您安装 ArcGIS 桌面版时,Python 也会安装,并附带一个名为 IDLE 的工具,允许您编写自己的代码。"IDLE"代表集成开发环境。因为它与每个 ArcGIS 桌面安装一起提供,所以我们将使用 IDLE 开发环境来编写本书中的许多脚本,以及 ArcGIS 桌面中嵌入的 Python 窗口。随着您作为程序员的进步,您可能会发现比 IDLE 更喜欢的其他开发工具。您可以使用这些工具中的任何一个来编写代码。

Python 外壳窗口

要启动 Python 的 IDLE 开发环境,您可以前往开始 | 程序 | ArcGIS | Python 2.7 | IDLE。请注意,ArcGIS 安装的 Python 版本将取决于您安装的 ArcGIS 版本。例如,ArcGIS 10.0 使用 Python 2.6,而 ArcGIS 10.1 使用 Python 2.7。

将显示与截图类似的 Python 外壳窗口:

Python 外壳窗口

Python 外壳窗口用于输出和脚本生成的错误信息。初学者常见的错误是认为地理处理脚本将在这个外壳窗口中编写。事实并非如此。您需要创建一个单独的代码窗口来存放您的脚本。

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

Python 脚本窗口

你的脚本将写在 IDLE 中的单独窗口,称为Python 脚本窗口。要创建一个新的代码窗口,从 IDLE shell 窗口中选择文件 | 新建窗口。将显示一个类似于以下截图的窗口:

Python 脚本窗口

你的 Python 脚本将在这个新的代码窗口中编写。每个脚本都需要保存到本地或网络驱动器。默认情况下,脚本以.py文件扩展名保存。

编辑现有的 Python 脚本

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

编辑现有的 Python 脚本

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

编辑现有的 Python 脚本

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

从 IDLE 执行脚本

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

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

一旦你确认代码中没有语法错误,你可以运行脚本。选择运行 | 运行模块来执行脚本:

从 IDLE 执行脚本

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

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语句将是您脚本中的第一行代码(不包括注释):

import arcpy, os

变量

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

fcParcels = "Parcels"
fcStreets = "Streets"

以下表格展示了使用前面的代码示例中变量名及其赋值:

变量名 变量值
fcParcels Parcels
fcStreets Streets

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

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

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

  • 变量名中除下划线外没有特殊字符

  • 不能使用 Python 关键字

有几十个 Python 关键字必须避免,包括classifforwhile等。

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

print Mapsize
>>>36x48

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# .NET 中,在处理变量之前,你需要命名并定义变量的数据类型。在下面的代码示例中,我们创建了一个名为 aTouchdown 的新变量,它被定义为整数变量,这意味着它只能包含整数数据。然后我们将值 6 分配给这个变量:

int aTouchdown;
aTouchdown = 6;

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

aTouchdown = 6

你的 Python 地理处理脚本对于 ArcGIS 通常需要引用计算机或共享服务器上数据集的位置。对这些数据集的引用通常由存储在变量中的路径组成。在 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 提供的用于操作数据的各种函数。

内置数据类型

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

字符串

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

字符串操作

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

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

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

>>>c:\GISData\Streets.shp

可以使用 Python 的 == 操作符测试字符串的相等性,它只是两个等号放在一起。不要将相等操作符与赋值操作符混淆,赋值操作符是一个单独的等号。相等操作符测试两个变量是否相等,而赋值操作符将值赋给变量:

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

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

>>>False

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

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

我简要地提到字符串是一个字符的有序集合。这意味着什么?这仅仅意味着我们可以从字符串中访问单个字符或一系列字符。在 Python 中,访问单个字符被称为 索引,访问一系列字符被称为 切片

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

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

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

字符串操作

虽然字符串索引允许你从一个字符串变量中获取单个字符,但字符串切片允许你提取一个连续的字符串序列。其格式和语法与索引类似,但增加了第二个偏移量,用于告诉 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 是处理字符串的出色语言,你可以使用许多其他函数来处理这类数据。大多数这些函数超出了本文的范围,但一般来说,以下所有字符串操作函数都是可用的:

  • 字符串长度

  • 大小写转换函数

  • 移除前导和尾随空格

  • 在字符串中查找字符

  • 文本替换

  • 根据分隔符拆分到单词列表

  • 格式化

数字

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

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

虽然 Python 提供了一些内置的数学函数,但可以使用math模块来访问更多高级的数学函数。要使用这些函数,你必须具体导入math模块,如下所示:

import math

math模块提供的函数包括返回数字的上限和下限、绝对值、三角函数、对数函数、角度转换和双曲函数。

列表

Python 提供的第三个内置数据类型是list。列表是有序的对象集合,可以存储 Python 支持的所有类型的数据,同时还能同时存储多种数据类型。这可以是数字、字符串、其他列表、字典或对象。例如,一个列表变量可以同时存储数字和字符串数据。列表是零基的,列表中的第一个元素占据位置0。列表中的每个后续对象递增一个。此外,列表具有动态增长和缩小的特殊能力。

列表是通过将一系列括号内的值赋值来创建的。要从列表中提取一个值,只需在变量名旁边使用括号内的整数值即可。下面的代码示例说明了这一点。您还可以使用列表的切片功能来返回多个值。切片列表始终返回一个新的列表变量。

fcList = ["Hydrants", "Water Mains", "Valves", "Wells"]
fc = fcList[0]
print fc
>>>Hydrants
fc = fcList[3]
print fc
>>>Wells

列表本质上是动态的,这使得它们可以增长、缩小和更改内容,而无需创建列表的新副本。可以通过索引或切片来更改列表中的值。索引允许您更改单个值,而切片允许您更改多个列表项。

列表有许多方法允许您操作列表中的值。您可以通过使用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
dictLayers['Airports']
>>>1
dictLayers['Rail']
>>>2

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

小贴士

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

类和对象

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

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

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

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

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 中的主要决策语句,用于测试真/假条件。决策语句使你能够控制程序的流程。以下是一些你可以在代码中做出的决策示例:如果变量持有点要素类,获取 X、Y 坐标;如果要素类名称等于 Roads,则获取 Name 字段。

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

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

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

语句缩进值得特别提一下,因为它对 Python 解释代码的方式至关重要。正如我提到的,Python 通过缩进来检测连续的代码段。默认情况下,所有 Python 语句都应该左对齐,直到使用循环、决策支持、try/exceptwith 语句。这包括 forwhile 循环、if/else 语句、try/except 语句和 with 语句。所有以相同距离缩进的语句都属于同一代码块,直到该块通过缩进较少的行结束。

循环语句

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

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

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

dictLayers = {"Roads":"Line","Rail":"Line","Parks":"Polygon"}
lstLayers = dictLayers.keys()
for x in lstLayers:
  print dictLayers[x]

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

try 语句

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

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 块,然后是 finally 块,之后继续执行 try 语句之后的代码。如果在执行过程中没有发生异常,Python 会运行 try 块,然后是 finally 块。这在你想确保代码块运行后某个动作发生,无论是否发生错误条件时非常有用。清理操作,例如关闭文件或数据库连接,通常放置在 finally 块中,以确保无论代码中是否发生异常都会执行:

import arcpy
from arcpy import env

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

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

f = open('Wildfires.txt','r')

在完成对一个文件的读写操作后,你应该始终使用close()方法关闭文件。

文件一旦打开,就可以通过多种方式使用各种方法从其中读取数据。最典型的情况是使用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
  f = open('Wildfires.txt','r')

 lstFires = f.readlines()
  cur = arcpy.InsertCursor("FireIncidents")

  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)
    except:
  print arcpy.GetMessages()
finally:
	del cur
	f.close()

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

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

摘要

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

在下一章中,您将学习使用 Python 编写 ArcGIS 地理处理脚本的基本技术。您将学习如何使用 ArcGIS Desktop 中的嵌入式 Python 窗口,将 ArcPy 包导入到脚本中,从脚本中执行 ArcToolbox 工具,在编写脚本时使用帮助系统,使用变量来存储数据,以及访问各种 ArcPy 模块。

第二章:使用 ArcPy 编写基本的地理处理脚本

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

  • 使用 ArcGIS Python 窗口

  • 使用 Python 访问 ArcPy

  • 从脚本中执行工具

  • 使用 ArcGIS Desktop 帮助

  • 使用变量存储数据

  • 使用 Python 访问 ArcPy 模块

简介

地理处理任务往往耗时且重复,通常需要定期运行。通常,涉及许多数据层和函数。ArcGIS 的 ArcPy Python 站点包提供了一套工具和执行环境,可用于将您的数据转换为有意义的成果。使用脚本,您可以自动化您的地理处理任务,并安排它们在您组织最方便的时候运行。

ArcGIS 提供了一个地理处理框架,用于通过一系列工具和执行环境来自动化您的重复性 GIS 任务。所有工具都操作在一个输入数据集上,您需要提供并对其进行某种方式的转换(取决于所使用的工具的性质),以生成一个新的输出数据集。如果需要,这个新的输出数据集可以随后用作更大工作流程中其他地理处理工具的输入数据集。ArcGIS 地理处理框架提供了许多工具,每个工具都旨在提供特定的功能。

尽管您可以使用许多不同的环境来编写您的地理处理脚本,但本书将专注于使用内置的 ArcGIS Python 窗口和 Python IDLE 编辑器。

使用 ArcGIS Python 窗口

在这个菜谱中,您将学习如何使用 ArcGIS Python 窗口。在第一章《ArcGIS Python 语言基础》中,您学习了如何使用 IDLE 开发环境进行 Python 开发,因此本章将为您提供编写地理处理脚本的另一种选择。两种开发环境都可以使用,但人们通常从使用 ArcGIS Desktop Python 窗口开始编写脚本,然后在脚本变得更加复杂时转向 IDLE。我还应该提到,还有许多其他您可能想要考虑的开发环境,包括 PythonWin、Wingware、Komodo 等。您选择哪种开发环境实际上是一个个人偏好的问题。

准备工作

新的 Python 窗口是 ArcGIS Desktop 10 中嵌入的交互式 Python 窗口,非常适合测试小块代码、学习 Python 基础知识、构建快速简便的工作流程以及执行地理处理工具。然而,随着您的脚本变得更加复杂,您很快就会发现自己需要更强大的开发环境。默认情况下,IDLE 与 ArcGIS Desktop 一起安装,因此对于许多人来说,这是一个合乎逻辑的下一步选择。但对于新程序员来说,ArcGIS Python 窗口是一个很好的起点!

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

如何操作…

Python 窗口可以通过点击主 ArcGIS Desktop 工具栏上的 Python 窗口按钮来打开。

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

    注意

    你不必专门打开 Crime_Ch2.mxd。任何地图文档文件都可以与 Python 窗口一起使用。

  2. 从主 ArcMap 工具栏中点击 Python 窗口按钮。Python 窗口将显示如下截图所示。这是一个浮动窗口,因此你可以根据需要调整大小,也可以将其停靠在 ArcMap 界面的各个位置:如何操作…

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

  3. 通过在 Python 窗口中右键单击并从菜单中选择 加载 来加载现有脚本。导航到 c:\ArcpyBook\Ch2 目录并选择 ListFields.py 以加载一个示例脚本。

    你也可以通过右键单击窗口并选择 格式 来格式化窗口中显示的字体和文本颜色。你将提供白色和黑色主题;你可以单独选择字体和颜色:

    如何操作…

点击 设置黑色主题 按钮查看示例。如果你花费大量时间编写代码,你可能发现较暗的主题对眼睛更容易:

如何操作…

使用 Python 访问 ArcPy

在你可以利用 ArcPy 提供的所有地理处理功能之前,你必须首先将包导入到你的脚本中。这将是每个地理处理脚本中的第一行代码。

准备工作

ArcPy 是 ArcGIS 10 版本的一部分 Python 站点包,完全包含了 ArcGIS 9.2 中 arcgis scripting 模块提供的功能,进一步增强了其能力。使用 ArcPy,你可以访问用于处理 ESRI GIS 数据的地理处理工具、扩展、函数和类。ArcPy 为模块、类和函数提供代码补全和集成文档。ArcPy 还可以与其他 Python 模块集成,以扩大其功能范围。你用 Python 编写的所有 ArcGIS 地理处理脚本都必须首先提供对 ArcPy 的引用。

如何操作…

按照以下步骤将 arcpy 站点包导入到 ArcGIS Python 窗口:

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

  2. 点击 Python 窗口按钮以显示一个可以编写 Python 代码的壳窗口。

  3. 在 Python 窗口中导入 arcpy 包并按下键盘上的 Enter 键。在 Python 窗口中输入的每个语句之后,您都需要按下 Enter 键。您将在每个脚本中都包含这一行代码,所以请习惯它!这个 import 语句是您访问 ArcPy 提供的所有功能的基础。

    注意

    从技术上讲,在 ArcMap Python 窗口内部工作时不一定要包含 import arcpy 语句。它是这个窗口固有的。然而,在创建 IDLE、PythonWin 或任何其他集成开发环境中的独立脚本时,它却是必需的。这也是一个好习惯,因为您的大多数脚本最终都将作为独立脚本运行。

    如何操作…

  4. ArcPy 还提供了代码补全功能,这使得您作为程序员的编程生活变得更加容易。在第二行,开始键入 arcpy 并然后一个点。ArcPy 是一个面向对象的包,这意味着您使用点符号来访问对象的属性和方法。请注意,提供了一个可用项的下拉列表。这些是在特定对象上可用的工具、函数、类和扩展。所有对象都有它们自己的相关项,因此呈现的项列表将根据您当前选定的对象而有所不同:如何操作…

  5. 这是一个自动过滤列表,因此当您开始键入工具、函数、类或扩展的名称时,列表将根据您输入的内容进行过滤:如何操作…

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

工作原理…

一旦导入了 ArcPy 模块,您就可以访问用于处理 ESRI GIS 数据的地理处理工具、扩展、函数和类。ArcPy 最重要的一点是,它根据当前使用的 ArcGIS Desktop 许可证级别提供对所有地理处理工具的访问。脚本可用的工具将根据您是否使用 ArcGIS 基础、标准或高级许可证级别而有所不同,其中基础级别提供最少的工具,而高级级别提供完整的工具集。

从脚本中执行工具

作为 ArcGIS 用户,您几乎肯定已经使用 ArcToolbox 中提供的许多工具来完成您的地理处理任务。一些例子包括 Clip、Buffer、Feature Class to Feature Class、Add Field 等。您的脚本可以执行 ArcToolbox 中找到的任何工具。请记住,您作为程序员可用的工具取决于您使用的 ArcGIS Desktop 的许可级别。这些任务可以通过创建一个执行这些工具的 Python 脚本来自动化。

如何操作…

  1. 按照以下步骤学习如何从您的脚本中执行地理处理工具。使用 ArcMap 打开c:\ArcpyBook\Ch2\TravisCounty.mxd

  2. 打开 Python 窗口。

  3. 导入arcpy包:

    import arcpy
    
  4. 设置工作空间。我们还没有讨论env类。ArcGIS 的环境设置作为env类的属性公开,它是arcpy的一部分。env类的一个属性是工作空间,它定义了数据输入和输出的当前工作目录。在这种情况下,它将是我们将从工具中写入输出数据集的目录:

    arcpy.env.workspace = "c:/ArcpyBook/data/"
    
  5. 我们将使用Analysis Tools工具箱中的Buffer工具来缓冲在 ArcMap 活动数据帧中看到的Streams层。打开 ArcToolbox 并找到此工具,如下面的截图所示:如何操作…

  6. 双击Buffer工具以显示以下截图所示的界面。大多数工具都有一个或多个必须提供的输入参数,以便工具可以执行。无论您是从用户界面还是从 Python 脚本中运行工具,您都必须始终提供这些必需的参数:如何操作…

  7. 关闭Buffer工具。

  8. 在 Python 窗口中执行Buffer工具。使用 Python 窗口的代码补全功能以及窗口右侧显示的工具帮助来帮助您。

    这将使Streams层缓冲 50 米以创建一个新的Streams_Buff多边形层:

    arcpy.Buffer_analysis("Streams", "Streams_Buff", "50 Meters")
    
  9. 使用您的 ArcMap缩放平移工具来更好地查看输出数据集,如下面的截图所示:如何操作…

它是如何工作的…

您的脚本可用的所有地理处理工具都定义为来自主arcpy对象的动态函数。您从脚本中执行的每个工具都必须遵循特定的语法,首先定义工具名称,然后是一个下划线,接着是工具箱名称的别名。在我们的例子中,Buffer工具位于Analysis Tools工具箱中,其别名为analysis。这样做是因为可能存在多个工具具有相同的名称。使用语法<toolname>_<toolbox_alias>为每个工具生成一个唯一的引用。

在 ArcGIS Desktop 中获取工具箱别名很容易。找到与工具关联的工具箱,右键单击工具箱名称。选择属性。在显示的属性对话框中,找到别名文本框。当在地理处理脚本中引用特定工具时,你会看到以下别名:

工作原理…

除了表示地理处理工具的动态函数外,arcpy类上还有许多其他可用函数,它们不是地理处理工具。提供了创建游标、列出数据集、描述数据集、处理环境设置、消息传递等许多其他功能的函数。随着我们阅读本书,我们将介绍这些函数中的许多。

还有更多…

地理处理工作流程通常需要多个步骤,这些步骤需要使用一个或多个地理处理工具。通过首先为你的脚本创建一个大纲,你可以更高效、更有效地开发脚本。这个大纲将帮助你考虑手头的任务并确定将使用的地理处理工具。大纲不必是复杂的任务。你可以简单地绘制一个工作流程图,然后根据这个工作流程实现你的代码。关键是实际开始编码之前做一些规划。

使用 ArcGIS Desktop 帮助

ArcGIS Desktop 帮助系统是获取任何可用工具信息的优秀资源。每个工具都在一个独特的页面上进行了详细描述。帮助系统可通过 ArcGIS Desktop 或在线访问。

准备工作

除了包含每个工具的基本描述信息外,帮助系统还包括对 Python 程序员感兴趣的信息,包括语法和代码示例,这些示例提供了有关如何在脚本中使用工具的详细信息。在本食谱中,你将学习如何访问 ArcGIS Desktop 帮助系统以获取语法信息和代码示例。

如何操作...

按照以下步骤学习如何使用 ArcGIS Desktop 帮助系统访问有关工具的语法信息,以及一个代码示例,展示如何在脚本中使用该工具。

  1. 如果需要,打开 ArcMap 并从主菜单中选择帮助 | ArcGIS Desktop 帮助

  2. 选择内容选项卡。

  3. 选择地理处理 | 工具参考。工具根据工具箱分组,就像在 ArcToolbox 中一样。

  4. 选择分析工具箱,然后选择邻近工具集

  5. 点击缓冲区工具。你应该会看到显示的缓冲区工具帮助,如图所示:如何操作...

  6. 滚动到语法部分,如图所示:如何操作...

  7. 该部分定义了从脚本中调用工具的语法。在这种情况下,语法如下:

    Buffer_analysis (in_features, out_feature_class, buffer_distance_or_field, {line_side}, {line_end_type}, {dissolve_option}, {dissolve_field})
    
  8. 滚动到 代码示例 部分。在这里,你可以找到一个或多个代码示例,展示如何在你的脚本中使用工具。我总是建议在编写脚本之前查看这些示例。

它是如何工作的...

每个工具的帮助系统包含几个部分,包括摘要、插图、用法、语法、代码示例、环境、相关主题和许可信息。作为一个程序员,你主要会对语法和代码示例部分感兴趣。

当查看语法部分时,请注意,你通过名称后跟一个下划线和工具所在工具箱的别名来调用每个工具。我们在这个章节的早期部分简要讨论了这一点。

工具通常接受一个或多个参数,这些参数通过括号传递到工具内部。参数可以是必需的或可选的。在这种情况下,Buffer 工具包括三个必需参数:输入要素、输出要素类和距离。必需参数首先列出,并且不被任何特殊字符包围。另一方面,可选参数被大括号包围,并且将跟在必需参数之后。Buffer 工具包含几个可选参数,包括线侧、线端类型、溶解选项和溶解字段。请注意,这些参数中的每一个都被大括号包围。在调用工具时,你不必包括这些参数,它仍然可以执行。

你还应该更详细地检查语法信息,以确定每个参数应传递的数据类型。例如,buffer_distance_or_field 参数可以接受的数据类型可以是线性单位或字段。因此,你可以为这个参数提供一个数值或一个表示包含距离信息的属性字段的 Field 对象。

在你的代码中使用每个工具之前,总是要检查其语法,以确保你有正确的参数、正确的顺序和正确的数据类型。

我建议你也看看代码示例,因为它们通常会为你提供脚本的起点。通常你会发现,你可以将示例代码的一部分复制粘贴到自己的脚本中,然后修改脚本以满足你的需求。这可以使你成为一个更高效的程序员,并且在学习方面,查看其他脚本并逐行检查脚本以确定脚本的工作方式是有帮助的。

使用变量存储数据

在第一章《ArcGIS 的 Python 语言基础》中,我们讨论了变量的主题,因此你应该对这些结构有一个基本的了解。在脚本中,变量被赋予一个名称并分配一个数据值。这些命名变量占据了计算机内存中的空间,在脚本运行期间,这些结构中的数据可以改变。脚本完成后,这些变量占用的内存空间将被释放,可用于其他操作。

准备工作

当使用 Python 编写地理处理脚本时,你将需要多次创建变量来存储不同类型的数据。这些数据然后可以用作脚本中的工具和函数的输入参数,作为内部处理的中间数据,存储数据集的路径,以及其他原因。此外,许多 ArcPy 函数和工具也会返回数据,这些数据可以存储在变量中以供脚本进一步使用。在本食谱中,你将学习创建变量并将数据赋给它们的基本技术。

如何做到这一点...

按照以下步骤创建一个包含硬编码值和从函数返回的变量的脚本:

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

  2. 将脚本保存到c:\ArcpyBook\Ch2\WorkingWithVariables.py

  3. 导入arcpy包:

    import arcpy
    
  4. 创建一个名为path的变量并将其赋予一个值:

    path = "c:/ArcpyBook/data"
    
  5. 使用新创建的变量设置工作空间:

    arcpy.env.workspace = path
    
  6. 调用ListFields()函数并将返回值赋给一个名为fields的新变量:

    fields = arcpy.ListFields("Building_Permits.shp")
    
  7. 开始一个for循环以处理fields变量中包含的每个字段对象:

    for fld in fields:
    
  8. 打印每个字段的名称:

    print fld.name
    
  9. 整个脚本应如下所示:

    import arcpy
    path = "c:/ArcpyBook/data"
    
    arcpy.env.workspace = path
    fields = arcpy.ListFields("Building_Permits.shp")
    for fld in fields:
           print fld.name
    
  10. 保存脚本。

它是如何工作的...

在此脚本中我们创建了三个变量。第一个变量path被创建并赋予了一个硬编码的数据路径值。这是一个字面量变量的例子,意味着它们确实就是所说的那样。它们与变量不同,变量的值不是直接由其名称确定的。第二个变量fields是由ListFields()函数的返回值创建的,是一个包含一个或多个Field对象的 Python 列表对象。每个Field代表一个来自要素类或独立表的属性表中的字段。最后一个变量是一个名为fld的动态变量。当for循环遍历ListFields()函数返回的列表时,每个Field被分配给fld变量。然后,每个字段的名称将被打印到屏幕上。

使用 Python 访问 ArcPy 模块

到目前为止,我们已经介绍了一些与 ArcPy 相关的基本概念。除了基本的 ArcPy 站点包外,还有一些模块可以用来访问特定的功能。在使用这些模块提供的功能之前,你必须将这些模块明确导入到你的脚本中。在本教程中,你将学习如何导入这些模块。

准备工作

除了提供对工具、函数和类的访问外,ArcPy 还提供了几个模块。模块是针对特定目的的 Python 库,包含函数和类。这些模块包括一个映射模块(arcpy.mapping)、一个数据访问模块(arcpy.da)、一个空间分析模块(arcpy.sa)、一个地理统计模块(arcpy.ga)、一个网络分析模块(arcpy.na)和一个时间模块(arcpy.time)。要使用这些模块包含的函数和类,你必须明确导入它们相关的库。

如何操作…

按照以下步骤学习如何使用arcpy.mapping模块提供的函数和类:

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

  2. 打开 Python 窗口。

  3. 导入arcpy.mapping模块:

    import arcpy.mapping as mapping
    
  4. 获取当前地图文档(Crime_Ch2.mxd)的引用:

    mxd = mapping.MapDocument("CURRENT")
    
  5. 调用arcpy.mapping.ListLayers函数:

    print mapping.ListLayers(mxd)
    

    这将返回地图文档中所有层的列表,并将这些打印到 shell 窗口中:

    [<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 layer u'2000 Census Tracts'>, <map layer u'City Limits'>, <map layer u'Travis County'>]
    
    

访问映射模块中所有可用的函数和对象的方式是相同的。

它是如何工作的…

ArcPy 提供的每个模块都提供了访问特定功能的方法。例如,ArcPy 映射模块提供了访问允许你管理地图文档和层文件的函数。该模块中的函数和对象都与以某种方式管理这些文件相关。

第三章. 管理地图文档和图层

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

  • 引用当前地图文档

  • 引用磁盘上的地图文档

  • 访问数据框架

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

  • 限制图层列表

  • 改变地图范围

  • 获取表格列表

  • 向地图文档中添加图层

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

  • 更新图层符号

  • 更新图层属性

简介

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

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

引用当前地图文档

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

准备工作

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

mxd = mapping.MapDocument("CURRENT")

注意

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

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

如何操作…

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

  1. 使用 ArcMap 打开 c:\ArcpyBook\Ch3\Crime_Ch3.mxd

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

  3. 通过在 Python 窗口中输入以下内容导入 arcpy.mapping 模块:

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

    mxd = mapping.MapDocument("CURRENT")
    
  5. 获取地图文档的标题并将其打印到壳窗口。当脚本执行时,地图文档的标题将使用 Python 的 print 语句打印出来:

    print mxd.title
    
  6. 为地图文档设置新标题:

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

    mxd.saveACopy("c:/ArcpyBook/Ch3/crime_copy.mxd")
    
  8. 运行脚本。

  9. 在 ArcMap 中打开您刚刚创建的 crime_copy.mxd 文件,并选择 文件 | 地图文档属性 来查看您为地图文档设置的新标题。

工作原理

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/Ch3/crime_copy.mxd")
    
  5. 打印地图文档的标题:

    print mxd.title
    
  6. 运行脚本以查看以下输出:

    Copy of Crime Project
    
    

它是如何工作的…

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

访问数据帧

ArcMap 的目录由一个或多个数据帧组成。每个数据帧可以包含图层和表格。数据帧可以用来过滤从各种列表函数(如 ListLayers())返回的列表。例如,可以使用 DataFrame 对象作为输入参数,将 ListLayers() 函数返回的图层限制在特定数据帧内。您还可以使用 DataFrame 对象获取或设置当前地图范围,这在创建地图册时可能很有用。在本菜谱中,您将学习如何从您的 Python 脚本中访问数据帧。

准备工作

ListDataFrames() 函数返回一个 DataFrame 对象列表。每个数据帧可以包含图层和表格,并且可以用来限制 ListLayers()ListTablesViews() 函数返回的列表。

如何操作...

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

  1. 使用 ArcMap 打开 c:\ArcpyBook\Ch3\Crime_Ch3.mxd

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

  3. 导入 arcpy.mapping 模块:

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

    mxd = mapping.MapDocument("CURRENT")
    
  5. 调用 ListDataFrames() 函数并传递一个指向地图文档的引用,以及一个用于仅查找以字母 C 开头的数据帧的通配符:

    frames = mapping.ListDataFrames(mxd,"C*")
    
  6. 开始一个 for 循环并打印出地图文档中每个图层的名称:

    for df in frames:
        print df.name
    
  7. 运行脚本以查看以下输出:

    Crime
    Crime_Inset
    
    

它是如何工作的...

ListDataFrames() 函数返回 ArcMap 目录中所有数据帧的列表。像任何其他 Python 列表一样,您可以使用 for 循环遍历列表的内容。在 for 循环内部,每个数据帧被动态分配给 df 变量,并将数据帧的名称打印到屏幕上。

获取地图文档中图层列表

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

准备工作

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

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

在本菜谱中,您将学习如何从地图文档文件中获取图层列表。

如何操作...

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

  1. 使用 ArcMap 打开 c:\ArcpyBook\Ch3\Crime_Ch3.mxd

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

  3. 导入 arcpy.mapping 模块:

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

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

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

    for lyr in layers:
        print lyr.name
    
  7. 运行脚本以查看以下输出:

    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\Ch3\Crime_Ch3.mxd

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

  3. 导入 arcpy.mapping 模块:

    import arcpy.mapping as mapping
    
  4. 引用当前活动文档(Crime_Ch3.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. 完整的脚本应如下所示:

    import arcpy.mapping as mapping
    mxd = mapping.MapDocument("CURRENT")
    for df in mapping.ListDataFrames(mxd):
      if (df.name == 'Crime'):
            layers = mapping.ListLayers(mxd,"'Burg*',df)
            for layer in layers:
          print layer.name
    
  9. 运行脚本以查看以下输出:

    Burglaries in 2009
    
    

它是如何工作的…

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

在这个特定的菜谱中,我们正在搜索所有以字符 Burg 开头并且数据框名称为 Crime 的图层。任何符合这些限制的图层都会被打印出来。请注意,在这种情况下,我们只是在打印图层名称,但在大多数情况下,你将通过使用工具或其他函数执行额外的地理处理。

改变地图范围

在你需要更改地图范围的情况下会有很多机会。当你自动化地图生产过程并需要创建不同区域或特征的许多地图时,这通常是这种情况。有几种方法可以使用 arcpy 来更改地图范围。但是,对于这个配方,我们将专注于使用定义表达式来更改范围。

准备工作

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

如何操作...

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

  1. 使用 ArcMap 打开 c:\ArcpyBook\Ch3\Crime_Ch3.mxd

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

  3. 导入 arcpy.mapping 模块:

    import arcpy.mapping as mapping
    
  4. 引用当前活动文档(Crime_Ch3.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. 整个脚本应如下所示:

    import arcpy.mapping as mapping
    mxd = mapping.MapDocument("CURRENT")
    for df in mapping.ListDataFrames(mxd):
      if (df.name == 'Crime'):
        layers = mapping.ListLayers(mxd,'Crime Density by School District',df)
      for layer in layers:
          query = '"NAME" = \'Lackland ISD\''
          layer.definitionQuery = query
          df.extent = layer.getExtent()
    
  9. 保存并运行脚本。数据视图的范围应更新,以仅可视化与定义表达式匹配的特征,如下面的截图所示:如何操作...

工作原理...

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

获取表格列表

arcpy.mapping 模块还有一个 ListTableViews() 函数,你可以使用它来获取包含在地图文档中的独立表格列表。在本配方中,你将学习如何使用 ListTableViews() 函数来创建此表格列表。

准备工作

除了提供在地图文档或数据框中生成图层列表的能力外,arcpy mapping 模块还提供了一个 ListTableViews() 函数,该函数生成表格列表。

注意

ListTableViews() 只适用于地图文档文件及其包含的数据框。图层文件没有保留表格的能力。

如何操作…

按照以下步骤学习如何获取地图文档中的独立表格列表:

  1. 使用 ArcMap 打开 c:\ArcpyBook\Ch3\Crime_Ch3.mxd

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

  3. 导入arcpy.mapping模块:

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

    mxd = mapping.MapDocument("CURRENT")
    
  5. 生成地图文档中的表格列表:

    for tableView in mapping.ListTableViews(mxd):
        print tableView.name
    
  6. 运行脚本以查看以下输出:

    Crime2009Table
    
    

工作原理…

ListTableViews()函数与arcpy.mapping提供的其他列表函数非常相似。与ListLayers()函数的情况一样,ListTableViews()函数接受一个地图文档的引用(但不是图层文件),以及可选的通配符和数据帧参数。输出是一个可以迭代以for循环的表格列表。

将图层添加到地图文档

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

准备工作

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

注意

无法将图层添加到图层文件(.lyr)中。

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

如何操作…

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

  1. 使用 ArcMap 打开c:\ArcpyBook\Ch3\Crime_Ch3.mxd

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

  3. 导入arcpy.mapping模块:

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

    mxd = mapping.MapDocument("CURRENT")
    
  5. 获取对Crime数据帧的引用,它是ListDataFrames()返回的列表中的第一个数据帧。代码末尾指定的[0]获取从ListDataFrames()方法返回的第一个数据帧,该方法返回一个数据帧列表。列表是从零开始的,因此要检索第一个数据帧,我们提供一个索引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. 运行脚本。School_District.lyr文件将被添加到数据帧中,如下面的截图所示:如何操作…

工作原理…

在前两行中,我们简单地引用了 arcpy.mapping 模块,并获取了对当前活动地图文档的引用。接下来,我们创建了一个名为 df 的新变量,它包含对 Crime 数据框的引用。这是通过 ListDataFrames() 函数获得的,该函数返回一个数据框对象列表。然后我们使用列表访问返回列表中的第一个项目,即 Crime 数据框。然后从磁盘上存储的 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\Ch3\Crime_Ch3.mxd

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

  3. 导入arcpy.mapping模块:

    import arcpy.mapping as mapping
    
  4. 引用当前活动文档(Crime_Ch3.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. 运行脚本。Crimes2009要素类将被添加到数据框中,如下截图所示:如何操作…

工作原理…

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

工作原理…

更多内容…

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

更新图层符号

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

准备就绪

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

准备中

如何操作...

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

  1. 使用 ArcMap 打开c:\ArcpyBook\Ch3\Crime_Ch3.mxd

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

  3. 导入arcpy.mapping模块:

    import arcpy.mapping as mapping
    
  4. 引用当前活动文档(Crime_Ch3.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. 运行脚本。现在按学区划分的犯罪密度图层将使用渐变符号而不是渐变色进行符号化,如下面的截图所示:如何操作…

工作原理...

在这个菜谱中,我们使用了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\Ch3\Crime_Ch3.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_Ch3.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. 运行脚本。

  20. Crimes2009图层将使用与BurglariesNoForcedEntry.lyr文件关联的属性进行更新。这将在以下截图中进行说明。打开图层以查看已应用的定义查询。您还可以打开图层属性对话框来查看已应用到Crimes2009要素类的属性更改:如何操作…

第四章:查找和修复损坏的数据链接

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

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

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

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

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

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

简介

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

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

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

准备工作

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

准备工作

如何操作…

按以下步骤操作,了解如何在地图文档文件中查找损坏的数据源。

  1. 在 ArcMap 中打开C:\ArcpyBook\Ch4\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\Ch4\Crime_BrokenDataLinks.mxd")
    
  6. 获取损坏数据源的列表:

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

    for layer in lstBrokenDS:
        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\Ch4文件夹中。

它是如何工作的…

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

更多内容...

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

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

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

准备工作

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

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

如何操作...

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

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

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

  3. 切换到选项卡,您会注意到图层的位置引用为C:\ArcpyBook\Ch4\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\Ch4\Crime_BrokenDataLinks.mxd")
    
  7. 使用 MapDocument.findAndReplaceWorkspacePaths() 修复地图文档中每个数据源的资源路径:

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

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

  10. 运行脚本。

  11. 在 ArcMap 中打开 C:\ArcpyBook\Ch4\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\Ch4\Crime_DataLinksFixed.mxd

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

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

  4. 导入 arcpy.mapping 模块:

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

    mxd = mapping.MapDocument(r"c:\ArcpyBook\Ch4\Crime_BrokenDataLinks.mxd.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\Ch4\Crime_DataLinksUpdated.mxd")
    
  8. 将脚本保存为 c:\ArcpyBook\Ch4\MapDocumentReplaceWorkspace.py

  9. 运行脚本。

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

它是如何工作的…

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

  • TEXT_WORKSPACE:文本文件工作空间

  • TIN_WORKSPACE:TIN 工作空间

  • VPF_WORKSPACE:VPF 工作空间

使用 replaceDataSource() 修复单个 Layer 和 Table 对象

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

准备工作

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

如何操作…

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

  1. 在 ArcMap 中打开 c:\ArcpyBook\Ch4\Crime_DataLinksLayer.mxd犯罪 数据帧包含一个名为 Burglary 的图层,它是 CityOfSanAntonio 文件地理数据库中的一个要素类。您将用包含相同数据的 shapefile 图层替换此要素类:如何操作…

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

  3. 导入 arcpy.mapping 模块:

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

    mxd = mapping.MapDocument(r"c:\ArcpyBook\Ch4\ Crime_DataLinksUpdated.mxd")
    
  5. 获取 Crime 数据框的引用:

    df = mapping.ListDataFrames(mxd,"Crime")[0]
    
  6. 查找 Burglary 层并将其存储在一个变量中:

    lyr = mapping.ListLayers(mxd,"Burglary",df)[0]
    
  7. Layer 对象上调用 replaceDataSource() 方法,并传入 shapefile 的路径、一个表示这将是一个 shapefile 工作区的关键词以及 shapefile 的名称:

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

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

  10. 运行脚本。

  11. 在 ArcMap 中打开 C:\ArcpyBook\Ch4\Crime_DataLinksNewLayer.mxd。你应该看到 Burglary 层现在引用了一个新的工作区:如何操作…

  12. 右键单击 Burglary 层并选择 属性

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

它是如何工作的…

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

还有更多…

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

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

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

准备工作

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

如何操作...

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

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

  2. 导入arcpyos包:

    import arcpy.mapping as mapping, os
    
  3. 定义一个你想要开始搜索的路径。在这种情况下,我们将从C:目录开始搜索,然后递归搜索C:驱动器内的所有目录。你可能想要定义一个更具体的路径:

    path = r"C:"
    
  4. 打开一个文件,你将用它来写入损坏的图层名称:

    f = open('BrokenDataList.txt','w')
    
  5. 使用os.walk()方法和for循环遍历目录树:

    for root,dirs,files in os.walk(path):
    
  6. for循环内部,创建一个第二个for循环,遍历所有返回的文件。对于每个文件,使用os.path.splitext()方法获取基本文件名以及扩展名:

    for filename in files:
        basename, extension = os.path.splitext(filename)
    
  7. 测试文件扩展名以查看它是否是地图文档文件。如果是,获取地图文档文件的完整路径,使用路径创建一个新的地图文档对象实例,写入地图文档名称,遍历每个损坏的数据源,并将其写入文件:

    if extension == ".mxd":
        fullPath = os.path.join(path,filename)
        mxd = mapping.MapDocument(fullPath)
        f.write("MXD: " + filename + "\n")
        brknList = mapping.ListBrokenDataSources(mxd)
        for brknItem in brknList:
            f.write("\t" + brknItem.name + "\n")
    
  8. 关闭文件:

    f.close()
    
  9. 整个脚本应如下所示:

    import arcpy.mapping as mapping, os
    path = r"C:"
    f = open('filename_here.txt','w')
    for root,dirs,files in os.walk(path):
        for filename in files:
            basename, extension = os.path.splitext(filename)
            if extension == ".mxd":
                fullPath = os.path.join(path,filename)
                mxd = mapping.MapDocument(fullPath)
                f.write("MXD: " + filename + "\n")
                brknList = mapping.ListBrokenDataSources(mxd)
                for brknItem in brknList:
                    f.write("\t" + brknItem.name + "\n")
    f.close()
    
  10. 运行脚本以生成文件。

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

它是如何工作的...

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

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

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

  • 创建布局元素列表

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

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

  • 更新布局元素属性

  • 获取可用打印机的列表

  • 使用PrintMap()打印地图

  • 将地图导出为 PDF 文件

  • 将地图导出为图像文件

  • 使用PDFDocumentCreate()PDFDocumentOpen()创建地图册

简介

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

创建布局元素列表

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

准备中...

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

准备中...

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

如何做...

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

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

  2. 打开 Python 窗口。

  3. 导入arcpy.mapping模块:

    import arcpy.mapping as mapping
    
  4. 引用当前活动文档(Crime_Ch5.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. 运行脚本以查看以下输出:

    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\Ch5\Crime_Ch5.mxd

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

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

  4. 右键单击上层数据帧并选择属性以显示数据帧属性窗口,如下截图所示。名称属性定义了元素的唯一名称。在这种情况下,元素名称是Crime如何操作…

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

  6. 在布局视图中选择2009 Crime Legend,并通过右键单击图例并选择属性来打开属性窗口。

  7. 为图例设置元素名称与为数据帧设置元素名称不同。单击大小和位置选项卡。

  8. 在此情况下使用元素名称文本框。将当前值更改为2009 Crime Legend,如下所示:如何操作…

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

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

它是如何工作的…

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

更多内容…

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

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

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

准备工作

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

如何操作…

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

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

  2. 打开 Python 窗口。

  3. 导入arcpy.mapping模块:

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

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

    for el in mapping.ListLayoutElements(mxd,"LEGEND_ELEMENT","*Crime*")
      print el.name
    
  6. 运行脚本。在这种情况下,只会返回单个布局元素:

    2009 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\Ch5\Crime_Ch5.mxd

  2. 打开 Python 窗口。

  3. 导入arcpy.mapping模块:

    import arcpy.mapping as mapping
    
  4. 引用当前活动文档(Crime_Ch5.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. 运行脚本。您应该看到以下图层被打印:

    Burglaries in 2009
    Crime Density by School District
    
    
  10. 改变在以下屏幕截图中显示:如何去做…

它是如何工作的...

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

获取可用打印机的列表

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

准备工作

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

如何操作…

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

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

  2. 打开 Python 窗口。

  3. 导入 arcpy.mapping 模块:

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

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

    for printerName in mapping.ListPrinterNames():
      print printerName
    
  6. 运行脚本。输出将根据计算机上可用的打印机列表而变化。但是,它应该打印出类似于以下代码片段的内容:

    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\Ch5\Crime_Ch5.mxd

  2. 打开 Python 窗口。

  3. 导入 arcpy.mapping 模块:

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

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

    for df in mapping.ListDataFrames(mxd):
      if df.name == "Test_Performance":
        mapping.PrintMap(mxd,"",df)
    

工作原理...

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

将地图导出为 PDF 文件

与将地图或布局视图发送到打印机相比,你可能只想简单地创建可以共享的 PDF 文件。Arcpy 映射提供了 ExportToPDF() 函数,你可以使用它来做到这一点。

准备工作

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

如何做到这一点…

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

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

  2. 打开 Python 窗口。

  3. 导入 arcpy.mapping 模块:

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

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

    mapping.ExportToPDF(mxd,r"c:\ArcpyBook\Ch5\Map_PageLayout.pdf").
    
  6. 运行脚本。

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

  8. 现在,我们将从我们的地图文档文件中打印一个特定的数据框架。修改你的脚本,使其看起来如下:

    import arcpy.mapping as mapping
    mxd = mapping.MapDocument('CURRENT')
    for df in mapping.ListDataFrames(mxd):
      if df.name == "Crime":
        mapping.ExportToPDF(mxd,r"c:\ArcpyBook\Ch5\DataFrameCrime.pdf",df)
    
  9. 运行脚本并检查输出 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\Ch5\Crime_Ch5.mxd

  2. 打开 Python 窗口。

  3. 导入arcpy.mapping模块:

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

    mxd = mapping.MapDocument("CURRENT")
    
  5. Crime数据框导出为 JPEG 图像:

    for df in mapping.ListDataFrames(mxd):
      if df.name == "Crime":
        mapping.ExportToJPEG(mxd,r"c:\ArcpyBook\Ch5\DataFrameCrime.jpg",df)
    
  6. 运行脚本并检查输出文件。

  7. 现在,我们将使用一个可选参数,该参数将输出一个与图像一起的world文件。修改您的脚本,使其如下所示:

    import arcpy.mapping as mapping
    mxd = mapping.MapDocument("CURRENT")
    for df in mapping.ListDataFrames(mxd):
      if df.name == "Crime":
        mapping.ExportToPDF(mxd,r"c:\ArcpyBook\Ch5\DataFrameCrime2.jpg",df,world_file=True)
    
  8. 运行脚本。将创建一个名为DataFrameCrime.jpg的新文件。在文本编辑器中打开此文件,您应该看到以下内容:

    470.520239851286190
    0.000000000000000
    0.000000000000000
    -496.256971063348490
    1972178.761771137800000
    13815440.387677660000000
    
    

工作原理...

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

使用PDFDocumentCreate()PDFDocumentOpen()创建地图册

对于许多 GIS 专业人士来说,一个常见的场景是需要创建一个可以与他人共享的地图册。地图册仅仅是特定区域的地图集合,通常还包含一个索引图。地图册通常使用 PDF 文件创建,因为它们是一种常见的交换格式。

准备工作

除了将您的地图导出为 PDF 外,您还可以操作现有的 PDF 文档或创建新的 PDF 文档。您可以合并页面、设置文档打开行为、添加文件附件以及创建或更改文档安全设置。PDFDocumentOpen()函数用于打开现有 PDF 文件进行操作。PDFDocumentCreate()创建一个新的 PDF 文档。这些函数通常用于创建地图册,这正是本教程中我们将要做的。

如何操作...

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

  2. 导入arcpy.mappingos模块:

    import arcpy.mapping as mapping
    import os
    
  3. 设置地图册的路径和文件名。如果文件已存在,则删除该文件:

    pdfPath = r"C:\ArcpyBook\Ch5\CrimeMapBook.pdf"
    if os.path.exists(pdfPath):
      os.remove(pdfPath)
    
  4. 创建 PDF 文档:

    pdfDoc = mapping.PDFDocumentCreate(pdfPath)
    
  5. 将现有的 PDF 页面追加到文档中:

    pdfDoc.appendPages(r"c:\ArcpyBook\Ch5\Map_PageLayout.pdf")
    pdfDoc.appendPages(r"c:\ArcpyBook\Ch5\Map_DataFrameCrime.pdf")
    
  6. 提交地图册的更改:

    pdfDoc.saveAndClose()
    
  7. 整个脚本应该如下所示:

    import arcpy.mapping as mapping
    import os
    pdfPath = r"C:\ArcpyBook\Ch5\CrimeMapBook.pdf"
    if os.path.exists(pdfPath):
      os.remove(pdfPath)
    pdfDoc = mapping.PDFDocumentCreate(pdfPath)
    pdfDoc.appendPages(r"c:\ArcpyBook\Ch5\Map_PageLayout.pdf")
    pdfDoc.appendPages(r"c:\ArcpyBook\Ch5\Map_DataFrameCrime.pdf")
    pdfDoc.saveAndClose()
    
  8. 运行脚本。

  9. 查看位于 c:\ArcpyBook\Ch5\CrimeMapBook.pdf 的新地图册。这本书现在应该包含两个页面,包含我们在之前的菜谱中创建的 PDF 文件。

它是如何工作的...

PDFDocumentCreate() 函数通过提供文档的路径和文件名来创建一个新的 PDF 文档。实际上,PDF 文件直到你插入或附加页面并调用 PDFDocument.saveAndClose() 后才会被创建在磁盘上。appendPages()insertPages() 函数用于插入和附加页面。

PDFDocumentOpen() 接受一个参数,指定 PDF 文件的路径,并返回 PDFDocument 类的一个实例。一旦打开,你可以修改 PDF 文件属性,添加或插入文件,并附加文档。确保在所有操作完成后调用 PDFDocument.saveAndClose() 以保存更改。

还有更多…

可以通过 PDFDocument 对象设置 PDF 文档的多个属性,包括获取页面数、附加文件、更新标题、作者、主题、关键词、打开行为和布局。你还可以通过调用 PDFDocument.updateDocSecurity() 来更新文档安全性,设置密码、加密和安全限制。

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

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

  • 查找地理处理工具

  • 获取工具箱别名

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

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

  • 设置环境变量

简介

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

查找地理处理工具

在您的地理处理脚本中使用工具之前,您需要确保您有权访问该工具,这取决于您正在运行的 ArcGIS Desktop 当前许可级别或您的最终用户将运行的许可级别。此信息包含在 ArcGIS Desktop 帮助系统中。

准备工作

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

如何操作…

  1. 在 ArcMap 中打开 C:\ArcpyBook\Ch6\Crime_Ch6.mxd

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

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

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

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

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

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

它是如何工作的…

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

注意

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

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

工作原理…

获取工具箱别名

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

准备工作

在上一个菜谱中,我们探讨了 Clip 工具。实际上有三个 Clip 工具可以在 Analysis, CoverageData Management 工具箱中找到。每个 Clip 工具执行不同的功能。例如,Analysis 工具箱中的 Clip 工具使用输入要素裁剪矢量要素类,而 Data Management 工具箱中的 Clip 工具用于创建栅格的空间子集。由于可能存在具有相同名称的多个工具,我们可以通过提供工具名称和工具所在工具箱的别名来唯一地识别特定工具。在这个菜谱中,您将学习如何查找工具箱的别名。

如何操作…

  1. 在 ArcMap 中打开 C:\ArcpyBook\Ch6\Crime_Ch6.mxd

  2. 如果需要,打开 ArcToolbox

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

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

工作原理…

您可以遵循以下过程来查找任何工具箱的别名。在 Python 脚本中,您可以通过使用 <toolname>_<toolbox alias> 语法来执行工具。例如,如果您正在调用 Buffer 工具,它将是 buffer_analysis。工具箱别名总是简单的。它们通常是单个单词,不包含破折号或特殊字符。在下一个菜谱中,我们将创建一个简单的脚本,用于按照此格式执行工具。

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

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

准备工作

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

如何操作…

  1. 在 ArcMap 中打开 C:\ArcpyBook\Ch6\Crime_Ch6.mxd

  2. 点击 Add Data 按钮,并将 EdgewoodSD.shp 文件添加到目录表中。

  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/Ch6/EdgewoodSD.shp"
    
  8. 创建一个变量来引用输出要素类:

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

    arcpy.Clip_analysis(in_features,clip_features,out_feature_class)
    
  10. 运行脚本。包含仅限于 Edgewood 学区内的那些盗窃点的输出要素类应添加到数据框中,如下截图所示:如何做…

它是如何工作的…

在本食谱中,我们感兴趣的代码的主要行是执行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)

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

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

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

准备工作

Buffer工具使用指定的距离从一个输入要素类创建输出要素类。这个输出要素类可以存储在一个变量中,然后可以将其用作另一个工具的输入,例如Select Layer by Location工具。在这个菜谱中,你将学习如何将Buffer工具的输出用作Select Layer by Location工具的输入,以找到所有位于河流半英里范围内的学校。

如何操作...

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

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

  2. 点击添加数据按钮并将StreamsSchools要素类从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"
    
  7. 调用Buffer工具并传入河流图层、缓冲河流图层、距离以及控制缓冲区外观的几个变量:

    arcpy.Buffer_analysis(streams, streamsBuffer, distance,'FULL','ROUND','ALL')
    
  8. 使用Make Feature Layer工具为学校创建一个临时图层:

    arcpy.MakeFeatureLayer_management(schools2mile, 'Schools2Mile_lyr')
    
  9. 使用Select Layer by Location工具选择所有位于河流半英里范围内的学校:

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

    except:
      print 'Error in script'
    
  11. 整个脚本应如下所示:

    import arcpy
    arcpy.env.workspace = "c:/ArcpyBook/data/TravisCounty"
    try:
      # Buffer areas of impact around major roads
      streams = "Streams.shp"
      streamsBuffer = "StreamsBuffer.shp"
      distance = "2640 Feet"
      schools2mile = "Schools.shp"
    
      arcpy.Buffer_analysis(streams, streamsBuffer, distance,'FULL','ROUND','ALL')
    
      # Make a layer
      arcpy.MakeFeatureLayer_management(schools2mile, 'Schools2Mile_lyr') 
      arcpy.SelectLayerByLocation_management('Schools2Mile_lyr', 'intersect', streamsBuffer)
    except:
      print 'Error in script'
    

它是如何工作的...

Buffer工具创建一个输出要素类,我们将其命名为StreamsBuffer.shp并存储在一个名为streamsBuffer的变量中。然后,这个streamsBuffer变量被用作Select Layer by Location工具的输入,作为传递给函数的第三个参数。使用一个工具的输出只需要创建一个变量来保存输出数据,然后它可以在其他工具中按需重复使用。

设置环境变量和检查工具消息

环境变量提供可以设置的附加参数,这些参数作为全局变量在各个级别(包括您的脚本)中可访问。您的脚本可以获取环境变量的值以及设置值。您需要了解可供您的脚本使用的环境变量以及如何访问它们。此外,工具在执行过程中会生成消息。这些消息有多种类型。

准备工作

环境设置是在执行期间可供您的脚本使用的附加参数。这些是在 ArcGIS 桌面应用程序级别使用单独的对话框设置的值,该对话框通过“地理处理 - 环境”菜单项访问,并按类别组织:

准备工作

这些设置与您可以在操作系统级别设置的类似的环境变量设置非常相似,但它们是针对 ArcGIS 地理处理框架的特定设置。这些应用程序级别的环境设置是最高级别的,并且在执行任何工具时都会应用所有工具的默认设置。除了应用程序级别的环境设置之外,您还可以在工具级别应用环境设置。工具级别的环境设置直接继承应用程序级别应用的设置。然而,这些设置可以在工具级别被覆盖。工具级别的设置仅适用于当前工具的执行。您的 Python 脚本可以通过 arcpy 中的 env 类获取和设置环境设置。这些都是读写属性。应用程序和工具级别的设置都会传递到脚本中,并将应用于您从脚本中运行的任何工具。您还可以在脚本内部覆盖任何环境设置,这些设置将在脚本执行期间应用。请注意,与工具一样,仅在脚本级别设置的环境设置仅适用于脚本当前执行。然而,有两种情况下环境设置不会传递到脚本。这包括在 ArcGIS 应用程序之外运行的脚本,例如,当它们从操作系统命令提示符运行时。此外,当脚本调用另一个脚本时,环境设置不会传递。在本食谱中,您将学习如何从您的 Python 脚本中设置环境设置并查看工具在执行期间生成的各种消息。

如何操作…

按照以下步骤学习如何在脚本中设置环境设置并生成消息:

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

  2. 导入 arcpy 模块:

    import arcpy
    
  3. 使用环境变量设置工作空间:

    arcpy.env.workspace = "c:/ArcpyBook/Ch6"
    
  4. 调用 Buffer 工具,传入输入数据集 Streams.shp,输出数据集 Streams_Buff.shp,以及距离 200 英尺。

    arcpy.Buffer_analysis("Streams.shp","Streams_Buff,’200 Feet’")
    
  5. 保存脚本。

它是如何工作的…

环境变量可以在应用程序级别和工具级别进行设置。应用程序级别的环境设置类似于全局环境设置;在于它们影响所有工具。另一方面,在工具级别定义的环境设置仅影响工具的当前运行。两者都可以使用 ArcGIS Desktop 进行设置。您的脚本也可以设置环境变量,这些变量仅在脚本执行期间适用。它们类似于在工具级别设置的环境变量。可能,在脚本中最常设置的环境变量是 env.workspace 变量,它定义了脚本的当前工作目录。在脚本顶部设置此变量可以使您的代码更加简洁,因为您不必不断引用数据集的完整路径,而只需简单地引用当前工作空间中定义的数据集名称。

第七章。创建自定义地理处理工具

在本章中,我们将介绍以下配方:

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

简介

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

创建自定义地理处理工具

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

准备工作

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

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

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

如何操作…

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

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

  2. 在 ArcToolbox 的空白区域中右键单击,然后选择添加工具箱。在添加工具箱对话框中,单击新建工具箱按钮。这将创建一个名为 Toolbox.tbx 的默认名称的新工具箱;您将在下一步中重命名工具箱:如何操作…

  3. 导航到 c:\ArcpyBook\Ch7 文件夹,并将工具箱命名为 Wildfire Tools如何操作…

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

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

    注意

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

  6. 在此下一步中,我们将修改一个名为InsertWildfires.py的现有 Python 脚本,以便接受通过 ArcToolbox 界面由工具用户提供的动态输入。在 IDLE 中打开c:\ArcpyBook\Ch7\InsertWildfires.py

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

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

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

    cur = arcpy.InsertCursor("FireIncidents")
    

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

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

    try:
      # the output feature class name
      outputFC = arcpy.GetParameterAsText(0)
    
      # the template feature class 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)。此工具将创建包含用户定义的输出要素类的空要素类。

  9. 您还需要修改创建InsertCursor对象的代码行。将行更改为以下内容:

    cur = arcpy.InsertCursor(outputFC)
    
  10. 整个脚本应如下所示:

    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()
      cur = arcpy.InsertCursor(outputFC)
      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:
      del cur
      f.close()
    

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

  11. 在 ArcToolbox 中,右键单击你之前创建的Wildfire Tools自定义工具箱,然后选择添加 | 脚本。这将显示添加脚本对话框,如图下所示。给你的脚本一个名称、标签和描述。名称字段不能包含任何空格或特殊字符。标签是显示在脚本旁边的名称。对于这个例子,给它一个标签为 Load Wildfires From Text。最后,添加一些描述性信息,详细说明脚本将执行的操作。

  12. 请参阅以下截图以获取名称标签描述的详细信息:如何操作…

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

  14. 在此对话框中,你将指定将附加到工具的脚本。导航到 c:\ArcpyBook\Ch7\InsertWildfires.py 并将 InsertWildfires.py 添加为脚本。

  15. 你还需要确保选择勾选了在进程中运行 Python 脚本复选框,如图下所示。在进程中运行 Python 脚本可以提高脚本的性能。如何操作…

    注意

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

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

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

    outputFC = arcpy.GetParameterAsText(0)
    

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

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

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

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

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

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

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

  23. 您还需要为新要素类提供一个名称。在这种情况下,我们将要素类命名为TodaysWildfires,但名称可以是您想要的任何名称。在以下截图中,您可以看到一个示例,说明如何进行此操作。点击保存按钮:如何操作…

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

  25. 最后,最后一个参数需要指向包含野火信息的逗号分隔的文本文件。此文件可在以下位置找到:c:\ArcpyBook\data\Wildfires\NorthAmericaWildfires_2007275.txt。点击浏览按钮,导航到c:\ArcpyBook\data\Wildfires。点击NorthAmericaWildfires_2007275.txt,然后点击添加按钮。

    您的工具应如下所示:

    如何操作…

  26. 点击确定以执行工具。任何消息都将写入到如下截图所示的对话框中。这是任何地理处理工具的标准对话框。如果一切设置正确,您应该看到如下截图,显示将有一个新的要素类添加到 ArcMap 显示中:如何操作…

如果一切设置正确,您应该看到如下截图,显示将有一个新的要素类添加到 ArcMap 显示中:

如何操作…

它是如何工作的…

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

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

还有更多...

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

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

第八章。查询和选择数据

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

  • 构建正确的属性查询语法

  • 创建要素图层和表格视图

  • 使用“按属性选择图层”工具选择特征和行

  • 使用“按位置选择”工具选择特征

  • 使用“按位置选择”工具结合空间和属性查询

简介

从地理图层选择特征或从独立属性表中选择行是 GIS 操作中最常见的操作之一。查询被创建以启用这些选择,可以是属性查询或空间查询。属性查询使用 SQL 语句通过使用数据集中一个或多个字段或列来选择特征或行。一个属性查询的例子可能是“选择所有价值超过 500,000 美元的土地地块”。空间查询用于根据某种空间关系选择特征。一个例子可能是“选择所有与 100 年一遇洪水平原相交的土地地块”或“选择所有完全位于德克萨斯州特拉维斯县的道路”。也可以将属性查询和空间查询结合起来。一个例子可能是“选择所有与 100 年一遇洪水平原相交且价值超过 500,000 美元的土地地块”。

构建正确的属性查询语法

构建属性查询对于您成功创建查询特征类和表的地理处理脚本至关重要。您对特征类和表执行的任何属性查询都需要正确的 SQL 语法,并且根据您执行的查询的数据类型,还需要遵循各种规则。

准备工作

创建属性查询的语法是在创建包含使用 按属性选择 工具的 Python 脚本时需要掌握的最困难且耗时最长的任务之一。这些查询基本上是 SQL 语句,以及一些你需要掌握的特殊性。如果你已经很好地理解了在 ArcMap 中创建查询或者在其他编程语言中创建 SQL 语句的经验,那么这对你来说会容易一些。除了创建有效的 SQL 语句外,你还需要了解一些特定的 Python 语法要求以及一些数据类型差异,这会导致某些数据类型的语句格式略有改变。在本食谱中,你将学习如何构建有效的查询语法,并了解不同数据类型如何改变语法以及一些 Python 特定的结构。

如何操作…

首先,我们将查看在 ArcMap 中如何构建查询,这样你可以了解它们的结构。

  1. 在 ArcMap 中,打开 C:\ArcpyBook\Ch8\Crime_Ch8.mxd

  2. 右键单击2009 年发生的盗窃事件图层,选择打开属性表。你应该会看到一个类似于以下截图的属性表。我们将查询SVCAREA字段:如何操作…

  3. 在属性表打开的情况下,选择表选项按钮,然后选择按属性选择以显示一个对话框,该对话框将允许你构建一个属性查询。

    注意查询对话框(如下面的截图所示)上的Select * FROM Burglary WHERE:语句。这是一个基本的 SQL 语句,它将返回所有满足我们通过查询构建器定义的条件的Burglary属性表中的列。星号(****)简单地表示将返回所有字段:

    如何操作…

  4. 确保在方法下拉列表中选中的是创建新选择项。这将创建一个新的选择集。

  5. 双击列表中的SVCAREA字段,将其添加到 SQL 语句构建器中,如下所示:如何操作…

  6. 点击=按钮。

  7. 点击获取唯一值按钮。

  8. 从生成的值列表中双击'North'以完成 SQL 语句,如下面的截图所示:如何操作…

  9. 点击应用按钮以执行查询。这应该选择 7520 条记录。

    许多人错误地认为可以将以这种方式生成的查询直接粘贴到 Python 脚本中。事实并非如此。我们将讨论一些重要的差异。

  10. 关闭按属性选择窗口和2009 年发生的盗窃事件表。

  11. 通过点击选择 | 清除所选要素来清除所选要素集。

  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是查询中使用的唯一字段,并且已经用双引号括起来了。当你处理 shapefiles、文件地理数据库或 ArcSDE 地理数据库时,情况总是如此。然而,这里有一点可能会让人感到困惑。如果你正在处理个人地理数据库中的数据,字段名需要用方括号而不是双引号括起来,如下面的代码示例所示。这可能会给脚本开发者带来一定的困惑。

qry = [SVCAREA] = 'North'

现在,我们需要处理围绕 'North' 的单引号。当从具有 text 数据类型的字段查询数据时,被评估的字符串必须用引号括起来。如果你检查原始查询,你会注意到我们实际上已经用引号括起了单词 North,所以一切应该没问题吧?不幸的是,在 Python 中并不是那么简单。引号,以及许多其他字符,必须用反斜杠后跟被转义的字符来转义。在这种情况下,转义序列将是 \'

  1. 修改你的查询语法以包含转义序列:

    qry = "SVCAREA" = \'North\'
    
  2. 最后,整个查询语句应该用引号括起来:

    qry = '"SVCAREA" = \'North\''
    

除了用于测试相等的 = 符号之外,还有许多其他运算符可以与字符串和数值数据一起使用,包括不等于 (< >), 大于 (>), 大于等于 (>=), 小于 (<), 和小于等于 (<=)。

通配符字符包括 %_ 也可以用于 shapefile、文件地理数据库和 ArcSDE 地理数据库。这些包括 % 用于表示任意数量的字符。LIKE 运算符常与通配符字符一起使用,以执行部分字符串匹配。例如,以下查询将找到所有服务区域以 N 开头且后面跟有任意数量字符的记录。

qry = '"SVCAREA" LIKE \'N%\''

下划线字符 (_) 可以用来表示单个字符。对于个人地理数据库,星号 (*) 用于表示任意数量字符的通配符,而 (?) 表示单个字符。

你还可以查询数据缺失的情况,也称为 NULL 值。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 表或在地理数据库中。两者,表和要素类,都包含属性信息。然而,表只包含属性信息。与表关联的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\Ch8\Crime_Ch8.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:
      print "An error occurred during creation"
    
  8. 整个脚本应如下所示:

    import arcpy
    arcpy.env.workspace = "c:/ArcpyBook/data/CityOfSanAntonio.gdb"
    try:
      flayer = arcpy.MakeFeatureLayer_management("Burglary","Burglary_Layer")
    except:
      print "An error occurred during creation"
    
  9. 将脚本保存到c:\ArcpyBook\Ch8\CreateFeatureLayer.py

  10. 运行脚本。新的Burglary_Layer文件将被添加到 ArcMap 的内容表中:如何操作…

  11. 创建表视图工具的功能与创建要素图层工具等效。区别在于它针对独立表而不是要素类。

  12. 删除以下代码行:

    flayer = arcpy.MakeFeatureLayer_management("Burglary","Burglary_Layer")
    
  13. 在其位置添加以下代码行:

    tView = arcpy.MakeTableView_management("Crime2009Table","Crime2009TView")
    
  14. 运行脚本以查看添加到 ArcMap 内容表的表视图。

它是如何工作的...

创建要素图层创建表视图工具分别创建要素类和表的内存表示。按属性选择按位置选择工具在从 Python 脚本调用时都需要将这些临时内存结构作为参数传递。这两个工具还要求您传递临时结构的名称。

还有更多...

您还可以将查询应用于创建要素图层创建表视图工具,以限制在要素图层或表视图中返回的记录。这是通过在脚本中调用这两个工具时添加where子句来完成的。此查询与您通过图层属性 | 定义查询在图层上设置定义查询时设置的定义查询非常相似。

添加查询的语法如下:

MakeFeatureLayer(in_features, out_layer, where_clause)
MakeTableView(in_table, out_view, where_clause)

使用按属性选择图层工具选择要素和行

可以通过使用按属性选择图层工具来对要素类或表执行属性查询。可以包含一个where子句来过滤所选记录,并可以包含各种选择类型。

准备工作

下面的屏幕截图显示的按属性选择图层工具用于根据您定义的查询从要素类或表中选择记录。我们在本章前面的配方中介绍了查询的相对复杂主题,因此希望您现在已经理解了创建查询的基本概念。您还学习了如何创建要素类或表的临时内存表示,这是使用按属性选择按位置选择工具的先决条件。

准备工作

按属性选择工具使用查询以及要素图层或表视图和一个选择方法来选择记录。默认情况下,选择方法将是一个新的选择集。其他选择方法包括“添加到选择”、“从选择中删除”、“子集选择”、“切换选择”和“清除选择”。每种选择方法如下总结:

  • NEW_SELECTION:这是默认选择方法,创建一个新的选择集

  • ADD_TO_SELECTION:根据查询将选择集添加到当前所选记录中

  • REMOVE_FROM_SELECTION:根据查询从选择集中删除记录

  • SUBSET_SELECTION:它将现有选择集中共有的所选记录组合起来

  • SWITCH_SELECTION:选择当前未选择的记录,并取消选择现有选择集

  • CLEAR_SELECTION:它清除当前选择集中的所有记录

调用 Select by Attributes 工具的语法如下:

arcpy.SelectLayerByAttribute_management(<input feature layer or table view>, {selection method}, {where clause})

在这个示例中,你将学习如何使用 Select by Attributes 工具从要素类中选择要素。你将使用在之前的示例中学到的技能来构建查询、创建要素层,并最终调用 Select by Attributes 工具。

如何操作…

按照以下步骤学习如何使用 Select Layer by Attributes 工具从表格或要素类中选择记录:

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

  2. 将脚本保存到 c:\ArcpyBook\Ch8\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. 调用 Select Layer by Attribute 工具,传入我们刚刚创建的要素层的引用。将其定义为一个新的选择集,并传入查询的引用:

    arcpy.SelectLayerByAttribute_management(flayer, "NEW_SELECTION", qry)
    
  9. 使用 Get Count 工具打印图层中选中的记录数:

    cnt = arcpy.GetCount_management(flayer)
    print "The number of selected records is: " + str(cnt)
    
  10. 添加一个 except 块和一行代码,以便在出现问题时打印错误消息:

    except:
      print "An error occurred during selection"
    
  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:
      print "An error occurred during selection"
    
  12. 保存脚本。

  13. 运行脚本。如果一切操作正确,你应该会看到一个消息,表明已选中 7520 条记录:

    The total number of selected records is: 7520
    
    

它是如何工作的…

Select by Attributes 工具要求传入一个要素层或表格视图作为第一个参数。在这个示例中,我们传入了一个由上一行中的 Make Feature Layer 工具创建的要素层。我们使用 Make Feature Layer 工具从 Burglary 要素类中创建了一个要素层。这个要素层被分配给变量 flayer,然后作为第一个参数传递给 Select by Attribute 工具。在这个脚本中,我们还传入了一个参数,表示我们希望创建一个新的选择集,以及 final 参数,它是一个 where 子句。where 子句在 qry 变量中指定。这个变量包含一个查询,将选择所有服务区域为 North 的要素。

使用 Select by Location 工具选择要素

如下截图所示的 Select Layer by Location 工具可以用于根据某种空间关系选择要素。由于它处理空间关系,此工具仅适用于要素类及其对应的内存要素层。

准备工作

在使用按位置选择工具选择要素时,你可以应用许多不同类型的空间关系,包括相交、包含、在内部、边界接触、相同,以及许多其他关系。如果没有指定,将应用默认的相交空间关系。输入要素层是唯一必需的参数,但还有许多可选参数,包括空间关系、搜索距离、要测试输入层的要素层或要素类,以及选择类型。在本菜谱中,你将学习如何在 Python 脚本中使用按位置选择工具根据空间关系选择要素。你将使用该工具选择位于 Edgewood 学区边界内的入室盗窃案件。

准备就绪

如何做到这一点...

按照以下步骤学习如何使用按位置选择工具执行空间查询:

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

  2. 将脚本保存到c:\ArcpyBook\Ch8\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. 调用按位置选择图层工具,传入我们刚刚创建的要素层的引用。空间关系测试将是COMPLETELY_WITHIN,这意味着我们想要找到所有完全位于比较层边界内的入室盗窃案件。将EdgewoodSD.shp定义为比较层:

    arcpy.SelectLayerByLocation_management (flayer, "COMPLETELY_WITHIN", "c:/ArcpyBook/Ch8/EdgewoodSD.shp")
    
  8. 使用获取计数工具在图层中打印所选记录的数量:

    cnt = arcpy.GetCount_management(flayer)
    print "The number of selected records is: " + str(cnt)
    
  9. 添加一个except块和一行代码,以便在出现问题时打印错误消息:

    except:
      print "An error occurred during selection"
    
  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/Ch8/EdgewoodSD.shp")
      cnt = arcpy.GetCount_management(flayer)
      print "The number of selected records is: " + str(cnt)
    except:
      print "An error occurred during selection"
    
  11. 保存脚本。

  12. 运行脚本。如果一切操作正确,你应该会看到一个消息指示已选择 1470 条记录:

    The total number of selected records is: 1470
    
    

在这种情况下,我们没有定义可选的搜索距离和选择类型参数。默认情况下,将应用新的选择作为选择类型。在这种情况下,我们没有应用距离参数,但现在我们将这样做以说明它是如何工作的。

  1. 更新调用按位置选择图层工具的代码行:

    arcpy.SelectLayerByLocation_management (flayer, "WITHIN_A_DISTANCE", "c:/ArcpyBook/Ch8/EdgewoodSD.shp","1 MILES")
    
  2. 保存脚本。

  3. 运行脚本。如果一切操作正确,你应该会看到一个消息指示已选择 2976 条记录。这将选择所有位于 Edgewood 学区边界内的入室盗窃案件,以及任何位于边界一英里内的入室盗窃案件:

    The total number of selected records is: 2976
    
    

在本节中,你将完成的最后一件事是使用复制要素工具将临时图层写入新的要素类。

  1. 注释掉获取要素数量并打印到屏幕上的两行代码:

    ## cnt = arcpy.GetCount_management(flayer)
    ## print "The number of selected records is: " + str(cnt)
    
  2. 添加一行代码调用复制要素工具。这一行应放在调用选择层位置工具的代码行下方。复制要素工具接受一个要素层作为第一个输入参数和一个输出要素类,在这个例子中,将是一个名为EdgewoodBurglaries.shp的形状文件:

    arcpy.CopyFeatures_management(flayer, 'c:/ArcpyBook/Ch8/EdgewoodBurglaries.shp')
    
  3. 整个脚本现在应如下所示。请记住,包括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/Ch8/EdgewoodSD.shp","1 MILES")
      arcpy.CopyFeatures_management(flayer, 'c:/ArcpyBook/Ch8/EdgewoodBurglaries.shp')
    	#cnt = arcpy.GetCount_management(flayer)
     #print "The total number of selected records is: " + str(cnt)
    except:
      print "An error occurred during selection"
    
  4. 保存脚本。

  5. 运行脚本。

  6. 检查你的c:\ArcpyBook\Ch8文件夹以查看输出要素形状文件:如何操作…

它是如何工作的…

选择位置工具需要将要素层作为第一个参数传入。在这个菜谱中,我们传入了一个由上一行中的创建要素层工具创建的要素层。我们使用创建要素层Burglary要素类创建要素层。这个要素层被分配给变量flayer,然后作为第一个参数传递给选择位置工具。在这个脚本中,我们还传入了一个参数,表示我们想要应用的空間关系。最后,我们还定义了一个用于空間关系比较的源层。其他可以应用的可选参数包括搜索距离和选择类型。

使用选择位置工具结合空间和属性查询

有时候你可能想使用组合的属性和空间查询来选择要素。例如,你可能想选择在周一发生的所有位于 Edgewood 学区内的盗窃事件。这可以通过依次运行选择位置选择属性工具并应用SUBSET SELECTION选择类型来实现。

准备工作

这个菜谱将需要你创建一个作为临时层的要素层,它将被用于选择位置选择层属性工具。选择位置工具将找到所有位于 Edgewood 学区内的盗窃事件,并将选择集应用于这些要素。选择层属性工具使用相同的临时要素层,并应用一个where子句来找到所有发生在周一的盗窃事件。此外,工具还指定选择应该是选择位置工具找到的当前选定要素的子集。最后,你将打印出由组合的空间和属性查询选定的记录总数。

如何操作...

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

  2. 将脚本保存为c:\ArcpyBook\Ch8\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/Ch8/EdgewoodSD.shp")
    
  9. 执行 按属性选择图层 工具以找到所有与我们在 qry 变量中先前定义的查询匹配的盗窃事件。这应该定义为子集查询:

    arcpy.SelectLayerByAttribute_management(flayer, "SUBSET_SELECTION", qry)
    
  10. 打印所选记录的数量:

    cnt = arcpy.GetCount_management(flayer)
    
  11. 添加 except 块:

    except:
      print 'Error in selection'
    

    整个脚本应如下所示:

    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/Ch8/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:
      print 'Error in selection'
    
  12. 保存并运行脚本。

    如果一切操作正确,你应该会看到一个消息,表明已选择了 197 条记录。这将选择在周一发生的,位于 Edgewood 学区边界内的所有盗窃事件。

    The total number of selected records is: 197
    
    

它是如何工作的...

使用 创建要素图层 工具创建一个新的要素图层,并将其分配给变量 flayer。这个临时图层随后被用作 按位置选择 工具的输入,同时使用空间运算符 COMPLETELY_WITHIN,以找到 Edgewood 学区内的所有盗窃事件。然后,使用已经定义了选择集的相同要素图层作为 按属性选择图层 工具的输入参数。除了传递要素图层的引用外,按属性选择图层 工具还传递了一个参数,用于定义选择类型和 where 子句。选择类型设置为 SUBSET_SELECTION。这种选择类型创建了一个新的选择,并将其与现有选择合并。只有两者共有的记录才会被选中。作为第三个参数传入的 where 子句是一个属性查询,用于找到所有在周一发生的盗窃事件。查询使用 DOW 字段,寻找值为 Mon 的值。最后,使用 获取计数 工具对 flayer 变量进行操作,以获取所选记录的数量,并将其打印到屏幕上。

第九章:使用 ArcPy 数据访问模块选择、插入和更新地理数据和表

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

  • 游标对象概述

  • 使用 SearchCursor 从要素类中检索特征

  • 使用 where 子句过滤记录

  • 使用几何标记提高游标性能

  • 使用 InsertCursor 插入行

  • 使用 UpdateCursor 更新行

  • 使用 UpdateCursor 删除行

  • 在编辑会话中插入和更新行

  • 从要素类中读取几何形状

简介

我们将从本章的基本问题开始。什么是游标?游标是包含来自表或要素类中的一行或多行数据的内存对象。每一行包含数据源中每个字段的属性,以及每个要素的几何形状。游标允许您从表和要素类中搜索、添加、插入、更新和删除数据。

ArcPy 数据访问模块或 arcpy.da 是 ArcGIS 10.1 中新增的,它包含允许您遍历游标中每一行的方法。可以创建各种类型的游标。例如,可以创建搜索游标来读取行中的值。可以创建更新游标来更新行中的值或删除行,也可以创建插入游标来插入新行。

ArcPy 数据访问模块引入了许多游标改进。在 ArcGIS 10.1 之前,游标性能一直很慢。现在,游标的速度显著提高。Esri 估计,搜索游标的速度提高了高达 30 倍,而插入游标的速度提高了高达 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()方法来删除一行。

数据锁的主题需要稍作解释。插入和更新游标必须对其引用的数据源获取锁。这意味着没有其他应用程序可以同时访问此数据源。锁是防止多个用户同时更改数据并因此损坏数据的一种方式。当在您的代码中调用InsertCursor()UpdateCursor()方法时,Python 会尝试获取数据的锁。此锁必须在游标完成处理之后特别释放,以便其他运行ArcMapArcCatalog等应用程序的用户可以访问数据源。否则,其他应用程序将无法访问数据。在 ArcGIS 10.1 和with语句之前,游标必须通过 Python 的del语句特别解锁。同样,ArcMapArcCatalog在更新或删除数据时也会获取数据锁。如果数据源被这些应用程序中的任何一个锁定,您的 Python 代码将无法访问数据。因此,最佳实践是在运行任何使用插入或更新游标的独立 Python 脚本之前关闭ArcMapArcCatalog

在本章中,我们将介绍使用游标访问和编辑表和要素类的方法。然而,在 ArcGIS 10.1 之前存在的许多游标概念仍然适用。

使用 SearchCursor 从要素类检索要素

有许多场合需要从表或要素类中检索行以进行只读操作。例如,您可能想生成一个包含价值超过 100,000 美元的所有城市土地地块的列表。在这种情况下,您不需要编辑数据。您的需求仅通过生成满足某些条件的行列表即可满足。

准备工作

SearchCursor()函数用于返回一个SearchCursor对象。此对象只能用于遍历为只读目的返回的行集。通过此对象不能进行插入、删除或更新操作。可以设置一个可选的where子句来限制返回的行。在本食谱中,您将学习如何通过使用SearchCursor()函数在要素类上创建一个基本的SearchCursor对象。

SearchCursor 对象包含一个 fields 属性以及 next()reset() 方法。fields 属性是一个只读结构,形式为 Python 元组,包含从要素类或表中请求的字段。您将经常在游标相关的上下文中听到术语元组。如果您之前没有覆盖这个主题,元组是用于存储类似 Python 列的数据序列的 Python 结构。但 Python 元组和列表之间有一些重要的区别。元组定义为括号内的值序列,而列表定义为方括号内的值序列。与列表不同,元组不能增长和缩小,这在某些情况下可能是一个非常好的事情,当您希望数据值每次都占据特定位置时。这种情况适用于使用元组存储来自表和要素类字段数据的游标对象。

如何操作...

按照以下步骤学习如何在 SearchCursor 对象内部检索表或要素类的行:

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

  2. 将脚本保存为 c:\ArcpyBook\Ch9\SearchCursor.py

  3. 导入 arcpy.da 模块:

    import arcpy.da
    
  4. 设置工作空间:

    arcpy.env.workspace = "c:/ArcpyBook/Ch9"
    
  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. 保存脚本。

  8. 运行脚本。你应该会看到以下输出:

    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. 通过添加一个查询facility字段的where子句来更新SearchCursor()函数,以查询具有文本High School的记录:

    with arcpy.da.SearchCursor("Schools.shp",("Facility","Name"), '"FACILITY" = \'HIGH SCHOOL\'') as cursor:
    
    
  3. 保存并运行脚本。现在输出将大大减小,仅限于那些高中:

    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 中被引入,作为游标性能改进的一部分。而不是在游标内返回要素的整个几何形状,只返回几何形状的一部分。返回要素的整个几何形状可能会导致游标性能下降,因为需要返回的数据量很大。只返回所需的几何形状要快得多。

准备工作

令牌作为传递给游标构造函数的field列表中的一个字段提供,其格式为SHAPE@<要返回的要素部分>。此格式的唯一例外是OID@令牌,它返回要素的对象 ID。以下代码示例检索要素的 x 和 y 坐标:

with arcpy.da.SearchCursor(fc, ("SHAPE@XY","Facility","Name")) as cursor:

以下表格列出了可用的几何令牌。并非所有游标都支持完整的令牌列表。请查阅 ArcGIS 帮助文件以获取有关每个游标类型支持的令牌的信息。SHAPE@令牌返回要素的整个几何形状。尽管如此,请谨慎使用,因为返回要素整个几何形状是一个昂贵的操作,可能会显著影响性能。如果你不需要整个几何形状,则不要包含此令牌!

准备工作

在这个菜谱中,你将使用几何令牌来提高游标性能。你将从parcels要素类中检索每个地块的 x 和 y 坐标,以及一些关于地块的属性信息。

如何操作...

按照以下步骤将几何标记添加到光标中,这应该会提高该对象的表现:

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

  2. 将脚本保存为c:\ArcpyBook\Ch9\GeometryToken.py

  3. 导入arcpy.da模块:

    import arcpy.da, time
    
  4. 设置工作空间:

    arcpy.env.workspace = "c:/ArcpyBook/Ch9"
    
  5. 我们将测量使用几何标记执行代码所需的时间。为脚本添加一个开始时间:

    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. 保存脚本。

  11. 运行脚本。你应该会看到以下类似的输出。注意执行时间;你的时间会有所不同:

    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\Ch9\GeometryTokenEntireGeometry.py

  2. SearchCursor()函数更改为使用SHAPE@而不是SHAPE@XY来返回整个几何形状:

    with arcpy.da.SearchCursor("coa_parcels.shp",("PY_FULL_OW","SHAPE@")) as cursor:
    
  3. 保存并运行脚本。你应该会看到以下输出。你的时间可能会和我的不同,但请注意执行时间较慢。在这种情况下,它只慢了一点点,但我们只返回了 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 将从 text 文件中检索到的野火数据添加到点要素类中。当向要素类插入行时,您需要知道如何将要素的几何表示添加到要素类中。这可以通过使用 InsertCursor 以及两个其他对象:ArrayPoint 来实现。在这个练习中,我们将以野火事件的形式将点要素添加到空点要素类中。此外,您还将使用 Python 文件操作技术从文本文件中读取坐标数据。

如何做到这一点…

我们将导入来自 2007 年 10 月某一天的北美野火事件数据。这些数据包含在一个逗号分隔的文本文件中,该文件包含该特定日期上每个火灾事件的单独一行。每个火灾事件都有一个由逗号分隔的纬度/经度坐标对以及一个置信度值。这些数据是通过使用遥感数据来推断野火的存在或不存在而自动生成的。置信度值范围从 0 到 100。数值越高表示这是一个真正的野火的置信度越大:

  1. 打开文件 c:\ArcpyBook\Ch9\Wildfire Data\NorthAmericaWildfire_2007275.txt 并检查其内容。

    您会注意到这是一个简单的逗号分隔的文本文件,包含每个火灾的经纬度值以及一个置信度值。我们将使用 Python 逐行读取此文件的内容,并将新的点要素插入到位于 c:\ArcpyBook\Ch9 \WildfireData\WildlandFires.mdb 个人地理数据库中的 FireIncidents 要素类中。

  2. 关闭文件。

  3. 打开 ArcCatalog

  4. 导航到 c:\ArcpyBook\Ch9\WildfireData

    您应该看到一个名为 WildlandFires 的个人地理数据库。打开此地理数据库,您将看到一个名为 FireIncidents 的点要素类。目前这是一个空要素类。我们将通过读取您之前检查的文本文件并插入点来添加要素。

  5. 右键单击 FireIncidents 并选择 属性

  6. 点击 字段 选项卡。

    我们之前检查的文件中找到的纬度/经度值将被导入到 SHAPE 字段中,置信度值将被写入到 CONFIDENCEVALUE 字段中。

  7. 打开 IDLE 并创建一个新的脚本。

  8. 将脚本保存到 c:\ArcpyBook\Ch9\InsertWildfires.py

  9. 导入 arcpyos 模块:

    import arcpy,os
    
  10. 设置工作空间:

    arcpy.env.workspace = "C:/ArcpyBook/Ch9/WildfireData/WildlandFires.mdb"
    
  11. 打开文本文件,将所有行读入一个列表:

    f = open("C:/ArcpyBook/Ch9/WildfireData/NorthAmericaWildfires_2007275.txt","r")
    lstFires = f.readlines()
    
  12. 开始一个 try 块:

    try:
    
  13. 使用 with 块创建一个 InsertCursor 对象。确保在 try 语句内部进行缩进。光标将在 FireIncidents 要素类上创建:

    with 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 = [(latitude,longitude),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, os
    
    arcpy.env.workspace = "C:/ArcpyBook/Ch9/WildfireData/WildlandFires.mdb"
    f = open("C:/ArcpyBook/Ch9/WildfireData/NorthAmericaWildfires_2007275.txt","r")
    lstFires = f.readlines()
    try:
      with 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 = [(latitude,longitude),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. 保存并运行脚本。当脚本运行时,你应该会在输出窗口看到消息被写入:

    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
    
    
  20. 打开 ArcMap 并将 FireIncidents 要素类添加到内容表中。点应该可见,如下面的截图所示:如何操作…

它是如何工作的…

这里可能需要一些额外的解释。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() 方法来删除一行。

在这个菜谱中,你将编写一个脚本,通过将 poorfairgoodexcellent 的值分配给一个新字段,该字段更详细地描述了置信度值,并使用 UpdateCursor 更新 FireIncidents 要素类中的每个要素。在更新记录之前,你的脚本将向 FireIncidents 要素类添加一个新字段。

如何操作…

按照以下步骤创建一个 UpdateCursor 对象,该对象将用于编辑要素类中的行:

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

  2. 将脚本保存到 c:\ArcpyBook\Ch9\UpdateWildfires.py

  3. 导入 arcpyos 模块:

    import arcpy,os
    
  4. 设置工作空间:

    arcpy.env.workspace = "C:/ArcpyBook/Ch9/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 =

    • 置信度值 41 至 60 = 一般

    • 置信度值 61 至 85 = 良好

    • 置信度值 86 至 100 = 优秀

      for row in cursor:
            # update the confid_rating field
            if row[0] <= 40:
              row[1] = 'POOR'
              cursor.updateRow(row)
            elif row[0] > 40 and row[0] <= 60:
              row[1] = 'FAIR'
              cursor.updateRow(row)
            elif row[0] > 60 and row[0] <= 85:
              row[1] = 'GOOD'
              cursor.updateRow(row)
            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, os
    
    arcpy.env.workspace = "C:/ArcpyBook/Ch9/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. 保存并运行脚本。当脚本运行时,你应该会看到消息被写入输出窗口:

    Record number 406 updated
    Record number 407 updated
    Record number 408 updated
    Record number 409 updated
    Record number 410 updated
    
    
  13. 打开 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\Ch9\DeleteWildfires.py

  3. 导入arcpyos模块:

    import arcpy,os
    
  4. 设置工作空间:

    arcpy.env.workspace = "C:/ArcpyBook/Ch9/WildfireData/WildlandFires.mdb"
    
  5. 开始一个try块:

    try:
    
  6. with块内创建UpdateCursor的新实例:

    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, os
    
    arcpy.env.workspace = "C:/ArcpyBook/Ch9/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. 保存并运行脚本。当脚本运行时,你应该会看到消息被写入输出窗口。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 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\Ch9\UpdateWildfires.py脚本并将其保存为名为c:\ArcpyBook\Ch9\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('C:\ArcpyBook\data\CityOfSanAntonio.gdb')
    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, os
    
    arcpy.env.workspace = "C:/ArcpyBook/Ch9/WildfireData/WildlandFires.mdb"
    try:
      edit = arcpy.da.Editor('C:\ArcpyBook\data\CityOfSanAntonio.gdb')
      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. 保存并运行脚本。

如何工作…

编辑操作应在编辑会话内进行,可以使用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,你可以从你的游标中访问这些对象。这些对象引用要素类的属性表中的 shape 字段。你可以通过这些对象读取要素类中每个要素的几何形状。

折线和多边形要素类由包含多个部分的要素组成。你可以使用 partCount 属性来返回每个要素的部分数量,然后对要素中的每个部分使用 getPart() 来遍历每个点并提取坐标信息。点要素类由每个要素的一个 PointGeometry 对象组成,该对象包含每个点的坐标信息。

在这个菜谱中,你将使用 SearchCursorPolygon 对象来读取多边形要素类的几何形状。

如何做到这一点…

按照以下步骤学习如何从要素类中的每个要素读取几何信息:

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

  2. 将脚本保存到 c:\ArcpyBook\Ch9\ReadGeometry.py

  3. 导入 arcpy 模块:

    import arcpy
    
  4. 将输入要素类设置为 SchoolDistricts 多边形要素类:

    infc = "c:/ArcpyBook/data/CityOfSanAntonio/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 循环遍历每个部分中的每个顶点并打印 x 和 y 坐标:

        # 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. 保存并运行脚本。当脚本为每个要素、每个要素的部分以及定义每个部分的 x 和 y 坐标写入信息时,你应该看到以下输出:

    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 坐标。

第十章。列出和描述 GIS 数据

在本章中,我们将介绍以下内容:

  • 获取工作空间中要素类的列表

  • 使用通配符限制返回的对象列表

  • 限制返回的对象列表中的要素类型

  • 获取要素类或表中的字段列表

  • 使用 Describe()函数返回关于要素类的描述性信息

  • 使用 Describe()函数返回关于图像的描述性信息

  • 使用 Describe()函数返回工作空间信息

简介

Python 通过脚本提供批量处理数据的能力。这有助于您自动化工作流程并提高数据处理效率。例如,您可能需要遍历磁盘上的所有数据集并对每个数据集执行特定操作。您的第一步通常是先进行初步的数据收集,然后再进行地理处理任务的主要内容。这种初步的数据收集通常是通过使用 ArcPy 中找到的一个或多个List方法来完成的。这些列表作为真正的 Python 列表对象返回。然后,这些列表对象可以被迭代以进行进一步处理。ArcPy 提供了一些函数,可以用来生成数据列表。这些方法适用于许多不同类型的 GIS 数据。在本章中,我们将检查 ArcPy 提供的用于创建数据列表的许多函数。在第三章中,我们也介绍了一些列表函数。然而,这些函数与使用arcpy.mapping模块有关,特别是用于处理地图文档和图层。本章中我们介绍的列表函数直接位于arcpy中,并且更具有通用性。

我们还将介绍用于返回包含属性组的动态对象的Describe()函数。这些动态生成的Describe对象将包含依赖于所描述数据类型的属性组。例如,当Describe()函数针对要素类运行时,将返回特定于要素类的属性。此外,所有数据,无论数据类型如何,都会获得一组通用属性,我们将在后面讨论。

获取工作空间中要素类的列表

就像本章我们将检查的所有列表函数一样,获取工作空间中要素类的列表通常是您的脚本执行的多步过程中的第一步。例如,您可能想要向文件地理数据库中的所有要素类添加一个新字段。为此,您首先需要获取工作空间中所有要素类的列表。

准备工作

ArcPy 提供了获取字段、索引、数据集、要素类、文件、栅格、表等列表的函数。ListFeatureClasses()函数可以用来生成工作空间中所有要素类的列表。ListFeatureClasses()有三个可选参数可以传递给函数,这些参数将用于限制返回的列表。第一个可选参数是一个通配符,可以用来根据名称限制返回的要素类。第二个可选参数可以用来根据数据类型(点、线、多边形等)限制返回的要素类。第三个可选参数通过要素数据集限制返回的要素类。在本例中,我们将返回工作空间中的所有要素类。

如何操作…

按照以下步骤学习如何使用ListFeatureClasses()函数检索工作空间中要素类的列表:

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

  2. 将脚本保存为c:\ArcpyBook\Ch10\ListFeatureClasses.py

  3. 导入arcpy模块:

    import arcpy
    
  4. 设置工作空间:

    arcpy.env.workspace = "C:/ArcpyBook/data/CityOfSanAntonio.gdb"
    

    注意

    你必须始终记住在调用任何列表函数之前使用环境设置设置工作空间。否则,列表函数将不知道应该从哪个数据集提取列表。

  5. 调用ListFeatureClasses()函数并将结果赋值给名为fcList的变量:

    fcList = arcpy.ListFeatureClasses()
    
  6. 遍历fcList中的每个要素类并在屏幕上打印它们:

    for fc in fcList:
      print fc
    
  7. 保存并运行脚本。你应该看到以下输出:

    Crimes2009
    CityBoundaries
    CrimesBySchoolDistrict
    SchoolDistricts
    BexarCountyBoundaries
    Texas_Counties_LowRes
    Burglary
    
    

它是如何工作的…

在调用任何列表函数之前,你需要设置工作空间环境设置,这将设置当前工作空间,你将从中生成列表。ListFeatureClasses()函数可以接受三个可选参数,这些参数将限制返回的要素类。大多数其他列表函数以相同的方式工作。然而,在这种情况下,我们没有传递任何参数就调用了ListFeatureClasses()函数。这将返回当前工作空间中所有要素类的 Python 列表对象,然后使用for循环进行迭代。列表中返回的每个要素类都表示为一个包含要素类名称的字符串。

还有更多…

除了返回工作空间中要素类的列表之外,你可能还需要获取一个表列表。ListTables()函数返回工作空间中独立表的列表。此列表可以根据名称或表类型进行筛选。表类型可以包括dBaseINFOALL。列表中的所有值都是string数据类型,并包含表名。

使用通配符限制返回的要素类列表

默认情况下,ListFeatureClasses() 函数将返回工作空间中的所有特征类。你通常会想以某种方式限制此列表。可以将三个可选参数传递给 ListFeatureClasses() 以限制返回的特征类。所有参数都是可选的。第一个参数是一个通配符,用于根据字符组合限制返回的列表。其他可以用来限制列表的参数包括数据类型和特征数据集。

准备工作

通过将通配符作为第一个参数传入,可以限制 ListFeatureClasses() 函数返回的特征类列表。通配符用于根据名称限制列表内容。例如,你可能只想返回以字母 B 开头的特征类列表。为此,你使用星号与任意数量的字符的组合。以下代码示例显示了如何使用通配符来限制列表内容:

fcs = arcpy.ListFeatureClasses("B*")

在本食谱中,你将学习如何通过使用通配符来限制返回的特征类列表。

如何操作...

按照以下步骤学习如何通过传递给第一个参数的通配符来限制 ListFeatureClasses() 函数返回的特征类列表:

  1. 打开 IDLE 和 c:\ArcpyBook\Ch10\ListFeatureClasses.py 脚本。

  2. 添加一个通配符,以限制返回的特征类列表仅包含以字母 C 开头的特征类:

    fcs = arcpy.ListFeatureClasses("C*")
    
  3. 保存并运行脚本以查看以下输出:

    Crimes2009
    CityBoundaries
    CrimesBySchoolDistrict
    
    

它是如何工作的...

ListFeatureClasses() 函数可以接受三个可选参数,包括一个通配符,该通配符将根据名称限制特征类列表。在这种情况下,我们使用了通配符字符(*)来限制返回的特征类列表,使其仅包含以字母 C 开头的特征类。

通过特征类型限制返回的特征类列表。

除了使用通配符来限制 ListFeatureClasses() 返回的特征类外,还可以通过特征类型进行过滤。

准备工作

除了使用通配符来限制 ListFeatureClasses() 函数返回的列表外,还可以结合通配符或单独应用类型限制。例如,以下代码示例显示了两者结合使用,以将返回的列表限制为仅包含以字母 B 开头的 polygon 特征类。在本食谱中,你将通过使用特征类型参数和通配符来限制返回的特征类。

fcs = arcpy.ListFeatureClasses("B*", "Polygon")

如何操作...

按照以下步骤学习如何通过特征类型限制 ListFeatureClasses() 函数返回的特征类列表:

  1. 打开 IDLE 和 c:\ArcpyBook\Ch10\ListFeatureClasses.py 脚本。

  2. ListFeatureClasses() 函数添加第二个参数,以限制返回的要素类仅限于以字母 C 开头且类型为 polygon 的那些:

    fcs = arcpy.ListFeatureClasses("C*","Polygon")
    
  3. 保存并运行脚本以查看以下输出:

    CityBoundaries
    CrimesBySchoolDistrict
    
    

它是如何工作的...

在这个菜谱中,我们已将要素类限制为仅包含多边形要素。其他有效的要素类型包括点、折线和区域。

更多...

可以传递给 ListFeatureClasses() 函数的第三个可选参数是要素数据集名称。这将过滤列表,只返回特定要素数据集中的要素类。当此可选参数不包括在 ListFeatureClasses() 调用中时,只返回当前工作空间中的独立要素类。

获取要素类或表中的字段列表

要素类和表包含一个或多个属性信息列。您可以通过 ListFields() 函数获取要素类中的字段列表。

准备工作

ListFields() 函数返回一个包含每个字段单独 Field 对象的列表,这些对象对应于要素类或表中的每个字段。一些函数,例如 ListFields()ListIndexes(),需要输入数据集来操作。您可以使用通配符或字段类型来限制返回的列表。每个 Field 对象包含各种只读属性,包括 NameAliasNameTypeLength 等。

如何操作...

按照以下步骤学习如何返回要素类中的字段列表:

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

  2. 将脚本保存为 c:\ArcpyBook\Ch10\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. 添加 except 块:

    except Exception 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 e:
      print e.message()
    
  9. 保存并运行脚本。您应该看到以下输出:

    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() 和所有其他列表函数通常在脚本中的多步过程中作为第一步被调用。例如,您可能只想更新人口普查区要素类中包含的人口统计信息。为此,您可以获取要素类中所有字段的列表,遍历此列表以查找包含人口信息的特定字段名称,然后更新每行的人口信息。或者,ListFields() 函数接受通配符作为其参数之一。因此,如果您事先知道人口字段的名称,可以将该名称作为通配符传递,从而只返回单个字段。

使用 Describe() 函数返回要素类的描述信息

所有数据集都包含描述性信息。例如,要素类有一个名称、形状类型、空间参考等。当您在脚本中继续进一步处理之前寻求特定信息时,这些信息对您的脚本可能很有价值。例如,您可能只想对折线要素类执行缓冲区操作,而不是对点或多边形执行。使用 Describe() 函数,您可以获取任何数据集的基本描述信息。您可以将此信息视为元数据。

准备工作

Describe() 函数为您提供了获取数据集基本信息的功能。这些数据集可能包括要素类、表格、ArcInfo 覆盖、图层文件、工作空间、栅格以及其他类型。返回一个 Describe 对象,其中包含基于描述的数据类型的特定属性。Describe 对象上的属性被组织成属性组,所有数据集至少属于一个属性组。例如,对地理数据库执行 Describe() 操作将返回 GDBFeatureClassTableDataset 属性组。每个属性组都包含可以检查的特定属性。

所有数据集,无论其类型如何,都包含在Describe对象上的默认属性集。这些属性是只读的。一些更常用的属性包括dataTypecatalogPathnamepathfile

arcpy.env.workspace = "c:/ArcpyBook/Ch10/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/Ch10/CityOfSanAntonio.gdb

添加except块:

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

Describe()函数接受一个字符串参数,该参数是指向数据源的指针。在下面的代码示例中,我们传递一个包含在文件地理数据库中的要素类。该函数返回一个包含一组称为属性组的动态属性的Describe对象。然后我们可以通过简单地使用print函数打印属性来访问这些各种属性,就像在这个例子中我们所做的那样:

Table属性组之所以重要,主要是因为它允许你访问独立表或要素类中的字段。你还可以通过此属性组访问表或要素类上的任何索引。表属性返回一个包含每个要素类中Field对象的 Python 列表。每个字段都有许多只读属性,包括namealiaslengthtypescaleprecision等。最显然有用的属性是nametype。在这个脚本中,我们打印了字段名称、类型和长度。注意使用 Python for循环来处理 Python 列表中的每个字段。

  1. 它是如何工作的...

  2. 整个脚本应如下所示:

  3. 对要素类执行Describe()函数,我们在脚本中已经这样做,返回一个FeatureClass属性组以及访问TableDataset属性组的权限。除了返回FeatureClass属性组外,你还可以访问Table属性组。

  4. 导入 arcpy 模块

    arcpy.env.workspace = "C:/ArcpyBook/data/CityOfSanAntonio.gdb"
    
  5. Burglary要素类上调用Describe()函数并打印形状类型:

    try:
    
  6. 设置工作空间:

    descFC = arcpy.Describe("Burglary")
    print "The shape type is: " + descFC.ShapeType
    
  7. 在这个菜谱中,你将编写一个脚本,使用Describe()函数获取关于要素类的描述性信息。

    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. 开始一个try块:

    except Exception 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. 保存并运行脚本。你应该看到以下输出:

    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
    
    

获取要素类的地理范围并打印定义范围的坐标:

按照以下步骤学习如何获取关于要素类的描述性信息:

将脚本保存为c:\ArcpyBook\Ch10\DescribeFeatureClass.py

最后,我们通过使用Extent对象,该对象由Dataset属性组上的extent属性返回,打印出层的地理范围。Dataset属性组包含许多有用的属性。也许,最常用的属性包括extentspatialReference,因为许多地理处理工具和脚本在执行过程中某个时刻都需要这些信息。你还可以获取datasetType和版本信息以及其他几个属性。

使用Describe()函数返回关于图像的描述性信息

栅格文件也包含描述性信息,这些信息可以通过Describe()函数返回。

准备工作

栅格数据集也可以通过使用Describe()函数来描述。在这个菜谱中,你将通过返回其范围和空间参考来描述一个栅格数据集。Describe()函数还包含对通用Dataset属性组的引用,该属性组包含对数据集的SpatialReference对象的引用。然后可以使用SpatialReference对象来获取数据集的详细空间参考信息。

如何做…

按照以下步骤学习如何获取关于栅格图像文件描述性信息的方法:

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

  2. 将脚本保存为c:\ArcpyBook\Ch10\DescribeRaster.py

  3. 导入arcpy模块:

    import arcpy
    
  4. 设置工作区:

    arcpy.env.workspace = "C:/ArcpyBook/data"
    
  5. 开始一个try块:

    try:
    
  6. try语句中调用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. 添加except块:

    except Exception 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:
      print arcpy.GetMessages()
    
  11. 保存并运行脚本。你应该看到以下输出:

    XMin: 3111134.862457
    YMin: 10086853.262238
    XMax: 3131385.723907
    YMax: 10110047.019228
    NAD83_Texas_Central
    Projected
    
    

它是如何工作的…

这个菜谱与上一个非常相似。不同之处在于我们正在使用Describe()函数针对栅格数据集而不是针对矢量要素类。在两种情况下,我们都使用了extent对象来返回数据集的地理范围。然而,在脚本中我们还获取了栅格数据集的SpatialReference对象并打印了关于该对象的信息,包括名称和类型。

使用Describe()函数返回工作区信息

可以使用多种类型的地理数据库与 ArcGIS 一起使用,包括个人、文件和企业。正如我们在第八章中看到的,查询和选择数据,查询的构建将取决于数据集所在的地理数据库类型。你的脚本可能或可能不知道地理数据库类型。为了使你的脚本在查询时更加健壮,你可以使用Describe()函数针对工作区来捕获这些信息并相应地构建你的查询。

准备工作

Workspace 属性组提供了关于工作空间(如文件夹、个人或文件地理数据库,或企业地理数据库)的信息。这些属性在获取 ArcSDE 连接信息时尤其有用。通过此属性组可以获取的信息包括当工作空间是 ArcSDE 工作空间时的连接信息、与地理数据库关联的域以及工作空间类型,这些类型可以是 FileSystemLocalDatabaseRemoteDatabaseLocalDatabase 指的是个人或文件地理数据库,而 RemoteDatabase 指的是 ArcSDE 地理数据库。在本例中,你将使用 Workspace 属性组来获取文件地理数据库的信息。

如何操作...

按照以下步骤学习如何获取工作空间的描述信息:

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

  2. 将脚本保存为 c:\ArcpyBook\Ch10\DescribeWorkspace.py

  3. 导入 arcpy 模块:

    import arcpy
    
  4. 开始一个 try 块:

    try:
    
  5. CityOfSanAntonio 地理数据库上调用 Describe() 函数,并确保将此语句缩进放在 try 语句内。下面的两个打印语句也应该缩进。

    descRaster = arcpy.Describe("c:/ArcpyBook/data/CityOfSanAntonio.gdb")
    
  6. 打印工作空间类型:

    print descWorkspace.workspaceType
    
  7. 打印详细的工作空间信息:

    print descWorkspace.workspaceFactoryProgID
    
  8. 添加 except 块:

    except Exception e:
      print e.message()
    
  9. 保存并运行脚本。你应该看到以下输出:

    LocalDatabase
    esriDataSourcesGDB.FileGDBWorkspaceFactory.1
    
    

工作原理...

workspaceType 属性返回三个值之一:FileSystemLocalDatabaseRemoteDatabaselocalDatabase 值表示你正在使用个人或文件地理数据库。然而,它并不更具体。要获取具体的地理数据库,你可以检索 workspaceFactoryProgID 属性,这将指示地理数据库的类型。在这种情况下,它是一个文件地理数据库。

第十一章. 使用插件自定义 ArcGIS 界面

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

  • 下载和安装 Python 插件向导

  • 创建按钮插件

  • 安装和测试插件

  • 创建工具插件

简介

在本章中,我们将介绍使用 Python 创建插件的创建、测试、编辑和共享。插件提供了一种通过模块化代码库向 ArcGIS Desktop 添加用户界面元素的方法,该代码库旨在执行特定操作。界面组件可以包括按钮、工具、工具栏、菜单、组合框、工具板和应用程序扩展。插件概念首次在 ArcGIS Desktop 10.0 中引入,可以使用 .NET 或 Java 创建。然而,随着 ArcGIS 10.1 的发布,现在可以使用 Python 创建插件。插件使用 Python 脚本和一个定义用户界面应如何显示的 XML 文件创建。

插件提供了一种简单的方式来向最终用户分发用户界面自定义。不需要安装程序。只需将一个扩展名为 .esriaddin 的单个压缩文件复制到已知文件夹中,ArcGIS 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 Desktop 创建添加组件。它通过点选工具大大简化了过程。在下一个示例中,您将使用向导创建基本的 ArcGIS Desktop 添加组件。

创建按钮添加组件

按钮添加组件是最简单的添加组件类型,也是最常用的。使用按钮添加组件,您在脚本中编写的功能将在每次点击按钮时执行。

准备工作

创建添加组件项目是创建新添加组件的第一步。要使用 Python 添加组件向导创建项目,您选择工作目录,输入各种项目设置,然后点击保存按钮。添加组件的创建随后遵循一个定义良好的过程,如以下截图所示:

准备工作

您必须首先为添加组件创建一个容器,这可以是工具栏或菜单。接下来,创建您想要添加到容器中的按钮、工具或另一个添加组件。在本例中,我们假设它是一个按钮。接下来,您需要编辑与按钮关联的 Python 脚本。您还希望测试按钮以确保其按预期工作。最后,您可以与他人共享添加组件。在本例中,您将学习如何使用添加组件向导创建 ArcGIS Desktop 的按钮添加组件。按钮添加组件将运行您在早期示例中创建的自定义脚本工具,该工具从文本文件将野火数据加载到点要素类中。

如何操作…

按照以下步骤学习如何创建按钮附加组件:

  1. 通过双击位于您提取向导的bin文件夹中的addin_assistant.exe文件来打开 ArcGIS Python 附加组件向导。

  2. 创建一个名为Wildfire_Addin的新项目文件夹并单击确定如何操作...

  3. 项目设置选项卡最初应该是活动的,并显示您刚刚创建的工作目录。默认情况下,ArcMap 应该是选定的产品,但您应该验证这一点:如何操作...

  4. 给您的项目起一个名字。我们将称之为Load Wildfire Data Addin如何操作...

  5. 默认情况下,版本号为 0.1。如果您愿意,可以更改此值。版本号应在您更新或添加工具时更改。这有助于跟踪和共享您的附加组件:如何操作...

  6. 名称和版本属性是仅有的两个必需属性。按照以下截图所示,添加公司、描述和作者信息是一个好习惯。添加您自己的信息:如何操作...

  7. 您可能还希望为附加组件添加图片。在C:\ArcpyBook\Ch11文件夹中提供了一个名为wildfire.png的文件用于此目的:如何操作...

  8. 附加组件内容选项卡用于定义可以创建的各种附加组件。在此步骤中,我们将创建一个工具栏,用于包含一个运行野火脚本的单个按钮附加组件,该脚本将fires从文本文件导入到要素类中。单击附加组件内容选项卡:如何操作...

  9. 附加组件内容选项卡中,右键单击工具栏并选择新建工具栏。为工具栏添加标题,接受默认 ID,并确保选中初始显示复选框:如何操作...

    工具栏附加组件虽然功能上并不太多,但非常重要,因为它充当其他附加组件(如按钮、工具、组合框、工具板和菜单)的容器。工具栏可以是浮动的或停靠的。使用 Python 附加组件向导创建工具栏附加组件很容易。

  10. 单击保存按钮。

  11. 现在,通过在新Wildfire 工具栏选项上右键单击并选择新建按钮来添加一个按钮。

  12. 填写按钮详细信息,包括标题、类名、ID、工具提示等。您还可以为控件添加图片。在此情况下,我没有这样做,但您可能希望这样做。这些信息将保存到附加组件的配置文件中:如何操作...

  13. 单击保存按钮。

    附加组件有一个与之关联的 Python 脚本。默认情况下,此文件将命名为AddIns_addin.py,并位于您工作项目文件夹的install目录中。

  14. 我们已经创建了一个自定义的 ArcToolbox Python 脚本工具,该工具可以从包含野火数据的磁盘上的逗号分隔文本文件中加载到要素类中。我们将在我们的插件中使用此脚本。在 Windows 资源管理器中,转到您之前创建的addin目录。它应该被称为Wildfire_Addin。转到Install文件夹,您应该找到一个名为WildfireAddin_addin.py的文件。将此文件加载到您的 Python 编辑器中。

  15. 找到以下代码片段中显示的onClick(self)方法。当按钮被点击时,此方法会被触发:

    import arcpy
    import pythonaddins
    
    class ButtonClassImportWildfires(object):
      """Implementation for WildfireAddIn_addin.button (Button)"""
      def __init__(self):
        self.enabled = True
        self.checked = False
      def onClick(self):
        pass
    
  16. onClick事件中移除pass语句。

  17. 在第七章中,您创建了一个自定义脚本工具,该工具可以从文本文件将野火数据加载到要素类中。在onClick事件内部,调用此从文本文件加载野火的自定义脚本工具,以便显示选择文本文件、模板和要写入的要素类的用户界面。

    def onClick(self):
        LoadWildfires_wildfire()
    
  18. 保存文件。

在下一节中,您将学习如何安装您的新插件。

它是如何工作的...

正如您在本食谱中看到的,Python 插件向导通过可视化界面处理插件的创建。然而,在幕后,向导为插件创建了一系列文件夹和文件。插件文件结构实际上非常简单。两个文件夹和一组文件构成了插件结构。您可以在以下屏幕截图中看到此结构:

它是如何工作的...

Images文件夹包含您的插件使用的任何图标或其他图像文件。在本食谱中,我们使用了wildfire.png图像。因此,此文件现在应该在Images文件夹中。Install文件夹包含处理插件业务逻辑的 Python 脚本。这是您用于编写插件的文件。它执行按钮、工具、菜单项等需要执行的所有业务逻辑。插件主文件夹中的config.xml文件定义用户界面以及任何静态属性,如名称、作者、版本等。可以双击makeaddin.py文件来创建具有.esriaddin扩展名的.esriaddin文件,该文件将所有内容压缩成一个带有.esriaddin扩展名的文件。这个.esriaddin文件将被分发给最终用户,以便安装插件。

安装和测试插件

在将插件分发给最终用户之前,您需要测试插件。为了测试,您首先需要安装该插件。

准备工作

在您的插件工作文件夹中,可以使用makeaddin.py脚本将所有文件和文件夹复制到工作目录中的一个压缩插件文件夹中,文件格式为<工作文件夹名称>.esriaddin。双击此.esriaddin文件以启动 ESRI ArcGIS 插件安装实用程序,该实用程序将安装您的插件。然后您可以在 ArcGIS Desktop 中测试插件。自定义工具栏或菜单可能已经可见并准备好测试。如果不可见,请转到自定义菜单并点击插件管理器插件管理器对话框列出了针对当前应用程序的已安装插件。插件信息,如名称、描述和图像,应作为项目设置输入并显示。

如何操作…

要了解如何安装和测试 Python 插件,请按照以下步骤操作:

  1. 在您的插件主文件夹内将有一个名为makeaddin.py的 Python 脚本文件。此脚本创建.esriaddin文件。双击脚本以执行并创建.esriaddin文件。以下截图展示了这一过程:如何操作…

  2. 要为 ArcGIS Desktop 安装插件,请双击Widlfire_Add-In.esriaddin文件,这将启动Esri ArcGIS 插件安装实用程序窗口,如下截图所示:如何操作…

  3. 点击安装插件。如果一切顺利,您应该会看到以下消息:如何操作…

  4. 要测试插件,请打开 ArcMap。您的插件可能已经激活。如果没有,请选择自定义 | 插件管理器。这将显示插件管理器对话框,如下截图所示。您应该能够看到您创建的插件:如何操作…

  5. 如有需要,请选择自定义按钮。要将工具栏添加到应用程序中,请点击工具栏选项卡并选择您创建的工具栏:如何操作…

如何操作…

实用程序将插件放置到 ArcGIS Desktop 可发现的已知文件夹中。已知文件夹的位置如下:

  • Vista/7: C:\Users\<username>\Documents\ArcGIS\AddIns\Desktop10.1

  • XP: C:\Documents and Settings\<username>\My Documents\ArcGIS\AddIns\Desktop10.1

在已知文件夹内将创建一个具有全局唯一标识符或 GUID 名称的文件夹。插件将驻留在该唯一文件夹名称内。以下截图展示了这一过程。当 ArcGIS Desktop 启动时,它将搜索这些目录并加载插件:

工作原理…

该插件将类似于以下内容:

工作原理…

注意

默认插件文件夹位于您的用户账户中的 ArcGIS 文件夹内。例如,如果您的 ArcGIS 安装版本为 10.1,插件将被复制到以下位置(在 Vista 或 Windows 7 操作系统上):c:\users\<username>\Documents\ArcGIS\AddIns\Desktop10.1

您还可以使用私有网络驱动器向最终用户分发插件。ArcGIS Desktop 中的插件管理器添加并维护可以搜索插件的文件夹列表。选择选项选项卡,然后选择添加文件夹将网络驱动器添加到列表中。

创建工具插件

工具插件类似于按钮,但工具需要与地图进行某种类型的交互。例如,缩放工具就是一种工具。工具应放置在工具栏或工具调色板内。属性与按钮中的属性非常相似。您还需要编辑 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. 将工具栏的标题设置为Random Points Toolbar

  7. 右键单击新创建的Random Points Toolbar并选择新建工具

  8. 按照以下截图输入工具项:如何操作...

  9. 点击保存。这将生成插件的文件夹和文件结构。

  10. 前往新插件的Install文件夹,并在 IDLE 中打开GenerateRandomPoints_addin.py文件。

  11. 将以下代码添加到工具的构造函数__init__中:

    def __init__(self):
      self.enabled = True
      self.cursor = 3
      self.shape = 'Rectangle'
    
  12. onRectangle()函数中编写代码以在屏幕上绘制的矩形内生成一组随机点:

    def onRectangle(self, rectangle_geometry):
      extent = rectangle_geometry
      arcpy.env.workspace = r'c:\ArcpyBook\Ch11'
       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. 通过在插件的根目录中双击makeaddin.py文件来生成.esriaddin文件。

  15. 通过双击Generate_Random_Points.esriaddin来安装插件。

  16. 使用新的地图文档文件打开 ArcMap,并在必要时添加生成随机点工具栏。

  17. C:\ArcpyBook\data\CityOfSanAntonio.gdb添加BexarCountyBoundaries要素类。

  18. 通过在地图上拖动矩形来测试插件。输出应类似于以下截图。不过,由于点生成是随机的,你的地图可能会有所不同:如何操作...

它是如何工作的...

工具插件与按钮插件非常相似,区别在于工具插件在功能触发之前需要与地图进行某种形式的交互。与地图的交互可以包括点击地图、绘制多边形或矩形,或执行各种鼠标或键盘事件。Python 代码被编写来响应这些事件之一或多个。在本食谱中,你学习了如何编写响应onRectangle()事件的代码。你还在插件的构造函数中设置了各种属性,包括cursorshape,这些将在地图上绘制。

更多内容...

你可以创建许多其他插件。ComboBox插件提供了一个下拉列表,用户可以从中选择值,或者他们可以在可编辑字段中输入新值。与其他插件一样,你首先想要使用 Python Add-In 向导创建一个新项目,添加一个新工具栏,然后创建一个组合框并将其添加到工具栏中。

工具调色板提供了一种分组相关工具的方法。它需要添加到现有的工具栏中。默认情况下,工具将以网格状模式添加到调色板中。

菜单插件充当按钮和其他菜单的容器。除了在 ArcGIS Desktop 插件管理器中显示外,菜单还会在 ArcGIS Desktop 的自定义对话框中显示。

应用程序扩展用于向 ArcGIS Desktop 添加特定的一组相关功能。几个例子包括空间分析器、3D 分析器和商业分析师。通常,应用程序扩展负责监听事件并处理它们。例如,您可以创建一个应用程序扩展,每次用户将图层添加到地图时,都会保存地图文档文件。应用程序扩展还协调组件之间的活动。

第十二章. 错误处理和故障排除

在本章中,我们将介绍以下内容:

  • 探索默认的 Python 错误信息

  • 添加 Python 异常处理结构(try/except/finally)

  • 使用 GetMessages()检索工具消息

  • 通过严重程度级别过滤工具消息

  • 使用 GetMessage()返回单个消息

  • 测试并响应特定错误消息

简介

在执行 ArcGIS 地理处理工具和函数的过程中,会返回各种消息。这些消息可能是信息性的,或者指示警告或错误条件,可能导致工具无法创建预期的输出,或者工具执行完全失败。这些消息不会以消息框的形式出现。相反,您需要使用各种 ArcPy 函数来检索它们。到目前为止,本书中我们忽略了这些消息、警告和错误的存在。这主要是因为我想让您集中精力学习一些基本概念,而不添加创建健壮的地理处理脚本所需的额外代码复杂性,这些脚本可以优雅地处理错误情况。话虽如此,现在是时候学习如何创建地理处理和 Python 异常处理结构,这将使您能够创建灵活的地理处理脚本。这些脚本可以处理在脚本运行时生成的指示警告、错误和一般信息的消息。这些代码细节将帮助使您的脚本更加灵活,减少错误发生的可能性。您已经使用基本的tryexcept块执行了一些基本的错误处理。但是,在本章中,我们将更详细地介绍为什么以及如何使用这些结构。

探索默认的 Python 错误信息

默认情况下,Python 会在您的脚本中遇到问题时生成错误消息。这些错误消息并不总是对运行脚本的最终用户非常有信息性。然而,查看这些原始消息是有价值的。在后面的菜谱中,我们将使用 Python 错误处理结构来获取更清晰的错误视图,并根据需要进行响应。

准备工作

在这个菜谱中,我们将创建并运行一个故意包含错误条件的脚本。我们不会在脚本中包含任何地理处理或 Python 异常处理技术。我们故意这样做,因为我想让您看到 Python 返回的错误信息。

如何操作…

按照以下步骤操作,以查看在脚本执行过程中工具执行时产生的原始 Python 错误信息:

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

  2. 将脚本保存到c:\ArcpyBook\Ch12\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. 运行脚本。你应该看到以下错误信息:

     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/finally)

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. 如果需要,在 IDLE 中打开 c:\ArcpyBook\Ch12\ErrorHandling.py 文件。

  2. 修改你的脚本以包含一个 try/except 块:

    import arcpy
    try:
      arcpy.env.workspace = "c:/ArcpyBook/data"
      arcpy.Buffer_analysis("Streams.shp","Streams_Buff.shp")
    except:
      print "Error"
    
  3. 保存并运行脚本。你应该看到简单的消息 Error。这并不比我们在第一个菜谱中收到的输出更有帮助。事实上,它甚至更没有用。然而,这个菜谱的目的仅仅是向你介绍 try/except 错误处理结构。

它是如何工作的…

这是一个极其简单的结构。try 块表示 try 语句下缩进的任何内容都将受到异常处理的影响。如果找到任何类型的异常,代码处理的控制将跳转到 except 部分,并打印错误消息(在这种情况下是简单的 Error)。正如我提到的,这对用户来说几乎没有任何信息量,但希望这能给你一个基本的想法,了解 try/except 块是如何工作的,并且作为程序员,你将更好地理解用户报告的任何错误。在下一个菜谱中,你将学习如何向这个结构添加工具生成的消息。

还有更多...

另一种类型的try语句是try/finally语句,它允许执行最终化操作。当在try语句中使用finally子句时,其语句块总是在最后执行,无论是否发生错误条件。try/finally语句的工作方式如下。如果发生异常,Python 将运行try块,然后运行finally块,然后执行继续到整个try语句之后。如果在执行过程中没有发生异常,Python 将运行try块,然后运行finally块,然后执行返回到更高级别的try语句。这在确保代码块运行后无论是否发生错误条件都要执行某些操作时非常有用。

使用 GetMessages() 获取工具消息

ArcPy 包含一个GetMessages()函数,你可以使用它来检索在 ArcGIS 工具执行时生成的消息。消息可以包括信息性消息,例如工具执行的开始和结束时间,以及警告和错误,这些可能导致结果不如预期或工具执行失败。

准备工作

在工具执行过程中,会生成各种消息。这些消息包括信息性消息,例如工具执行的开始和结束时间、传递给工具的参数值以及进度信息。此外,工具还可以生成警告和错误。这些消息可以通过你的 Python 脚本读取,并且你可以设计代码来适当地处理已生成的任何警告或错误。

ArcPy 存储了最后执行的工具的消息,你可以使用GetMessages()函数检索这些消息,该函数返回一个包含最后执行的工具所有消息的单个字符串。你可以通过严重性过滤这个字符串,以返回仅包含某些类型的消息,例如警告或错误。第一条消息将始终包含执行的工具的名称,最后一条消息是开始和结束时间。

在这个菜谱中,你将在except语句中添加一行代码,这将打印关于当前工具运行更详细的信息。

如何做到这一点...

按照以下步骤学习如何将GetMessages()函数添加到你的脚本中,以生成来自最后执行的工具的消息列表。

  1. 如果需要,在 IDLE 中打开c:\ArcpyBook\Ch12\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. 保存并运行脚本。这次,错误消息应该更加详细。同时请注意,还会生成其他类型的消息,包括脚本执行的开始和结束时间:

    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\Ch12\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. 保存并运行脚本以查看输出:

    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 桌面帮助系统中通过访问地理处理 | 工具错误和警告来获取所有可用错误消息和代码的列表。这在下图中得到了说明。所有错误都将有一个独特的页面,简要描述错误代码:

准备中…

如何操作…

按照以下步骤学习如何编写一个响应由地理处理工具执行生成的特定错误代码的代码:

  1. 通过访问开始 | 程序 | ArcGIS | ArcGIS for Desktop 帮助来打开 ArcGIS 桌面帮助系统。

  2. 前往地理处理 | 工具错误和警告 | 工具错误 1-10000 | 工具错误和警告:701-800

  3. 选择000735: : 值是必需的。这个错误表示工具所需的参数尚未提供。你会记得在运行此脚本时,我们没有提供缓冲距离,因此生成的错误消息包含我们在帮助系统中查看的错误代码。在下面的代码中,你会找到错误消息的完整文本。注意错误代码。

    ERROR000735:Distance[valueorfield]:Valueisrequired
    
  4. 如果需要,在 IDLE 中打开c:\ArcpyBook\Ch12\ErrorHandling.py文件。

  5. 在你的脚本中,修改except语句,使其如下所示:

    except:
     print “Error found in Buffer tool \n”
    errCode = arcpy.GetReturnCode(3)
     if str(errCode) in “735”:
     print “Distance value not provided \n”
     print “Running the buffer again with a default value \n”
    defaultDistance = “100 Feet”
    arcpy.Buffer_analysis(“Streams.shp”, “Streams_Buff”, defaultDistance)
     print “Buffer complete”
    
  6. 保存并运行脚本。你应该会看到各种消息被打印出来,如下所示:

    Error found in Buffer tool
    Distance value not provided for buffer
    Running the buffer again with a default distance value
    Buffer complete
    

它是如何工作的…

在这个代码块中,你所做的是使用arcpy.GetReturnCode()函数来返回工具生成的错误代码。然后,使用一个if语句来测试错误代码是否包含值735,这个代码表示工具未提供所需的参数。你随后为缓冲距离提供了一个默认值,并再次调用了Buffer工具;这次提供了默认的缓冲值。

使用 GetMessage()返回单个消息

虽然GetMessages()返回一个包含最后一次工具运行中所有消息的列表,但你也可以使用GetMessage()从字符串中获取单个消息。

准备中

到目前为止,我们一直在返回工具生成的所有消息。然而,你可以通过 GetMessage() 方法将单个消息返回给用户,该方法接受一个整数参数,表示你想要检索的特定消息。工具生成的每个消息都被放置在一个消息列表或数组中。我们在本书前面讨论了列表对象,所以你会记得这只是一个某种对象的集合。提醒一下:列表是从零开始的,意味着列表中的第一个元素位于位置 0。例如,GetMessage(0) 会返回列表中的第一条消息,而 GetMessage(1) 会返回列表中的第二条消息。第一条消息总是执行的工具以及任何参数。第二条消息返回脚本的开始时间,而最后一条消息返回脚本的结束时间。

如何做...

  1. 如果需要,在 IDLE 中打开 c:\ArcpyBook\Ch12\ErrorHandling.py 文件。

  2. 修改 except 块如下:

    import arcpy
    try:
      arcpy.env.workspace = "c:/ArcpyBook/data"
      arcpy.Buffer_analysis("Streams.shp","Streams_Buff.shp")
    except:
      print arcpy.GetMessage(1)
      print arcpy.GetMessage(arcpy.GetMessageCount() – 1)
    
  3. 保存并运行脚本以查看输出:

    Start Time: Wed Nov 14 09:07:35 2012
    Failed at Wed Nov 14 09:07:35 2012 (Elapsed Time: 0.00 seconds)
    
    

它是如何工作的...

我们还没有介绍 GetMessageCount() 函数。这个函数返回工具返回的消息数量。请记住,我们的消息列表是从零开始的,所以我们必须从 GetMessageCount() 函数中减去一,才能得到列表中的最后一条消息。否则,我们会尝试访问一个不存在的消息。在这个脚本中,我们已经访问了脚本的开始和结束时间。第二条消息总是脚本的开始时间,而最后一条消息总是脚本的结束时间。这个概念如下所示:

Message 0 - Executing: Buffer c:/ArcpyBook/data\Streams.shp c:/ArcpyBook/data\Streams_Buff.shp # FULL ROUND NONE #
Message 1 - Start Time: Tue Nov 13 22:23:04 2012
Message 2 - Failed to execute. Parameters are not valid.
Message 3 - ERROR 000735: Distance [value or field]: Value is required
Message 4 - Failed to execute (Buffer).
Message 5 - Failed at Tue Nov 13 22:23:04 2012 (Elapsed Time: 0.00 seconds)

消息总数为 6,但最后一条消息是编号 5。这是因为计数从 0 开始。这就是为什么你需要减去 1,如前所述。在这种情况下,开始和结束时间相同,因为脚本中包含了一个错误。然而,它确实说明了如何访问工具生成的单个消息。

附录 A. 自动化 Python 脚本

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

  • 从命令行运行 Python 脚本

  • 使用 sys.argv[] 捕获命令行输入

  • 将 Python 脚本添加到批处理文件中

  • 安排批处理文件在指定时间运行

简介

Python 地理处理脚本可以作为独立脚本在 ArcGIS 外部执行,也可以作为脚本工具在 ArcGIS 内部执行。这两种方法都有其优点和缺点。到这本书的这一部分,我们所有的脚本要么在 ArcGIS 内部作为脚本工具运行,要么从 Python 开发环境(如 IDLE 或 ArcGIS 中的 Python 窗口)运行。然而,Python 脚本也可以从 Windows 操作系统命令行执行。命令行是一个你可以输入命令的窗口,而不是 Windows 提供的通常的点按和点击方法。运行 Python 脚本的方法对于安排脚本的执行非常有用。你可能有很多理由想要安排你的脚本。许多地理处理脚本需要很长时间才能完全执行,并且需要定期在工作时间之外安排运行。此外,一些脚本需要定期执行(每天、每周、每月等),并且应该为了效率而安排。在本章中,你将学习如何从命令行执行脚本,将脚本放入批处理文件中,并在指定的时间安排脚本的执行。请记住,任何从命令行运行的脚本仍然需要访问 ArcGIS Desktop 许可证才能使用 arcpy 模块。

从命令行运行 Python 脚本

到这本书的这一部分,你所有的 Python 脚本都作为 ArcGIS 中的脚本工具或从 Python 开发环境(如 IDLE 或 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.1。如果找不到文本字符串,请将其添加到末尾。确保在添加路径之前添加一个分号。现在,当你在命令提示符中键入python时,它将遍历路径系统变量中的每个目录,检查是否存在名为python.exe的可执行文件。如何操作…

  11. 点击确定以关闭编辑系统变量对话框。

  12. 点击确定以关闭环境变量对话框。

  13. 点击确定以关闭系统属性对话框。

  14. 返回到命令提示符。

  15. 输入python ListFields.py。这将运行ListFields.py脚本。经过短暂的延迟后,你应该会看到以下输出:如何操作…

它是如何工作的…

本食谱中提供的ListFields.py脚本是一个简单的脚本,用于列出Burglaries_2009.shp文件的属性字段。工作空间和 shapefile 名称在脚本中是硬编码的。键入python后跟脚本名称,在本例中为ListFields.py,将触发使用 Python 解释器执行脚本。如我所述,工作空间和 shapefile 名称在这个脚本中是硬编码的。在下一个食谱中,您将学习如何向脚本传递参数,以便您可以移除硬编码并使脚本更加灵活。

使用 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, sys
    
  3. 创建一个变量来保存将被传递到脚本中的工作空间:

    wkspace = sys.argv[1]
    
  4. 创建一个变量来保存将被传递到脚本中的要素类:

    fc = sys.argv[2]
    
  5. 更新设置工作空间和调用 ListFields() 函数的代码行:

    arcpy.env.workspace = wkspace
    fields = arcpy.ListFields(fc)
    

    您完成的脚本应如下所示:

    import arcpy, 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:
      print arcpy.GetMessages()
    
  6. 保存脚本。

  7. 如有必要,打开命令提示符并导航到 c:\ArcpyBook\Appendix1

  8. 在命令行中,键入以下内容并按 Enter 键:

    python ListFields.py c:\ArcpyBook\data Burglaries_2009.shp
    
  9. 再次运行后,您应该看到输出详细说明 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. 给您的任务起一个名字。在这种情况下,我们将称之为List Fields from a Feature Class。点击下一步如何操作...

  4. 选择任务执行时的触发器。这可以是,并且通常会是基于时间的触发器,但也可以有其他类型的触发器,例如用户登录或计算机启动。在这种情况下,让我们只选择每日。点击下一步如何操作...

  5. 选择一个开始日期/时间以及重复间隔。在下面的屏幕截图中,我选择了日期为12/3/2012,时间为1:00:00 AM,重复间隔为 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 程序员来说,一个常见的任务是读取包含 x 和 y 坐标以及其他属性信息的逗号分隔文本文件。然后,这些信息将被转换为 GIS 数据格式,如 shapefile 或地理数据库。

准备工作

要使用 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. 将文本文件的内容读取到一个列表中:

    lstFires = f.readlines()
    
  5. lstFires 变量中读取的所有行添加一个 for 循环以迭代:

    for fire in lstFires:
    
  6. 使用 split() 函数使用逗号作为分隔符将值拆分到一个列表中。这个列表将被分配给一个名为 lstValues 的变量。确保将此行代码缩进到您刚刚创建的 for 循环中:

    lstValues = fire.split(",")
    
  7. 使用引用纬度、经度和置信值的索引值创建新的变量:

    latitude = float(lstValues[0])
    longitude = float(lstValues[1])
    confid = int(lstValues[8])
    
  8. 使用 print 语句打印每个值:

    print "The latitude is: " + str(latitude) + " The longitude is: " + str(longitude) + " The confidence value is: " + str(confid)
    
  9. 关闭文件:

    f.close()
    
  10. 整个脚本应如下所示:

    f = open('c:/ArcpyBook/data/N_America.A2007275.txt','r')
    lstFires = f.readlines()
    for fire in lstFires:
      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()
    
  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文件。

然后,readlines()函数将整个文件内容读取到一个 Python 列表中,然后可以迭代这个列表。这个列表存储在一个名为lstFires的变量中。文本文件中的每一行都将是一个列表中的唯一值。由于这个函数将整个文件读取到列表中,您需要谨慎使用此方法,因为大文件可能会引起显著的性能问题。

for循环内部,该循环用于遍历lstFires中的每个值,使用split()函数从某种方式分隔的文本行创建一个列表对象。我们的文件是逗号分隔的,因此我们可以使用split(",")。您也可以根据其他分隔符(如制表符、空格或任何其他分隔符)进行分割。由split()创建的新列表对象存储在一个名为lstValues的变量中。这个变量包含每个野火值。这在上面的屏幕截图中有说明。您会注意到纬度位于第一个位置,经度位于第二个位置,依此类推。列表是从零开始的:

工作原理…

使用索引值(这些值参考纬度、经度和置信度),我们创建了新的变量,分别称为latitudelongitudeconfid。最后,我们打印出每个值。一个更健壮的地理处理脚本可能会使用InsertCursor对象将此信息写入一个要素类。

还有更多...

正如读取文件的情况一样,有几种方法可以将数据写入文件。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 账户是免费的。

如何操作…

按照以下步骤创建一个可以发送电子邮件的脚本:

  1. 打开 IDLE 并创建一个名为c:\ArcpyBook\Appendix2\SendEmail.py的文件。

  2. 为了发送带有附件的电子邮件,您需要导入smtplib模块以及os模块,以及电子邮件模块中的几个类。将以下import语句添加到您的脚本中:

    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. 保存并运行脚本。为了测试,我使用了我的个人 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 站点,并下载一个阿拉斯加野火的 Google Earth 格式文件。

如何做…

按照以下步骤创建一个连接到 FTP 服务器并下载文件的脚本:

  1. 打开 IDLE 并创建一个名为c:\ArcpyBook\Appendix2\ftp.py的文件。

  2. 我们将连接到 NIFC 的 FTP 服务器。访问他们的网站ftpinfo.nifc.gov/获取更多信息。

  3. 导入ftplibossocket模块:

    import ftplib
    import os
    import socket
    
  4. 添加以下变量,以定义 URL、目录和文件名:

    HOST = 'ftp.nifc.gov'
    DIRN = '/Incident_Specific_Data/ALASKA/Fire_Perimeters/20090805_1500'
    FILE = 'FirePerimeters_20090805_1500.kmz'
    
  5. 添加以下代码块以创建连接。如果发生连接错误,将生成一条消息。如果连接成功,将打印成功消息:

    try:
      f = ftplib.FTP(HOST)
    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 anonymously'
      f.quit()
    print '*** Logged in as "anonymous"'
    
  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()函数检索 KMZ 文件:

    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'
    DIRN = '/Incident_Specific_Data/ALASKA/Fire_Perimeters/20090805_1500'
    FILE = 'FirePerimeters_20090805_1500.kmz'
    
    try:
      f = ftplib.FTP(HOST)
    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 anonymously'
      f.quit()
    print '*** Logged in as "anonymous"'
    
    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. 保存并运行脚本。如果一切顺利,您应该看到以下输出:

    *** Connected to host "ftp.nifc.gov"
    *** Logged in as "anonymous"
    *** Changed to "/Incident_Specific_Data/ALASKA/Fire_Perimeters/20090805_1500" folder
    *** Downloaded "FirePerimeters_20090805_1500.kmz" to CWD
    
    
  12. 检查您的c:\ArcpyBook\Appendix2目录中的文件。默认情况下,FTP 会将文件下载到当前工作目录:如何操作……

它是如何工作的……

要连接到 FTP 服务器,您需要知道 URL。您还需要知道将要下载的文件的目录和文件名。在这个脚本中,我们硬编码了这些信息,这样您可以专注于实现 FTP 特定的功能。使用这些信息,我们随后创建了一个连接到 NIFC FTP 服务器。这是通过ftplib.FTP()函数完成的,该函数接受主机的 URL。

nifc.gov服务器接受匿名登录,因此我们以这种方式连接到服务器。请注意,如果服务器不接受匿名连接,您将需要获取用户名/密码。一旦登录,脚本随后将 FTP 服务器的根目录更改为DIRN变量中定义的路径。这是通过cwd(<path>)函数实现的。使用retrbinary()函数检索了kmz文件。最后,您将想要在完成操作后关闭与 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. 保存并运行脚本。你应该看到以下输出:

    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
    
    
  10. 在 Windows 资源管理器中,你应该能够看到如下截图所示的输出 .zip 文件。注意存档的大小。此文件是在没有压缩的情况下创建的:如何操作…

  11. 现在,我们将创建 .zip 文件的压缩版本以查看差异。对创建 .zip 文件的代码行进行以下更改:

    zfile = zipfile.ZipFile("shapefiles2.zip", "w", zipfile.ZIP_DEFLATED)
    
  12. 保存并重新运行脚本。

  13. 查看你刚刚创建的新 shapefiles2.zip 文件的大小。注意由于压缩导致的文件大小减少:如何操作…

工作原理…

在这个示例中,你以写入模式创建了一个名为 shapefiles.zip 的新 .zip 文件。在脚本的第一次迭代中,你没有压缩文件的内容。然而,在第二次迭代中,你通过将 DEFLATED 参数传递给 ZipFile 对象的构造函数来压缩了文件内容。然后脚本获取数据目录中的文件列表,并遍历每个文件。每个扩展名为 .shp.dbf.shx 的文件随后使用 write() 函数写入存档文件。最后,将写入存档的每个文件的名称打印到屏幕上。

还有更多...

可以使用 read() 方法读取存储在 ZIP 存档中的现有文件的文件内容。首先应以读取模式打开文件,然后你可以调用 read() 方法,传入一个表示要读取的文件名的参数。然后可以将文件内容打印到屏幕上,写入另一个文件,或存储为列表或字典变量。

读取 XML 文件

XML 文件被设计为一种传输和存储数据的方式。由于数据存储在纯文本文件中,因此它们是平台无关的。尽管与 HTML 类似,但 XML 的不同之处在于 HTML 是为显示目的而设计的,而 XML 数据是为数据而设计的。XML 文件有时被用作 GIS 数据在不同软件系统之间交换的格式。

准备工作

XML 文档由一个根元素、子元素和元素属性组成的树状结构。元素也被称为 节点。所有 XML 文件都包含一个 元素。这个根元素是所有其他元素或子节点的父元素。以下代码示例说明了 XML 文档的结构。与 HTML 文件不同,XML 文件是区分大小写的:

<root>
 <child att="value">
 <subchild>.....</subchild>
 </child>
</root>

Python 提供了多个编程模块,你可以使用这些模块来处理 XML 文件。你应该根据适合工作的模块来决定使用哪个模块。不要试图强迫单个模块做所有事情。每个模块都有它们擅长执行的具体功能。在这个示例中,你将学习如何使用文档中的 nodeselement 属性从 XML 文件中读取数据。

有多种方法可以访问 XML 文档中的节点。也许,最简单的方法是通过标签名称查找节点,然后遍历包含子节点列表的树。在这样做之前,你将想要使用 minidom.parse() 方法解析 XML 文档。一旦解析,你可以使用 childNodes 属性获取从树根开始的所有子节点的列表。最后,你可以使用 getElementsByTagName(tag) 函数通过标签名称搜索节点,该函数接受一个标签名称作为参数。这将返回与该标签相关联的所有子节点的列表。

你也可以通过调用 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. 保存并运行脚本。你应该看到以下输出:

    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 类派生的搜索类,然后从这个类创建一个对象。一旦创建,你就可以在搜索对象上调用 parse() 方法来搜索数据。最后,你可以使用 getElementsByTagName(tag) 函数通过标签名搜索节点,该函数接受一个标签名作为参数。这将返回与该标签相关联的所有子节点的列表。

posted @ 2025-10-01 11:27  绝不原创的飞龙  阅读(2)  评论(0)    收藏  举报