基于ArcGIS的Python编程秘笈(第2版)

978-7-115-43804-1
作者: 【美】Eric Pimpler(派普勒)
译者: 牟乃夏张灵先张恒才
编辑: 胡俊英
分类: ArcGIS

图书目录:

详情

本书以基础理论结合GIS开发实例的方式,循序渐进地介绍了Python在ArcGIS开发中的基本应用和相关技巧,以基本知识开始,陆续简洁了地图文档和地图层的管理、找到并修复一些破损数据,本书还致力于更好地实现ArcGIS内部任务的自动化。全书内容结构清晰,示例完整,适合各类和GIS开发相关的读者参考学习。

图书摘要

版权信息

书名:基于ArcGIS的Python编程秘笈(第2版)

ISBN:978-7-115-43804-1

本书由人民邮电出版社发行数字版。版权所有,侵权必究。

您购买的人民邮电出版社电子书仅供您个人使用,未经授权,不得以任何方式复制和传播本书内容。

我们愿意相信读者具有这样的良知和觉悟,与我们共同保护知识产权。

如果购买者有侵权行为,我们可能对该用户实施包括但不限于关闭该帐号等维权措施,并可能追究法律责任。

• 著    [美] Eric Pimpler

  译    牟乃夏 张灵先 张恒才

  责任编辑 胡俊英

• 人民邮电出版社出版发行  北京市丰台区成寿寺路11号

  邮编 100164  电子邮件 315@ptpress.com.cn

  网址 http://www.ptpress.com.cn

• 读者服务热线:(010)81055410

  反盗版热线:(010)81055315


Copyright ©2015 Packt Publishing. First published in the English language under the title Programming ArcGIS with Python Cookbook, Second Edition.

All rights reserved.

本书由英国Packt Publishing公司授权人民邮电出版社出版。未经出版者书面许可,对本书的任何部分不得以任何方式或任何手段复制和传播。

版权所有,侵权必究。


Python作为一种高级程序设计语言,凭借其简洁、易读及可扩展性日渐成为程序设计领域备受推崇的语言。使用Python作为GIS开发的脚本语言,将大大提升ArcGIS数据处理的效率。

本书将介绍如何使用Python来创建桌面ArcGIS环境下的地理处理脚本、管理地图文档和图层、查找和修复丢失的数据链接、编辑要素类和表中的数据等,以期能够提高 GIS开发人员的工作效率。

本书内容结构清晰,示例完整,不仅适合从事GIS开发的专业人士,而且适合那些有兴趣接触或从事Python编程的读者。


ArcGIS(ARC/INFO)软件从诞生之日起就引领着地理信息系统的技术潮流,它的很多技术方法和理念已成为教科书的内容。在某种程度上,我们甚至可以说由它驱动了地理信息软件产业的发展。ArcGIS软件由于其面向地理问题的科学理念,不断创新的技术方法,已在国内外市场占据了主导地位。特别是在国内市场,更可谓是一枝独秀。因此,掌握ArcGIS软件及其开发技巧不仅是GIS从业者必备的基本功,也是在校大学生和研究生基本的专业技能。

基于ArcGIS软件的二次开发,针对不同的需求应采取不同的开发方式。如果要深入行业应用的业务逻辑,使GIS成为工作流的一部分,则可以采用ArcGIS Engine进行细粒度的桌面端应用软件的设计与开发。如果GIS功能需求相对简单,侧重于数据的可视化和分析制图,那么可以采用ArcGIS Server开发Web端的应用。如果面向的用户对GIS的需求侧重于对地图的浏览,那么移动 GIS 则是首选的开发方式。当然,无论采用哪一种开发方式,都需要一定的开发工作量。而且采用这些方式开发的应用软件,尽管都是采用ArcGIS 平台提供的接口,但是在形式上是脱离 ArcGIS 运行的,也就无法充分利用 ArcGIS提供的强大的功能模块。总体来说,上述开发方式针对的往往是公共用户或者大众用户,而非GIS专业用户。

由于ArcGIS的触角已渗透到各行各业,大多数企事业单位的GIS从业人员能在一定程度上熟悉ArcGIS软件的使用,ArcGIS软件也成为他们日常业务的得力助手。但是工作中经常会有一些行业特色的应用或者大量重复的工作,仅凭ArcGIS软件来完成是有一定难度的,或者工作量超过了可承受的范围。这时,如果能通过一些简单的编程来满足特殊需求或者提高自动化处理的水平,则可以起到事半功倍的效果。同样,对于那些经常使用ArcGIS进行数据处理和分析的科研工作者,也时常需要对ArcGIS进行改造以满足专业研究的深度应用。实际上,有时仅仅几句简单的代码就可以满足用户的要求,解决工作难题,提高工作效率。因此,在ArcGIS平台的基础上进行改造和定制,既能最大化地利用ArcGIS软件提供的功能,又可以最大化地满足个性化的需求。这似乎是基于ArcGIS开发的最聪明的方式,也是有一定ArcGIS使用基础的数量庞大的GIS行业用户最现实的深度掌握和应用ArcGIS的方式。

ArcGIS软件在不同时期也提供了不同的定制开发方式,如VBA方式、动态库方式等,但是这些开发方式对读者的编程水平要求较高,不适于大范围推广。Python语言由于语法简洁,简单易学,适合没有编程经验的初学者。ArcGIS已经将其内嵌于桌面软件中,因此使用Python语言进行ArcGIS的定制开发是近年Esri力推的开发方式。这种方式介于单纯使用ArcGIS软件来处理与分析数据和使用ArcObjects进行深度开发之间,特别适用于那些具有一定的ArcGIS软件使用基础,却又不想在编程方面投入较多精力,同时还需要针对ArcGIS软件做一些扩展和智能化应用的用户。

本书就是讲解如何使用Python这一脚本语言来进行基于ArcGIS平台的二次开发。主要介绍了Python语言的架构、数据管理、地图制图、数据查询与检索、地理处理工具的调用等基本功能,还介绍了如何定制ArcGIS的界面,访问ArcGIS server发布的地图服务等功能,并提及了ArcGIS Pro下Python的编程。本书概念清晰、条理清楚、步骤详细,特别适合初学者。对于具有一定开发经验的读者来讲,也具有一定的参考价值。

本书由山东科技大学的牟乃夏、张灵先和中国科学院地理科学与资源研究所的张恒才3人统筹规划,分工负责各个章节的审校,最后由3人统稿并定稿。山东科技大学的研究生许璐璐、张晨、廖梦迪、杨忍等和江苏省邳州市国土资源局的赵永分别负责了其中一部分的翻译工作。

尽管本书经过翻译人员的多次集体讨论和修改方才定稿,以力求全面真实地再现原著。由于中外著作写作风格与语言表达的差异,为了兼容国内读者的阅读习惯,我们在贯彻“信、雅、达”的基础上,对很多技术细节依据自己的理解进行了调整。限于作者的学识和经验,定有不少疏漏和不当之处,甚至是错误也在所难免,恳请读者和同行批评指正。读者的批评和建议请致信:mounaixia@163.com,或者关注译者的微博@山东科大牟乃夏老师GISer,译者将及时发布本书的勘误,并对读者的建议、意见和学习指导进行反馈。

牟乃夏

于青岛开发区洞门山下寓所


牟乃夏,博士、博士后,知名GIS技术作家,现为山东科技大学测绘学院副教授,硕士生导师。已出版《ArcGIS 10地理信息系统教程-从初学到精通》《ArcGIS Engine地理信息系统开发教程》《CityEngine城市三维建模》等多部著作,并被全国诸多高校采用为相关课程的教材,收到同学们的广泛好评。目前主要从事地理信息科学的理论研究和工程实践,开发了城市管网、环境保护、地质矿产等多个行业软件,已获得软件著作权30余项。科研方向主要为时空数据挖掘,已主持和参与国家自然科学基金、山东省自然科学基金、中国博士后基金、国家863计划等多项课题,发表论文40余篇,培养研究生50余人。


Eric Pimpler是GeoSpatial Training Services(http://geospatialtraining.com/)的创始人和所有者,他使用Esri、Google Earth/Maps和开源技术等进行GIS实践和教学已有20多年的历史。目前,Eric侧重于使用Python编写ArcGIS脚本,以及使用JavaScript开发web和移动ArcGIS Server应用程序。此外,Eric还编写了《Programming ArcGIS with Python Cookbook》和《Building Web and Mobile ArcGIS Server Applications with JavaScript》(中文版名为《JavaScript构建Web和ArcGIS Server应用实战》由人民邮电出版社出版)两本书,这两本书都已经由Packt出版社出版。

Eric获得了美国德克萨斯A&M大学地理学专业的学士学位,以及美国德克萨斯州立大学应用地理学(GIS方向)专业的硕士学位。


Mohammed Alhessi是一位主要研究地理空间分析理论、算法和应用的GIS专家和培训师,在GIS分析、开发和培训等方面具有丰富的经验。他为不同专业背景的人开设了很多培训课程,培训课程涉及到GIS应用的各个领域,包括MS SQL Server企业数据库管理、空间数据分析和建模、面向ArcGIS的Python脚本编程等。

Mohammed曾是德国斯图加特大学的一名GIS开发人员,在职期间使用Java和Python开发了许多地理处理工具。此外,他还参与过当地的许多GIS项目,为当地社区提供了咨询服务。目前,他是巴勒斯坦加沙伊斯兰大学的一名讲师,并且还在巴勒斯坦加沙大学应用科学学院开设了课程。

Mohammed获得了巴勒斯坦加沙伊斯兰大学土木工程专业的学士学位,以及德国斯图加特大学测绘工程专业的硕士学位。

Matthew Bernardo是新港可再生能源(Newport Renewables)公司的一名高级GIS分析师,该公司是位于美国新港的一家可再生能源公司。作为一个狂热的户外运动达人和技术爱好者,他热衷于将GIS技术与环境相结合。在过去的几年里,他使用GIS和Python编程处理了包括可再生能源、情报分析、遥感、海洋科学、环境科学和城市规划等多个领域中的复杂问题。

Matthew获得了美国罗德岛大学环境科学专业的理学学士学位,以及美国宾夕法尼亚州立大学地理空间情报专业的硕士学位。

Rahul Bhosle获得了印度希瓦吉大学信息技术工程专业的学士学位和美国北卡罗来纳州立大学地理信息科学与技术专业的硕士学位。目前,他是美国GIS数据资源(GIS Data Resources)公司的一名GIS开发人员。按专业来说,他是一名地理空间开发人员,在Python、JavaScript、ArcGIS Suite、GeoServer、PostGIS、PostgreSQL、SQL Server、Leaflet、Openlayers、Machine Learning和NoSQ等运用方面具有丰富的经验。

Kristofer Lasko获得了美国马里兰大学地理科学专业的学士学位和地理空间信息科学专业的硕士学位。他现在在马里兰大学分别给研究生和本科生讲授 GIS 课程。几年前,他发现以自动化的方式处理日常任务和大量的地理空间数据是非常有必要的,于是他开始学习Python。

目前,他正在马里兰大学攻读地理科学专业的博士学位。在此之前,他曾在NASA(美国国家航空航天局)的戈达德太空飞行中心和喷气推进实验室工作,也曾作为GIS和遥感分析师在马里兰大学工作过。目前他的研究重点是越南农作物燃烧的残留。

可以浏览如下网址来访问他的个人网页:http://terpconnect.umd.edu/~klasko/cv.html

Doug McGeehan是美国密苏里州密苏里科学技术大学罗拉分校博士三年级的学生,现正在Sanjay Madria博士和Dan Lin博士的指导下从事计算机科学技术的研究。2013年,他获得了美国密苏里科学技术大学计算机科学专业的学士学位,并在《computational geometry》(《计算机几何》)期刊上发表了两篇论文。目前他在美国地质调查局(USGS)从事计算机制图工作。

Ann Stark在2005年成为GISP,从事GIS工作已有20多年。她热衷于GIS行业,是美国西北太平洋地区GIS社区中的活跃成员,不仅协调当地用户组,而且担任区域GIS专业组的主席。她还是一位热心的老师,主要讲解如何有效地在ArcGIS中使用Python,并且她会在她的博客(https://gisstudio.wordpress.com/)上分享相关主题的内容。此外,她还是美国萨利希海岸科学(Salish Coast Sciences)公司的GIS咨询顾问,为该公司提供战略规划、过程自动化和GIS开发服务等方面的咨询服务。

在工作之余,Ann会和她的丈夫与儿子一起去城市中心的城市农场,在那里体验可持续的生活方式以及城市农场的自给自足。


ArcGIS是Esri公司研发的构建于工业标准之上的地理信息系统软件系列的总称。

本书将介绍如何使用Python语言来创建桌面ArcGIS环境下的地理处理脚本、工具和快捷方式等。并通过介绍如何使用Python语言和桌面ArcGIS来自动执行地理处理任务、管理地图文档和图层、查找和修复丢失的数据链接、编辑要素类和表中的数据等,以期能够有效地提高GIS工作人员的工作效率。

本书首先介绍了桌面ArcGIS环境中Python编程的基本概念,然后通过具体的操作方法来介绍如何使用Python编程实现ArcGIS中的地理处理任务。

在使用ArcGIS工作时,针对特定的任务编写脚本可以有效地节省GIS工作人员的时间和工作量。本书根据ArcGIS脚本处理的功能分为不同的主题进行讲解,主要包括管理地图文档文件、自动化地图制图和打印、查找和修复丢失的数据链接、创建自定义地理处理工具、编辑要素类和表中的数据等。

通过对本书的学习,读者将学会如何设计和使用合适的方法来编写地理处理脚本,以完成指定的任务。

第1章主要介绍Python语言的基本架构,首先介绍了如何创建新的Python脚本及编辑已有的脚本;其次介绍了Python语言的特点,如添加注释、创建变量并赋值、创建内置变量等,以使Python的代码更加简单明了;还介绍了Python语言提供的各种内置数据类型,如字符串、数字、列表和字典等;最后介绍了一些语句,包括条件语句、循环语句和with语句等。

第2章主要介绍如何使用ArcPy制图模块管理地图文档和图层文件,包括在地图文档中添加和移除地理图层,将图层插入到数据框中,在地图文档中移动图层,以及更新图层属性和符号系统等。

第3章主要介绍如何在地图文档文件中生成丢失的数据源列表,并应用ArcPy制图模块中的函数修复丢失的数据源。此外,还介绍了如何通过编程来修复多个地图文档中丢失的数据源。

第4章主要介绍如何自动化地创建高质量的地图,以及如何将这些地图进行打印、导出为图像文件或PDF文件等并存入地图册中。

第5章主要介绍如何编写脚本来访问和运行ArcGIS提供的地理处理工具。

第6章主要介绍如何创建自定义的地理处理工具,这些工具既可以添加到ArcGIS中,又能够与其他用户共享。自定义地理处理工具需要添加一个Python脚本,该脚本可以以某种方式处理或分析地理数据。

第7章主要介绍如何在脚本中执行Select Layer by Attribute和Select Layer by Location地理处理工具来选择要素和记录。包括:如何为Select Layer by Attribute工具的可选参数where子句构造查询语句,如何使用作为临时数据集的要素图层和表视图等。

第8章主要介绍如何创建地理处理脚本来选择、插入或更新地理数据图层和表中的数据。通过使用ArcGIS 10.1中新的数据访问模块,地理处理脚本可以创建要素类和表中数据的内存表,即游标。此外,还将介绍如何创建不同类型的游标,如搜索游标、查询游标和更新游标等。

第9章主要介绍如何通过使用ArcPy的Describe函数获取关于地理数据集的描述性信息。一项具体的地理处理任务的第1步通常是生成一个地理数据的列表,其后才是针对这些数据集进行的各种地理处理操作。

第10章主要介绍如何通过创建Python加载项来定制ArcGIS界面。Add-in(加载项)提供了一种扩展桌面应用程序的方式,即使用模块化的代码库,将用户界面(UI)元素添加到桌面ArcGIS中,这个模块化的代码库是为执行特定操作而设计的。UI组件包括按钮、工具、工具条、菜单、组合框、工具选项板和应用程序扩展模块等。基于Python语言的加载项,需要使用Python脚本和XML文件来创建,其中XML文件用来定义用户界面的显示方式。

第11章主要介绍如何处理运行地理处理脚本时生成的错误和异常,讲解了如何使用try/except语句捕获ArcPy和Python的错误,并进行相应的响应。

第12章主要介绍如何使用ArcGIS REST API和Python访问由ArcGIS Server和ArcGIS Online发布的服务。首先介绍了如何制作HTTP请求并解析响应、导出地图、查询地图服务、进行地理编码等。然后介绍了一些ArcPy的其他内容,如FieldMap和FieldMappings类,以及ValueTable对象的使用等。

第13章主要介绍新的ArcGIS Pro环境与桌面ArcGIS中Python的差异,特别是使用Python窗口编写和执行代码的差异。

附录A主要介绍如何在规定的时间运行地理处理脚本。许多脚本的执行需要花费很长的时间,这就需要将其安排在非工作时间内执行。具体介绍了如何创建包含地理处理脚本的批处理文件以及如何在规定的时间执行它。

附录B主要介绍如何使用Python编写脚本来执行一些常规的任务,如读取和编辑带分隔符的文本文件、发送邮件、访问FTP服务、创建.zip文件、读取和编辑JSON与XML文件等。每个GIS程序员都应该知道如何编写Python脚本来实现这些功能。

要完成本书中的练习,需要安装具有基础版、标准版或高级版许可级别的桌面ArcGIS 10.3。安装桌面ArcGIS 10.3时,会同时安装Python 2.7和Python代码编辑器IDLE。本书也同样适用于桌面ArcGIS 10.2和ArcGIS 10.1。另外,由于第13章要在ArcGIS Pro中使用Python,因此需要安装ArcGIS Pro 1.0。

本书面向的读者是那些想要使用Python革新ArcGIS工作流程、提高工作效率的GIS专业人员。无论是初学者,还是经验丰富的专业人员,几乎每天都需要花费大量时间来执行各种地理处理任务。本书将介绍如何使用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'>]

新的术语和重要词汇用粗体显示,例如屏幕上、菜单或对话框中的词汇等,其在正文中的样式为单击“Start | All Programs | ArcGIS | Python 2.7 | IDLE”。

注意事项或重要的笔记会以这种形式表示。


提示和技巧会以这种形式表示。

欢迎读者对本书进行反馈,这可以让我们了解读者对本书的意见——是否喜欢这本书。读者的反馈意见对我们非常重要,因为它可以帮助我们编写出更符合读者需求的书,使读者可以从我们的书中获得最大的帮助。

读者的反馈意见可以发送邮件到feedback@packtpub.com,并在邮件的主题上注明书名。

如果读者对本书的任何一部分内容有深入见解,并且有兴趣编写或补充相关专业知识,可以访问作者指南:www.packtpub.com/authors。

如果读者购买了Packt出版社的图书,可以享受以下权益。

使用个人账户在http://www/PacktPub.com网站上购买了Packt出版社出版的图书的读者,可以直接下载示例代码文件;在其他地方购买的读者,可以访问http://www.PacktPub. com/support,注册账户后代码文件会通过邮件发送给用户。

虽然我们已经尽可能地确保内容的准确性,但是由于编者水平有限,错误与不妥之处在所难免,敬请广大读者批评指正,以便避免误导其他读者,同时帮助我们改进和完善本书的后续版本。如果读者发现任何错误——不论是正文中的还是代码中的,请记录错误的信息,访问勘误页面:http://www.packtpub.com/submit-errata,选择本书,输入发现的错误的详细信息。一旦读者提交的勘误内容通过验证,我们就会接受该勘误,并将其上传到packt出版社的网站上或添加到“Errata”下的勘误列表中。

互联网上存在盗版资料一直是所有媒体都存在的问题。我们非常重视版权的保护和授权的合法性。如果读者在互联网上看到了非法抄袭本书内容的情况,无论对方以何种形式抄袭,请立即向我们提供网址或网站名称,我们将会采取补救措施。

请将涉嫌盗版资料的链接发送到copyright@packtpub.com,我们会非常感谢读者对出版方和作者权益的保护。

如果读者有任何关于本书的问题,都可以通过questions@packtpub.com邮箱联系我们,我们将竭尽全力解决读者的问题。


同其他编程语言一样,Python也支持多种类型的程序架构。本章主要介绍Python的基本语言架构。首先,介绍如何创建新的Python脚本及编辑已有的脚本;其次,介绍Python语言的特点,如添加注释、创建变量并赋值、创建内置变量等,以使Python的代码更加简单明了。

然后,介绍Python语言提供的各种内置数据类型,如字符串、数字、列表和字典等。类和对象是Python等面向对象编程语言的基本概念,在使用ArcGIS编写地理处理脚本时会经常用到它们,所以本章也介绍了这些复杂的数据类型。

另外,本章还介绍了一些语句的概念,包括条件语句、循环语句和with语句等。使用Python编写ArcGIS地理处理脚本时,常常用with语句打开cursor(游标)来循环遍历代码块。cursor对象来自于ArcPy的数据访问模块,它有插入、搜索和更新3种数据处理的方式。

最后,介绍如何访问Python语言的其他功能模块。

学完本章,读者将会掌握以下内容。

正如前言提及的,在桌面ArcGIS的安装过程中,会同时安装Python和IDLE。IDLE是编写Python程序代码的集成开发环境,本书中的很多代码都是在IDLE或桌面ArcGIS的Python窗口中编写的。随着编程能力的不断提高,读者可以选择IDLE以外的其他开发环境,如PyScripter、Wingware、Komodo等进行代码的编写,具体选择哪种开发环境依个人喜好而定。

单击“Start | AllPrograms | ArcGIS | Python 2.7 | IDLE”,可以启动Python的IDLE开发环境。需要注意的是,在ArcGIS的安装过程中一同安装的Python版本,取决于ArcGIS的版本。如ArcGIS 10.3使用Python 2.7,而ArcGIS 10.0则使用Python 2.6。

Python Shell窗口如图1-1所示。

图1-1 Python Shell窗口

Python Shell窗口用来显示输出结果和脚本的错误信息。初学者常常误以为地理处理脚本也写在Shell窗口中,实际上需要创建一个单独的代码窗口来编写脚本,详见本书1.1.2节。

虽然一般不在Shell窗口中编写完整的脚本,但是可以以交互的方式编写代码并获得及时的反馈。ArcGIS提供了一个内置的Python Shell窗口,使用方法与之类似,详见本书1.2节。

在Python Shell窗口中单击“File | New Window”创建一个新的代码窗口,可以在这个独立的窗口中编写脚本。该窗口称为Python脚本窗口,如图1-2所示。

图1-2 Python脚本窗口

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

打开已有的Python脚本有两种方式:一是在Python Shell窗口中单击“File | Open”,选择要打开的脚本文件;二是在Windows资源管理器中右击文件,单击“Edit with IDLE”,如图1-3所示。通过这两种方法中的任何一种即可打开一个新的脚本窗口,同时脚本会加载在脚本编辑器中。

图1-3 在资源管理器中打开已有的Python脚本

在本例中,IDLE加载了ListFeatureClasses.py脚本文件,其对应的Python脚本窗口中的代码如图1-4所示。

图1-4 ListFeatureClasses.py脚本

脚本窗口打开后,可以在其中写入或编辑代码,还可以在这个窗口中进行基本的脚本调试,调试是一个识别和修正代码错误的过程。

当写好一个地理处理脚本或者打开了一个已有的脚本之后,就可以在Python脚本窗口中执行代码。IDLE提供了语法检查功能,在运行脚本之前,可单击“Run | Check Module”来检查代码的语法错误。

如果有语法错误,一般情况下会跳转到Shell窗口并在Shell窗口中显示错误的详细信息,而有些语法错误不会跳转到Shell窗口,此时会弹出“Syntax error”对话框并在脚本窗口中高亮显示错误的位置,具体会出现哪种情况取决于语法错误的类型。如果没有语法错误,将不做提示。虽然IDLE界面可以检查语法错误,但是无法检查代码的逻辑错误,也没有像其他开发环境(如PyScripter、Wingware等)一样可以提供更高级的调试工具。

如果代码中不存在语法错误,单击“Run | Run Module”运行脚本,如图1-5所示。

图1-5 运行脚本

运行脚本后,print 语句的输出结果、错误消息和系统消息都会在Python Shell窗口中显示。print语句在Shell窗口中只输出文本,它经常用于更新脚本的运行状态或显示代码的调试信息。

1.1节介绍了如何使用Python的IDLE开发环境,本节给出一个地理处理脚本实例来说明如何使用ArcGIS Python窗口。刚开始编写代码时,人们通常在桌面ArcGIS Python窗口中编写脚本,当脚本越来越复杂时,会转向使用IDLE或者其他开发环境。

ArcGIS Python窗口是桌面ArcGIS 10.x中的一个嵌入式、交互式的窗口,它在测试小型代码块、学习Python基础知识、建立方便快捷的工作流以及执行地理处理工具方面都是一个新颖而又理想的选择。对于初学者来说,ArcGIS Python窗口是个极好的起点!

ArcGIS Python窗口除了可用于编写代码外,还有很多其他的功能。它可以把窗口中的内容以Python脚本文件的形式保存到磁盘中,也可以把已有的Python脚本加载到窗口中。窗口有停靠和浮动两种状态,停靠状态下可以固定在ArcGIS界面的不同位置,浮动状态下可以任意放大或缩小。右键单击窗口并选择“Format”,可以设置窗口上的字体和文本颜色等格式。

单击桌面ArcGIS上“标准”工具条的“Python”按钮,打开Python窗口,如图1-6所示。这是一个浮动窗口,可以根据需要调整大小,也可以在ArcMap界面的任意位置停靠。

图1-6 ArcGIS Python窗口

Python窗口本质上是一个Shell窗口,只能在主提示符(>>>)后一次性输入一行语句。如果有问题,可以查看分隔线右边的帮助窗口。

右键单击Python窗口,从菜单中选择“Load…from the menu”,可以加载已有的脚本。如果想设置窗口上的字体和文本颜色,右键单击窗口并选择“Format”,在弹出的Python Window Format窗口中(如图1-7所示)可以选择黑色/白色主题,并设置个性化的字体和颜色。

图1-7 Python Window Format窗口

图1-8所示为单击“Set Black Theme”按钮设置黑色主题的例子,如果长时间编写代码,使用这种主题会使眼睛更舒服。

图1-8 黑色主题界面

ArcGIS Python窗口还提供了代码补全功能,以简化程序员的工作,读者可以在ArcGIS Python窗口中键入“arcpy.”来试试这个功能,如图1-9所示。ArcPy是一个面向模块的软件包,使用点记法能够访问对象的属性和方法。在对象名后键入“.”会出现下拉列表,列表中提供了用于这个对象的工具、函数、类或扩展模块等。所有对象都有自己的关联项,因此根据所选对象的不同,项目列表的显示也会有所不同。

图1-9 代码补全功能

如图1-10所示为一个自动筛选列表,当键入工具、函数、类或扩展模块的名称时,该列表会根据输入的内容进行筛选。

图1-10 自动筛选功能

通过鼠标从列表中单击或者用方向键上下移动来高亮显示需要的条目,然后按下〈Tab〉键,Python窗口就会自动补全代码。自动补全功能简单易用,大大减少了代码中的拼写错误,使程序员的工作更加快速高效。

了解Python语言的基本架构,有助于读者更有效地编写ArcGIS地理处理脚本。尽管Python语言相对于其他编程语言来说更易学,但要想真正掌握它,也需要花一定的时间来学习和练习。本节将介绍如何创建变量及给变量赋值,可赋值给变量的数据类型,如何使用不同类型的语句和对象,如何读写文件和导入Python第三方模块等内容。

编写Python脚本时,一般都需要遵循约定俗成的程序架构。通常在每个脚本的开头是说明部分,用来说明脚本的名称、作者和处理过程的梗概,以帮助程序员快速了解脚本的细节和用途。在Python中,说明部分通常使用注释来实现。注释是脚本中以#或##开头的代码行,#或##后跟随说明代码的文字,用来解释脚本中某些代码或代码块的功能。注释只起到说明代码的作用,在代码运行时Python解释器并不执行它。如图1-11所示,注释是以#为前缀的代码行。要尽量在整个脚本的重要部分添加注释,以使程序更易读,这对更新脚本非常有用。

图1-11 脚本的说明注释

下载示例代码 

使用个人账户在http://www/PacktPub.com网站上购买了Packt出版社出版的图书的读者,可以直接下载示例的代码文件;在其他地方购买的读者,可以访问http://www.PacktPub.com,注册账户后代码文件会通过邮件发送给用户。

尽管Python语言有很多内置的函数,能够完成不同的功能,但仍然需要经常访问存储在外部模块中的具有特定功能的函数集以完成特定的功能。例如,math模块存储与数值处理有关的特定函数,R模块提供与统计分析有关的函数等。一般说来,函数是一个已命名的代码块,执行时只需调用其名称。模块则是由一系列函数构成的,它可以通过import语句导入。import语句通常是脚本文件中的第1行代码(不包括注释)。在编写ArcGIS地理处理脚本时,需要导入arcpy模块,该模块是访问ArcGIS提供的GIS工具和函数的Python工具包。下面的代码展示了如何导入arcpy模块和os模块,其中os模块提供了与底层操作系统进行交互操作的接口。

import arcpy
import os

一般来说,变量可视为计算机内存中的一块区域,用来存储脚本运行过程中的值。在Python中进行变量定义时,并不需要预先声明变量的类型,只需直接命名和赋值,通过引用变量名就可以在脚本中任意位置访问赋给变量的值。例如,创建一个包含要素类名称的变量,然后通过缓冲区工具引用该变量可以创建一个新的输出数据集。在创建一个变量时只需指定它的名称,通过赋值运算符(=)就可以实现变量的赋值,如下所示。

fcParcels = "Parcels"
fcStreets = "Streets"

表1-1列出了以上代码示例的变量名和赋给变量的值。

表1-1  变量名和赋给变量的值

变 量 名

变 量 的 值

fcParcels

Parcels

fcStreets

Streets

创建变量必须遵循如下命名规则。

命名变量时必须避免使用Python语言的关键字,如classifforwhile等。在Python语句中,这些关键字通常会以不同的颜色突出显示。

下面是一些合法的变量名。

下面是一些非法的变量名。

Python语言区分大小写,所以要特别注意脚本中的大小写,如变量的命名等。对初学者来说,大小写问题是最常见的错误来源,所以当代码出现错误时要首先考虑大小写问题。来看一个例子,下面是3个变量,虽然每个变量的名字相同,但是由于大小写的不同,实际上创建的是3个不同的变量。

如果输出这些变量,会得到以下结果。

print(mapsize)
>>> 22x34
 
print(MapSize)
>>> 8x11   #output from print statement

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

要变量名在整个脚本中保持一致,最好的做法就是采用camel命名法,即变量名的第1个单词全部小写,而后连接的每个单词的首字母大写。如以变量名fieldOwnerName为例来说明这一概念。第1个单词(field)所有字母小写,第2个单词(Owner)和第3个单词(Name)的首字母大写。

fieldOwnerName

Python中的变量是动态的,也就是说不需要预先声明变量的类型,变量赋值时就已经隐式地声明变量的类型了。赋值给变量的常用数据类型如表1-2所示。

表1-2  常用数据类型

数据类型

示例值

示例代码

String

"Streets"

fcName = "Streets"

Number

3.14

percChange = 3.14

Boolean

True

ftrChanged = True

List

"Streets", "Parcels", "Streams"

lstFC = ["Streets", "Parcels",
"Streams"]

Dictionary

'0':Streets,'1':Parcels

dictFC = {'0':Streets,'1':Parcels]

Object

Extent

spatialExt = map.extent

接下来的章节会详细介绍这些数据类型。

在C#中,使用变量之前必须先定义变量的名称和类型,而Python则只需定义变量名,通过赋值就可以使用该变量,变量的具体数据类型由Python后台识别。

下面的C#代码示例创建了一个名为aTouchdown的整型变量,它只能包含整数数据,然后给该变量赋值整数6。

int aTouchdown;
aTouchdown = 6;

在Python中,这个变量可以动态地创建和赋值,如下列代码所示。Python解释器可以动态地判断赋给变量的数据类型。

aTouchdown = 6

有时候需要创建一个变量,但事先并不知道具体为它赋何值,在这种情况下,可以简单地创建一个没有赋值的变量,下面的代码示例就创建了这样一个变量。

aVariable = ''
aVariable = NULL

赋值给变量的数据可以在脚本运行时改变。

变量可以存储不同类型的数据,包括基本数据类型,如字符串和数字,以及更复杂的数据类型,如列表、字典和对象等。接下来介绍可以赋值给变量的不同数据类型以及Python提供的各种操作数据的功能。

Python有一些内置的数据类型。这里首先介绍string类型,之前已经给出几个string变量的例子,这种变量类型有多种操作方式,下面详细介绍这种数据类型。

1.字符串

字符串是字符的有序集合,用于存储和表示文本信息。当字符串赋值给变量时,要由英文单引号或双引号括起来,它可以是一个名称、要素类名称、where子句或其他任何可编码的文本。

2.字符串操作

在Python中,字符串有多种操作方式,其中字符串连接是比较常用且容易实现的操作方式之一。“+”操作符可以把它两边的字符串变量连接起来形成一个新的字符串变量。

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

运行上述代码,将得到以下结果。

>>>C:\GISData\Streets.shp

判断字符串是否相等可以使用“==”操作符,就是简单地把两个等号放在一起。读者一定要注意不要混淆相等操作符和赋值运算符:相等操作符有两个等号,而赋值运算符只有一个等号;相等操作符用于判断两个变量是否相等,而赋值运算符用于给变量赋值。

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

运行上述代码示例会得到以下结果,是因为“firstName”和“lastName”变量不相等。

>>>False

判断变量是否包含某个字符串可以使用“in”操作符,如果第 1 个操作对象包含于第2个操作对象中则返回True。

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

正如前文所述,字符串是字符的有序集合,也就意味着可以访问字符串中的单个字符或一串字符,只要不人为改变,字符的顺序都会保持不变。而有些集合却不能保持设定的顺序,如字典等。在Python中,访问单个字符称为索引,访问一串字符称为切片。

字符串中的单个字符可以通过字符串变量后的方括号内的偏移量来获得,如使用fc[0]可以获得fc变量的第1个字符。Python是一种从零开始的语言,也就是说列表中第1项的索引值是0。负偏移用于从字符串的末尾逆向搜索,在这种情况下,字符串最后一个字符的索引值是−1。索引总是创建一个新变量来保存字符。

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

图1-12说明了字符串是字符的有序集合,第1个字符的索引值是0,第2个字符的索引值是1,接下来的每个连续字符按顺序占用一个索引值。

图1-12 字符串的索引值

字符串索引只能获得string变量的单个字符,而字符串切片能够提取字符串的连续序列,其格式和语法与索引类似,但需要引入第二偏移量来指定要截取的字符序列的结束位置,从而获得要返回的子字符串。

下面的代码是一个字符串切片的例子,先把“Floodplain.shp”赋值给“theString”变量,然后使用theString[0 : 5]获得“Flood”切片。

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

提示: 

Python切片返回的字符开始于第一偏移量,结束于第二偏移量,但不包括第二偏移量。这对于初学者来说特别容易混淆,也是一种经常犯的错误。在上述例子中,返回的变量包含“Flood”字符串,第1个字符的索引值是0,对应字符“F”,最后一个返回的字符索引值是4,对应字符“d”。请注意,索引值5不包括在内,因为Python切片仅返回到第二偏移量的前一个索引值对应的字符。

任一偏移量都可以省略,这实际上是创建了一个通配符。例如,theString[1:]要求Python返回从第2个字符开始到字符串末尾的所有字符;theString[:-1]要求Python返回从第1个字符开始到倒数第2个字符的所有字符。

Python是一门优秀的语言,在字符串操作方面提供了很多函数,可以方便地对字符串进行处理。但是限于篇幅,大多数的字符串操作功能本书并没有介绍,仅仅介绍如下字符串操作功能。

使用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"

3.数字

Python内置的数值型数据有intlongfloatcomplex等。把数字赋值给变量的方式与字符串类似,不同之处在于不需要使用引号把值引起来并且它还必须是一个数值。

Python支持所有常用的数字操作,包括加、减、乘、除、取模和求余等,还可以使用函数进行返回绝对值、将字符串转换成数值型数据和四舍五入等操作。

尽管Python提供了一些内置的数学函数,但是如果要访问其他更高级的数学函数则需要使用math模块。当然,在使用这些函数前必须先使用import导入math模块,代码如下。

import math

math模块提供的函数有向上舍入和向下取整函数、绝对值函数、三角函数、对数函数、角转换函数和双曲函数等。值得注意的是,Python并没有提供函数来计算中位数或平均值,需要编程来实现。有关math模块的更多细节可以通过单击“All Programs | ArcGIS | Python 2.7 | Python Manuals”来查看。打开Python Manual后,在目录栏里单击“The Python Standard Library | Numeric and Mathematical Modules”,你就可以查看任何的数据类型、语法、内置函数以及其他想详细了解的内容了,在此不一一赘述。

4.列表

Python提供的第3种内置数据类型是列表。列表是元素的有序集合,它可以存放Python支持的任何一种数据类型,也可以同时存放多种数据类型。这些数据类型可以是数字、字符串、其他列表、字典和对象等。例如,一个列表变量可以同时存放数字和字符串。列表是从零开始的,即列表中第1个元素的索引值是0,如图1-13所示。

图1-13 列表的索引值

之后列表中每个连续对象的索引值依次增加1。此外,列表的长度可以根据需要动态地增长和收缩。

列表是通过在方括号内赋一系列的值来创建的。要提取列表中的值,只需在变量名后的方括号内填写相应的索引值即可,代码如下所示。

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

通过使用append()方法可以在已有的列表中添加新元素,具体代码如下。

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

列表可以通过切片返回多个值。下列代码所示为用冒号隔开两个偏移量进行列表切片操作,第一偏移量表示起始索引值,第二偏移量表示终止索引值,注意并不是返回终止索引值对应的值,而是其前一个索引对应的值,前面已经讲述。列表切片返回的是一个新的列表。

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

列表本质上是动态的,即可以在已有的列表中添加元素、删除元素和改变已有的内容,且这些操作不需要创建新的列表副本。改变列表中的值可以通过索引或切片来实现,索引改变的是列表中的单个值,而切片改变的是列表中的多个值。

Python 中有许多操作列表中值的方法,如:sort()方法可以对列表中的内容进行升序或降序排列;append()方法可以在列表的末尾添加元素,而insert()方法可以在列表的任意位置插入元素;remove()方法可以移除列表中第1个与参数匹配的项,而pop()方法可以删除列表中的元素(默认是最后一个)并返回该元素的值;reverse()方法可以对列表中的内容进行反向排序。

5.元组

元组与列表类似,但也有一些明显的区别。与列表一样,元组也是由值的序列组成,这些值可以是任何类型的数据;与列表不同的是,元组的内容是静态的。元组创建后,既不能更改值的顺序,也不能添加或删除值,当一些列表数据需要固定不变时,元组的这一特性恰好满足要求。创建元组很简单,就是把值放在括号内并用逗号分隔开,如下代码所示。

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

读者可能已经注意到创建元组与创建列表非常相似,区别仅在于元组使用圆括号而列表使用方括号。

与列表类似,元组的索引值从0开始,访问存储在元组中的值的方法与列表相同,代码示例如下。

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

当列表的内容要求是静态时,通常用元组代替列表,因为列表不能保证这一点,而元组可以。

6.字典

字典是Python中第2类集合对象。它类似于列表,所不同的是字典是对象的无序集合。字典通过键而不是偏移量来存储和获取值,字典中的每个键都有一个关联值,如图1-14所示。

图1-14 字典的键/值对

与列表类似,在字典中也可以使用函数来改变字典的长度。下面的代码示例介绍了如何创建字典并为其赋值,以及如何使用键来访问字典中的值。创建字典要使用花括号,花括号内的每个键后面有一个冒号,冒号后是与这个键相关联的值,这些键/值对用逗号分隔开。

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

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

常用的字典操作包括获取字典中元素的数量、使用键获取值、确定键是否存在、将键转换成列表以及获取一系列的值等操作。字典对象可以在适当的位置改变、扩大和收缩,也就是说Python不需要创建一个新的字典对象来保存修改过的字典。给字典中的键赋值可以通过在花括号中声明键并设置它等于某个值来实现。

小技巧: 

与列表不同,字典不能切片,因为它的内容是无序的。如果需要遍历字典中所有的值,可以使用keys()方法,它能返回一个包含字典中所有键的集合,并且可以单独赋值或取值。

类和对象是面向对象编程的基本概念。尽管Python倾向于面向过程的编程,但也支持面向对象的编程。在面向对象编程中,类用于创建对象实例,可以把类视为创建一个或多个对象的模板。每个对象实例具有相同的属性和方法,但对象存储的数据通常是不同的。对象是Python中的复杂数据类型,由属性和方法组成,可以像其他数据类型一样赋值给变量。属性包含与对象相关的数据,而方法是对象可以执行的操作。

下面用一个例子来解释这些概念。在ArcPy中,extent类是通过给出矩形左下角和右上角的地图坐标来指定的矩形。extent类包含一些属性和方法。属性包括XMinXMaxYMinYMaxspatialReference等,其中xy的最大值和最小值属性存储extent矩形的坐标,spatialReference属性存储extent类中spatialReference对象的空间参考系。extent类的对象实例可以通过点记法(.)来设置和获取属性值。这个例子的代码示例如下。

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

脚本运行的结果如下。

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

extent类还提供了一些对象可以执行的方法,大多数方法是extent对象和其他几何图形之间的几何运算,如contains()(包含)、crosses()(相交)、disjoint()(不相交)、equals()(相等)、overlaps()(重叠)、touches()(邻接)和within()(包含于)等。

另一个需要掌握的面向对象的概念是点记法,它是一种访问对象的属性和方法的方式,同时也表示了这些属性或方法属于某一个特定的类。

点记法使用的语法是在对象实例后跟一个点,其后是属性或方法的名称。不管是访问属性还是方法,其语法描述都是一样的,但是,如果是访问方法,方法名后要有一个圆括号,括号内可以没有参数也可以有多个参数,如下列代码所示。

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

Python中的每一行代码称为一条语句。Python有许多不同类型的语句,如有创建变量和给变量赋值的语句、有根据测试结果执行分支代码的条件语句和多次执行代码块的循环语句等。在脚本中编写语句时,需要遵循一定的规则。创建变量和赋值语句在前文中已经介绍过,下面介绍其他类型的语句。

1.条件语句

if/elif/else 语句是 Python 中基本的条件判断语句,用来判断给定条件的True/False值,以决定条件后代码分支的执行情况,即使用条件语句可以控制程序的流程。下面给出一个条件判断的示例:如果变量存储了点要素类,则获取它的XY坐标;如果要素类名称为“Roads”,则获取Name字段。

在Python中,True值是指任何非零数字或非空对象;False值是指零数字或空对象,往往表示不正确。一般地,比较测试的返回值是1或0(真或假),布尔运算的and/or运算的返回值是真或假。

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

Python的代码编写必须遵循一定的语法规则。语句是一条条顺序执行的,直到遇到分支语句,通常使用的分支语句是if/elif/else语句。此外,也可以使用forwhile等循环结构来改变程序流程。Python会自动检测语句和代码块的边界,所以不需要在代码块的边界使用括号或分隔符,而是使用缩进来确定代码块(这一点与C和C#等语言是不同的)。许多编程语言使用分号来结束语句,但Python不是这样。复合语句中需要包含“:”,它的编写规则是:复合语句首行以冒号结束,其后代码块中的语句需要以相同量级逐行缩进在复合语句首行的下方即可。

2.循环语句

循环语句是根据需要可以重复执行的代码行。如果条件表达式的结果为Truewhile循环体就会重复执行,如果条件表达式的结果为FalsePython会跳出循环,执行while循环后的代码。在下面的代码示例中,首先给x变量赋值为10while循环语句判断x的值是否小于100,如果是,则输出x的当前值并且x的值增加10,然后继续判断while后的条件表达式的值。第2次循环时,x的值变为20仍然小于100,所以条件表达式的值仍为True,然后执行输出x值和累加操作,这个过程一直循环,直到x大于或等于100。当x的值不满足x<100的条件时,此时测试结果为False,循环结束。在编写while语句时要特别注意,必须要有跳出循环的条件,否则会陷入死循环。死循环是计算机程序无限次循环执行指定的代码。无论是由于循环不具有终止条件或尽管有终止条件但不能满足,还是由于有导致循环重新开始的条件,都会陷入死循环。

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

for循环是一种可按预定的次数执行代码块的循环方式,它有两种情况:一种是计数循环,可以根据预定次数循环代码块;另一种是序列循环,可以遍历序列中的所有对象。在下面的例子中,序列循环依次执行字典中的每个值后就停止了循环。

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

有时候,需要跳出循环,可以使用break语句或continue语句来实现。break语句跳出最近的封闭循环,即跳出当前的循环代码块;continue语句跳回到当前封闭循环的顶部,根据条件继续执行循环代码块。这两个语句可以在代码块的任何地方出现。

3.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
    print("Additional processing steps")

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

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

try/except/else语句的工作原理如下:当代码执行到try语句时,Python会标记已进入一个try代码块,如果执行try子句时抛出一个异常,程序就会跳转到except语句。如果找到与异常匹配的except语句,就会执行该except子句,此时,try/except/else语句执行完毕,这种情况下不执行else语句。如果没有异常抛出,则try子句中的每个语句都执行,然后代码指针跳到else语句并执行其中的代码,执行完成后跳出整个try代码块,继续执行下一行代码。

try语句的另一种类型是try/finally语句,它可以保证操作的完成。当在try语句中使用finally子句时,不管是否有异常抛出,该子句最后总会执行。

try/finally语句的工作原理如下:如果有异常抛出,Python先执行try子句,然后执行except子句,最后执行finally子句,执行完整个try语句后继续执行后面的代码;如果执行过程中没有异常抛出,则先执行try子句,然后执行finally子句。无论代码是否抛出异常,try/finally语句都可以保证某个操作总会发生。例如,关闭文件或断开数据库连接等清理操作通常放在finally子句中,以确保无论代码是否抛出异常,它们都会被执行。

import arcpy

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

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

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

4.with语句

当有两个相关操作需要作为代码块中的一对操作来执行时,可以使用with语句。with语句常用于打开、读取和关闭文件。打开和关闭文件是一对相关操作,而读取文件和对文件内容进行操作是这对相关操作之间执行的操作。当编写ArcGIS地理处理脚本时,with语句常与ArcGIS 10.1新引入的游标对象一起使用。后面的章节将会详细讲解游标对象,在这里仅作简单介绍。游标是要素类或表的属性表中的记录在内存中的副本。游标操作有3种类型:插入游标可以插入新记录;搜索游标可以对记录建立只读的访问权限;更新游标可以编辑或删除记录。游标对象可以用with语句打开和自动关闭,并能以某种方式进行操作。

with语句可自动关闭文件或游标对象,就像是使用try/finally语句一样,但with语句的代码行更少,这使得编码更加简洁和高效。在下面的代码示例中,演示了使用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]))

5.语句缩进

编写代码时要特别注意语句的缩进,因为它对Python解释代码起着至关重要的作用。Python的复合语句使用缩进来创建代码块,这些复合语句包括if/thenforwhiletrywith语句等。Python解释器会根据缩进来检测代码块。复合语句首行以冒号结尾,之后所有的代码行应缩进相同的距离。可以使用任意数量的空格来定义缩进,但每个代码块应使用相同级别的缩进,通常的做法是用〈Tab〉键来进行缩进。当Python解释器遇到代码行的缩进少于上一行时,就会认为该代码块已结束。下面的代码通过try语句说明了这一概念,try语句后的冒号表明后面的语句是复合语句的一部分,应当缩进,这些语句形成一个代码块。

此外,if语句包含在try语句中,这也是一个首行以冒号结尾的复合语句。因此,if语句中的任何语句都应进一步缩进。可以看到,下面的代码中if语句下有一条语句没有缩进,而是和if语句处于同一水平,这表明statement4try代码块的一部分,而不属于if代码块。

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

JavaScript、Java和.NET等许多语言使用花括号来确定代码块,但Python使用缩进而不是花括号,这是为了减少代码编写量,增强代码的可读性。包含许多花括号的代码往往难以阅读,任何使用过其他语言的人对这一点都应该深有体会。不过,缩进确实需要一些时间来适应。

在日常工作中,读者会经常需要在文件中读取或写入信息。Python有一种内置的对象类型,为多种任务提供了访问文件的方法。这里只介绍部分文件操作的功能,其中包括最常用的功能,如打开和关闭文件,在文件中读取和写入数据等。

Python的open()函数能够创建一个文件对象,它可以作为一个链接打开计算机的本地文件。在文件中读取或写入数据之前,必须调用open()函数。open()函数的第1个参数是要打开文件的路径,第2个参数对应一个模式,通常是读模式(r)、写模式(w)或追加模式(a)等。“r”表示对打开文件进行只读操作;“w”表示对打开文件进行写入操作,打开一个已有的文件进行写入操作时,会覆盖文件中原有的数据,所以必须谨慎使用写模式;追加模式(a)在打开一个文件进行写入操作时,不会覆盖原有的数据,而是在文件的末尾追加新的数据。下面是一个使用open()函数以只读方式打开文本文件的代码示例。

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

注意上述代码示例也使用了with关键字来打开文件,以确保执行完代码后清理文件源。

打开一个文件后,可以使用多种方法读取文件中的数据。最常用的方法是使用readline()方法从文件中一次读取一行数据。readline()函数可以把一次读取的一行数据写入一个字符串变量。可以在Python代码中创建一个循环来逐行读取整个文件。如果要将整个文件读入一个变量,可以使用read()方法,它会读取文件直到遇到文件结束标记(EOF),还可以使用readlines()方法读取文件的全部内容,把每行代码存储为单个字符串,直到遇到EOF。

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

import arcpy, os
try:

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

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

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

与读取文件一样,把数据写入文件的方法也有很多。write()函数是最容易使用的方法,只需要一个字符串参数就可以将其写入文件。writelines()函数可以把列表结构的内容写入文件。在下面的代码示例中,创建了一个名为“fcList”的列表,其中含有一系列的要素类,可以用writelines()方法将这个列表写入文件。

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

本章介绍了Python编程的基本概念,理解这些基本概念才能编写出有效的地理处理脚本。在本章的开头简略介绍了如何在IDLE开发环境下编写和调试Python脚本,讲解了如何创建一个新的脚本、编辑已有的脚本、检查语法错误和运行脚本等。本章还介绍了基本的语言结构,包括导入模块、创建变量并为其赋值、if/else语句、循环语句以及各种数据类型(如字符串、数字、布尔型、列表、字典和对象等)。最后介绍了如何读取和写入文本文件。


本章将介绍以下内容。

ArcPy制图模块提供了自动化的制图功能,包括管理地图文档和图层文件,以及这些文件中的数据。此外,还提供自动导出和打印地图、创建PDF地图册和将地图文档发布成ArcGIS Server地图服务等功能。对于GIS分析人员来说,制图模块在完成诸多日常任务时是非常有用的。

本章将介绍如何使用ArcPy制图模块管理地图文档和图层文件,包括在地图文档文件中添加和移除地理图层和表,将图层插入到数据框中,在地图文档中移动图层,以及更新图层属性和符号系统等。

在ArcGIS Python窗口或自定义的脚本工具中运行地理处理脚本时,经常需要引用当前加载在ArcMap中的地图文档。通常来讲,在对地图文档中的图层和表执行地理处理操作之前,需要引用当前的地图文档。本节将介绍如何在Python地理处理脚本中引用当前的地图文档。

在对地图文档执行任何操作之前,都需要先在Python脚本中引用地图文档,可以通过调用arcpy.mapping模块中的MapDocument()函数来实现。引用地图文档的途径有两种:一是引用ArcMap中当前活动的文档;二是引用磁盘中特定位置的文档。使用CURRENT关键字作为MapDocument()函数的参数,就可以加载ArcMap中当前活动的地图文档,如下列代码所示。

mxd = mapping.MapDocument("CURRENT")

提示: 

只有在ArcGIS的Python窗口或ArcToolbox的自定义脚本工具中运行脚本时,才可以使用CURRENT关键字。如果在IDLE或其他开发环境中运行脚本时使用CURRENT关键字,则无法访问当前加载在ArcGIS中的地图文档。需要指出的是,CURRENT关键字不区分大小写,所以也可以使用“current”。

引用本地或网络驱动器上的地图文档,只需提供地图文档的路径和名称作为MapDocument()函数的参数。例如,要引用C:\data文件夹中的crime.mxd文件,代码为:arcpy.mapping.MapDocument("C:/data/crime.mxd")

下面按步骤介绍如何引用ArcMap中当前活动的地图文档。

(1)在ArcMap中打开C:\ArcpyBook\Ch2\Crime_Ch2.mxd

(2)单击ArcMap“标准”工具条上的“Python”按钮。

(3)在“Python”窗口中键入如下代码,导入arcpy.mapping模块。这里将arcpy.mapping模块赋值给mapping变量,就可以不需要在所有代码中都以arcpy.mapping为前缀,而只需要引用mapping代替arcpy.mapping即可。这不仅使代码更容易阅读,而且减少了代码的编写量。本书后面的小节也使用这种方法。虽然并没有要求一定要使用这种方式,但它确实可以使代码的编写更加简洁高效。此外,可以按个人意愿为这个变量命名,例如命名为MAPmp或其他任何合理的名字。

import arcpy.mapping as mapping

(4)在上一步添加的第一行代码下键入如下代码,可引用当前活动的地图文档(Crime_Ch2.mxd),把该引用赋值给变量。

mxd = mapping.MapDocument("CURRENT")

(5)设置地图文档标题。

mxd.title = "Crime Project"

(6)使用saveACopy()方法保存地图文档文件的副本。

mxd.saveACopy("C:/ArcpyBook/Ch2/crime_copy.mxd")

(7)单击“File | Map Document Properties”,可以查看地图文档的新标题。

(8)可以通过查看C:\ArcpyBook\code\Ch2\ReferenceCurrentMapDocument.py解决方案文件来检查代码。

MapDocument类有创建该类实例的构造函数。在面向对象编程中,实例也叫对象。MapDocument的构造函数既接受CURRENT关键字,也接受本地或网络驱动器上的地图文档文件的路径。首先使用构造函数创建一个对象,并把它赋值给mxd变量。然后可以使用点记法访问该对象的属性和方法。在本例中,使用MapDocument.title属性输出地图文档文件的标题,并使用MapDocument.saveACopy()方法保存地图文档文件的副本。

除了可以引用ArcMap中当前活动的地图文档,还可以使用MapDocument()函数访问存储在本地或网络驱动器上的地图文档文件。本节将介绍如何访问本地或网络驱动器上的地图文档。

正如前文所述,引用存储在本地计算机或共享服务上的地图文档,只需要提供地图文档文件的路径。这种引用地图文档的方法更为通用,因为使用该方法可以在ArcGIS Python窗口以外(IDLE等其他开发环境中)运行脚本。接下来讨论脚本中函数的参数,程序员可以根据需要每次输入一个新的路径作为参数,使用路径参数可使脚本的应用更为广泛。

下面按步骤介绍如何引用存储在本地或网络驱动器上的地图文档。

(1)单击“Start | All Programs | ArcGIS | Python2.7 | IDLE”,打开IDLE开发环境。

(2)在“Python shell”窗口中单击“File | New Window”,新建一个IDLE脚本窗口。

(3)导入arcpy.mapping模块。

import arcpy.mapping as mapping

(4)引用上节中创建的crime地图文档的副本。

mxd =
mapping.MapDocument("C:/ArcpyBook/Ch2/crime_copy.mxd")

(5)输出地图文档标题。

print(mxd.title)

(6)运行脚本,得到如下输出结果。

Crime Project

(7)可以通过查看C:\ArcpyBook\code\Ch2\ReferenceMapDocumentOnDisk.py解决方案文件来检查代码。

本节与上一节的不同之处仅在于,上一节使用CURRENT关键字作为参数来引用地图文档,而本节使用的是地图文档文件存储在本地或网络驱动器上的位置。通常推荐使用第2种方法来引用地图文档,只有当开发者非常确定地理处理脚本在ArcGIS中的Python窗口或自定义脚本工具上运行时,才使用CURRENT关键字。

大多数情况下,获取地图文档中的图层列表是地理处理脚本中的首要工作之一。获取图层列表后,脚本可以循环遍历每个图层并执行某些类型的处理。制图模块中的ListLayers()函数提供获取图层列表的功能。本节将介绍如何获取地图文档中的图层列表。

arcpy.mapping模块包含各种列表函数,使用列表函数可以返回图层、数据框、丢失的数据源、表视图和布局元素等对象的列表。在多步骤的处理过程中,通常先使用列表函数返回Python列表,从返回的列表中获取一项或多项元素来做进一步地处理。每个列表函数可返回一个Python列表,Python列表在第1章中介绍过,它是一种用于存储信息的功能非常强大的数据结构。

在多步骤的处理过程中,第1步通常是用列表函数创建列表。脚本随后的处理过程会迭代访问列表中的一项或多项元素。例如,可以先获取地图文档中的图层列表,然后迭代访问每个图层,找到指定名称的图层后,就可以进行进一步的地理处理。

本节将介绍如何从地图文档中获取图层列表。

下面按步骤介绍如何获取地图文档中的图层列表。

(1)在ArcMap中打开C:\ArcpyBook\Ch2\Crime_Ch2.mxd

(2)单击ArcMap“标准”工具条上的“Python”按钮。

(3)导入arcpy.mapping模块。

import arcpy.mapping as mapping

(4)引用当前活动的地图文档(Crime_Ch2.mxd),把该引用赋值给变量。

mxd = mapping.MapDocument("CURRENT")

(5)调用ListLayers()函数,传入对地图文档的引用作为参数。

layers = mapping.ListLayers(mxd)

(6)使用for循环,输出地图文档中每个图层的名称。

for lyr in layers:
    print(lyr.name)

(7)运行脚本得到如下输出结果(可以通过查看 C:\ArcpyBook\code\Ch2\GetListLayers.py解决方案文件来检查代码)。

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

ListLayers()函数用来检索地图文档、数据框或图层文件中的图层列表。在本节中,把对当前地图文档的引用作为参数传递给ListLayers()函数,该函数检索地图文档中所有图层的列表。检索结果存储在名为layers的变量中,layers变量是一个Python列表,Python列表中包含一个或多个图层对象,可以用for循环进行迭代。

ListLayers()函数是 arcpy.mapping 模块提供的列表函数之一。每种列表函数都返回一个包含某种数据类型的Python列表。例如:ListTableViews()函数返回Table对象列表;ListDataFrames()函数返回 DataFrame 对象列表;ListBookmarks()函数返回地图文档中的书签列表。本书后面的章节会介绍一些其他的列表函数。

上节已经学习了如何使用ListLayers()函数获取图层列表。有时候并不需要地图文档中全部图层的列表,而仅仅需要图层的子集。ListLayers()函数可以限制返回的图层列表。本节将介绍如何使用通配符和在ArcMap的内容列表中指定的数据框来限制返回的图层。

默认情况下,如果只传入对地图文档或图层文件的引用作为参数,ListLayers()函数会返回文件中所有图层的列表。如果使用通配符参数或对指定数据框的引用作为参数,则可以限制返回的图层列表。通配符是一种字符,进行搜索时用来匹配字符或字符序列。本节后述内容将会解释这一概念。

小技巧: 

如果要处理图层文件(.lyr),则不能使用数据框限制图层,因为图层文件不支持数据框。

下面按步骤介绍如何限制地图文档中的图层列表。

(1)在ArcMap中打开C:\ArcpyBook\Ch2\Crime_Ch2.mxd

(2)单击ArcMap“标准”工具条上的“Python”按钮。

(3)导入arcpy.mapping模块。

import arcpy.mapping as mapping

(4)引用当前活动的地图文档(Crime_Ch2.mxd),把该引用赋值给变量。

mxd = mapping.MapDocument("CURRENT")

(5)获取地图文档的数据框列表,搜索名称为Crime的指定数据框(注意,文本字符串用英文单引号或双引号引起来)。

for df in mapping.ListDataFrames(mxd):
  if df.name == 'Crime':

(6)调用ListLayers()函数,传入3个参数,分别为对地图文档的引用(mxd)、限制搜索的通配符(Burg*)和进一步限制搜索的数据框(df)。ListLayers()函数应缩进在上一步写入的if语句下。

layers = mapping.ListLayers(mxd,'Burg*',df)

(7)使用for循环,输出地图文档中每个图层的名称。

for layer in layers:
    print(layer.name)

(8)完整的代码如图2-1所示。也可以查看 C:\ArcpyBook\code\Ch2\Restrict Layers.py解决方案文件。

图2-1 限制图层列表的完整代码

(9)运行脚本,输出结果如下所示。

Burglaries in 2009

ListDataFrames()函数是 arcpy.mapping 模块提供的另一种列表函数,该函数返回地图文档中所有数据框的列表。使用该函数循环遍历每个返回的数据框,查找名为Crime 的数据框。如果找到这个数据框,就调用 ListLayers()函数。该函数的第 2 个参数是值为“Burg*”的通配符参数,通配符参数是可选参数,它的值由任意长度的字符和一个可选字符(*)组成;第3个参数则是对Crime数据框的引用。

在本节中,首先在Crime数据框中搜索名称以“Burg”开头的所有图层,然后输出搜索到的所有与限制条件相匹配的图层。请注意两点:一是本节案例中执行的处理仅仅是输出图层的名称,但是在大多数情况下,需要使用更多的工具或函数来执行其他地理处理;二是简短的列表可以加快脚本运行的速度,也可以使脚本更整齐。

创建选择集是ArcMap中常见的操作,选择集通常由属性查询或空间查询来创建,也可以由用户手动选择要素或其他方式来实现。为了更好地显示选择集,用户经常需要将视图缩放至所选要素的范围。Python有几种方法可以程序化地实现这一功能。本节将介绍如何在数据框和单独的图层中缩放至所选要素。

DataFrame.zoomToSelectedFeatures()方法可以缩放至所有选择要素的范围,这些要素来自数据框的所有图层。在本质上,这个方法执行的操作与在ArcMap的菜单栏上单击“Selection | Zoom to Selected Features”所执行的操作是一样的。其中一个区别是,如果没有选中的要素,DataFrame.zoomToSelectedFeatures()方法会缩放至所有图层的全部范围(相当于全图显示)。

在一个单独图层中缩放至所选要素的范围,需要使用Layer对象。Layer对象包含的getSelectedExtent()方法,可以缩放至所选记录的范围。它同时返回一个Extent对象,该对象可以作为参数传递给DataFrame.panToExtent()方法。

下面按步骤介绍如何获取和设置ArcMap中活动的数据框和活动的视图。

(1)在ArcMap中打开C:\ArcpyBook\Ch2\Crime_Ch2.mxd

(2)查看ArcMap的“Table Of Contents”窗口,确保Crime是活动的数据框。

(3)单击“Table Of Contents”窗口中的“List By Selection”按钮。

(4)单击“Bexar County Boundaries”图层名称右边的“toggle”按钮,如图2-2所示,设置图层为“unselectable”(不可选)状态。

图2-2 “TableOfContents”窗口

(5)单击“Table Of Contents”窗口中的“List By Source”按钮。使用“Select Features”工具,用鼠标光标在Northside ISD区域的边界内拖曳出一个矩形框,矩形框包围一部分盗窃点集,即可选中一个特定学校区域的边界和一些盗窃点,如图2-3所示。

图2-3 选中盗窃点集和区域边界

(6)单击ArcMap“标准”工具条上的“Python”按钮。

(7)导入arcpy.mapping模块。

import arcpy.mapping as mapping

(8)引用当前活动的地图文档(Crime_Ch2.mxd),把该引用赋值给变量。

mxd = mapping.MapDocument("CURRENT")

(9)获取活动的数据框(Crime),缩放至所选要素。

mxd.activeDataFrame.zoomToSelectedFeatures()

(10)如果没有选择要素,调用 zoomToSelectedFeatures()方法会缩放至数据框中所有要素的范围。单击“Selection | Clear Selected Features”,清除所选要素。此时,再执行相同的代码,比较清除操作前后zoomToSelectedFeatures()方法的执行结果。

mxd.activeDataFrame.zoomToSelectedFeatures()

(11)现在即将执行的步骤是缩放至特定图层上所选要素的范围。使用“Select Features”工具,在Northside ISD区域的边界内拖曳出一个矩形框,矩形框包围一部分盗窃点集。

(12)首先,获取对Crime数据框的引用。调用ListDataFrames()函数,传入Crime通配符参数,用来返回一个包含单独项的Python列表。使用[0]取出列表中的第一项元素,也就是这个返回的列表中唯一的一项元素。

df = mapping.ListDataFrames(mxd, "Crime")[0]

(13)其次,获取对Burglaries图层的引用,该图层包含所选要素。下面的代码使用通配符(*)搜索Crime数据框中的“Burglaries in 2009”图层。ListLayers()函数返回一个Python列表,使用[0]取出列表中的第一项元素,即一个名称中包含Burglaries字符的图层。

layer = mapping.ListLayers(mxd,"Burglaries*",df)[0]

(14)最后,通过获取图层中所选要素的范围来设置数据框的范围。

df.extent = layer.getSelectedExtent()

(15)缩放至所选要素的完整代码如下所示,也可以查看C:\ArcpyBook\code\Ch2\ZoomSelectedExtent.py解决方案文件来检查代码。

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

本节介绍了如何缩放至一个数据框的所有图层或特定图层中所选要素的范围。

缩放至一个数据框的所有图层中所选要素的范围,只需要引用当前活动的数据框,并调用zoomToSelectedFeatures()方法即可。

缩放至一个数据框的特定图层中所选要素的范围,需要编写的代码更复杂一些。首先,在导入arcpy.mapping模块后,获取对地图文档和Crime数据框的引用。然后,使用ListLayers()函数,传入对数据框的引用参数和通配符参数,搜索名称以Burglaries开头的图层。ListLayers()函数返回一个Python列表。因为本节使用的数据中只有一个图层符合通配符的搜索条件,所以取出列表中的第一个图层,并将其赋值给layer变量。最后,使用layer.getSelectedExtent()方法设置数据框的范围。

很多时候我们需要改变地图的范围,常见的情况有以下两种:一是在自动生成地图的过程中,二是在需要创建不同区域或要素的地图时。arcpy提供了一些可以改变地图范围的方法,本节将使用定义表达式来改变地图范围。

DataFrame 类的 extent 属性可以用来设置地图的范围,它经常同 Layer.definitionQuery属性一起使用来定义图层的定义查询属性(即定义表达式)。本节将介绍如何使用这些类(DataFrameLayer)与属性(DataFrame.extentLayer.definitionQuery)来改变地图范围。

下面按步骤介绍如何使用定义表达式改变地图范围。

(1)在ArcMap中打开C:\ArcpyBook\Ch2\Crime_Ch2.mxd

(2)单击ArcMap“标准”工具条上的“Python”按钮。

(3)导入arcpy.mapping模块。

import arcpy.mapping as mapping

(4)引用当前活动的地图文档(Crime_Ch2.mxd),把该引用赋值给变量。

mxd = mapping.MapDocument("CURRENT")

(5)创建for循环来遍历地图文档中的所有数据框。

for df in mapping.ListDataFrames(mxd):

(6)查找Crime数据框和该数据框内的指定图层,这个图层将用于定义查询。

if df.name == 'Crime':
  layers = mapping.ListLayers(mxd,'Crime Density by
  School District',df)

(7)创建for循环来遍历图层。尽管layers列表中只有一项元素,但是这里也使用循环来遍历。在for循环中,创建一个定义表达式,并设置新的数据框范围。

for layer in layers:
  query = '"NAME" = \'Lackland ISD\''
  layer.definitionQuery = query
  df.extent = layer.getExtent()

(8)完整的脚本如图2-4所示,也可以查看C:\ArcpyBook\code\Ch2\ChangeMapExtent.py解决方案文件来检查代码。

图2-4 改变地图范围的完整代码

(9)保存并运行脚本。此时数据视图的范围已经更新,因此只显示与定义表达式相匹配的要素,如图2-5所示。

图2-5 更新后的视图范围

本节使用图层的定义查询属性来更新地图范围。首先,在脚本结尾处创建query变量来存放定义表达式,设置定义表达式,查找名为Lackland ISD的学校区域。然后,将query变量存储的字符串赋值给 definitionQuery 属性。最后,设置 df.extent 属性为layer.getExtent()方法返回的值。

在很多情况下都需要把图层添加到地图文档中。制图模块提供了AddLayer()函数来实现这一功能。本节将介绍如何使用AddLayer()函数把图层添加到地图文档中。

arcpy.mapping模块提供了在已有的地图文档中添加图层或图层组的功能。使用ArcMap 的自动排序功能,可以自动将一个图层添加到数据框中并显示出来。这个功能本质上与ArcMap中的“Add Data”按钮实现的功能是一样的,即根据几何类型和图层权重的规则,将图层添加到数据框中的适当位置。

小技巧: 

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

当把图层添加到地图文档中时,该图层必须引用一个已有的图层,即能够在磁盘上的图层文件、同一个地图文档和数据框、同一个地图文档但不相同的数据框或完全不同的地图文档中找到的图层。引用的图层可以是地图文档中的图层,也可以是图层文件(.lyr)中的图层。要将图层添加到地图文档中,首先创建Layer类的实例,然后调用AddLayer()函数,传入新的图层、图层要放置的数据框和图层放置的规则等参数。

下面按步骤介绍如何将图层添加到地图文档中。

(1)在ArcMap中打开C:\ArcpyBook\Ch2\Crime_Ch2.mxd

(2)单击ArcMap“标准”工具条上的“Python”按钮。

(3)导入arcpy.mapping模块。

import arcpy.mapping as mapping

(4)引用当前活动的地图文档(Crime_Ch2.mxd),把该引用赋值给变量。

mxd = mapping.MapDocument("CURRENT")

(5)获取对Crime数据框的引用,它是ListDataFrames()函数返回的数据框列表中的第1个数据框。在代码的末尾指定[0]值,用来获取ListDataFrames()函数返回的数据框列表中的第1个数据框。因为列表的索引是从0开始的,所以需要使用索引值0来检索列表的第1个数据框。

df = mapping.ListDataFrames(mxd)[0]

(6)创建Layer对象,该对象引用一个图层文件(.lyr)。

layer =
mapping.Layer(r"C:\ArcpyBook\data\School_Districts.lyr")

(7)将图层添加到数据框中。

mapping.AddLayer(df,layer,"AUTO_ARRANGE")

(8)可以通过查看C:\ArcpyBook\code\Ch2\AddLayersMapDocument.py解决方案文件来检查代码。运行脚本,School_Districts.lyr文件即可加载在数据框中,如图2-6所示。

图2-6 将“School_Districts”图层添加到地图文档中

首先,导入arcpy.mapping模块,并获取对当前活动地图文档的引用。接着,创建一个新变量df来存储对Crime数据框的引用,该引用是通过ListDataFrames()函数返回数据框列表并使用[0]访问列表中的第1项元素(Crime数据框)来获取的。然后,创建一个 Layer 类的实例 layerlayer 变量引用存储在磁盘上的名为School_Districts. lyr的图层文件。最后,调用AddLayer()函数,传入3个参数:图层要添加到的数据框(df)、引用的图层(layer)和自动排序方式(auto-arrange)。对于第3个可选参数,可以使用AUTO_ARRANGE(默认值)自动地放置图层在数据框中的位置,也可以使用BOTTOMTOP,指定图层放置在数据框或图层组的底层或顶层。

arcpy.mapping模块提供的AddLayerToGroup()函数可以把图层添加到图层组中。使用该函数可以将图层添加到图层组的顶层或底层,也可以使用自动排序方式来放置图层的位置,还可以将图层添加到一个空的图层组中。请读者注意,跟图层对象一样,图层组也不能添加到图层文件中。

图层也可以从数据框或图层组中移出。RemoveLayer()函数用来移除指定数据框中的图层或图层组。如果有两个图层的名字相同,只移除检索到的第1个图层。只有在脚本中设置迭代,才可以将两个图层都移除。

AddLayer()函数可以用来将图层添加到地图文档中,图层添加到数据框中的位置可以使用自动排序方式放置,也可以使用BOTTOMTOP参数将图层置于顶层或底层。但是,AddLayer()函数没有提供把图层插入到数据框中某个指定位置的功能。要实现该功能,可以使用InsertLayer()函数。本节将介绍如何将图层添加到数据框中的指定位置。

AddLayer()函数仅仅提供把图层添加到数据框或图层组中的功能,并且只可以使用自动排序方式自动地放置图层的位置,或者选择放置在顶层或底层。然而,使用InsertLayer()函数可以准确地指定图层添加到数据框或图层组中的位置。InsertLayer()函数使用一个参考图层来指定位置,新图层将会添加在指定参考图层的上方或下方。因为InsertLayer()函数需要使用参考图层,所以不能对空数据框使用该函数。如图2-7所示,“District_Crime_Join”是参考图层,“School_Districts”是将要添加的图层,使用InsertLayer()函数可以把“School_Districts”图层添加到“District_Crime_Join”图层的上方或下方。

图2-7 利用参考图层插入新图层

下面按步骤介绍如何使用InsertLayer()函数把图层插入到数据框中。

(1)在ArcMap中打开C:\ArcpyBook\Ch2\Crime_Ch2.mxd

(2)单击ArcMap“标准”工具条上的“Python”按钮。

(3)导入arcpy.mapping模块。

import arcpy.mapping as mapping

(4)引用当前活动的地图文档(Crime_Ch2.mxd),把该引用赋值给变量。

mxd = mapping.MapDocument("CURRENT")

(5)获取对Crime数据框的引用。

df = mapping.ListDataFrames(mxd, "Crime")[0]

(6)定义参考图层。

refLayer = mapping.ListLayers(mxd, "Burglaries*", df)[0]

(7)定义相对于参考图层的插入图层。

insertLayer =
mapping.Layer(r"C:\ArcpyBook\data\CityOfSanAntonio.gdb\
Crimes2009")

(8)将图层插入到数据框中。

mapping.InsertLayer(df,refLayer,insertLayer,"BEFORE")

(9)可以通过查看 C:\ArcpyBook\code\Ch2\InsertLayerMapDocument.py解决方案文件来检查代码。

(10)运行代码。“Crimes2009”要素类作为一个图层添加到数据框中,如图2-8所示。

图2-8 插入“Crimes2009”图层

首先,导入arcpy.mapping模块,获取对当前的地图文档文件和Crime数据框的引用。接着,定义参考图层,通过调用ListLayers()函数,传入“Burglaries*”通配符参数和Crime数据框参数来限制返回的图层列表,使图层列表中只包含“Burglaries in 2009”图层这一项元素;使用0索引值来检索Python列表中的第1个图层,并把该图层赋值给图层对象(refLayer)。然后,定义插入图层,引用CityOfSanAntonio地理数据库中的“Crimes2009”要素类,将其赋值给新的图层对象(insertLayer)。最后,调用InsertLayer()函数,传入数据框、参考图层、插入图层和BEFORE(表明插入的图层置于参考图层的上方)4个参数。结果如图2-9所示。

图2-9 将图层插入到地图文档中

图层在数据框或图层组中的位置是可以改变的。MoveLayer()函数提供了在数据框或图层组中移动图层位置的功能,但是图层的移动只能在同一个数据框内,而不能把一个数据框中的图层移动到另一个数据框中。同InsertLayer()函数一样,MoveLayer()函数需要引用参考图层来改变图层的位置。

有时候需要改变地图文档中图层的符号系统,可以通过使用UpdateLayer()函数来实现,该函数还可以改变图层的各种属性。本节将介绍如何使用UpdateLayer()函数更新图层的符号系统。

arcpy.mapping模块的UpdateLayer()函数具有更新图层符号系统的功能。例如,可以将图层的符号系统由分级颜色更新为分级符号,如图2-10所示。UpdateLayer()也可以用来更新各种图层属性,但在默认情况下是更新符号系统。因为UpdateLayer()是一个多功能的函数,既能改变符号系统,也能改变其他图层属性,所以读者需要掌握UpdateLayer()函数的各个参数。

图2-10 分级颜色更新为分级符号

下面按步骤介绍如何使用UpdateLayer()函数更新图层的符号系统。

(1)在ArcMap中打开C:\ArcpyBook\Ch2\Crime_Ch2.mxd

(2)单击ArcMap“标准”工具条上的“Python”按钮。

(3)导入arcpy.mapping模块。

import arcpy.mapping as mapping

(4)引用当前活动的地图文档(Crime_Ch2.mxd),把该引用赋值给变量。

mxd = mapping.MapDocument("CURRENT")

(5)获取对Crime数据框的引用。

df = mapping.ListDataFrames(mxd, "Crime")[0]

(6)定义将要更新的图层。

updateLayer = mapping.ListLayers(mxd,"Crime Density by
School District",df)[0]

(7)定义用于更新符号系统的源图层。

sourceLayer =
mapping.Layer(r"C:\ArcpyBook\data\CrimeDensityGradSym.lyr")

(8)调用UpdateLayer()函数来更新符号系统。

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

(9)可以通过查看C:\ArcpyBook\code\Ch2\UpdateLayerSymbology.py解决方案文件来检查代码。

(10)运行脚本。可以发现“Crime Density by School District”图层的符号已由分级颜色变为分级符号,如图2-11所示。

图2-11 分级颜色符号

在本节中,使用UpdateLayer()函数来更新图层的符号系统,但是没有进行属性的更新,更新属性的方法将在下节介绍。UpdateLayer()函数需要传入几个参数,包括数据框、将要更新的图层和源图层。在代码中,updateLayer变量是将要更新的图层,它存储对“Crime Density by School District”图层的引用。sourceLayer变量是源图层,它是包含分级符号的图层文件(CrimeDensityGradSym.lyr),用于更新图层的符号系统。

要更新图层的符号系统,首先必须确保更新图层和源图层有相同的几何图形(点、线、面)。根据渲染器的要求,还需要检查属性定义是否相同。例如,分级颜色和分级符号都基于一个特定的属性。在本节中,两个图层的几何类型均为面要素,且属性表中都含有记录犯罪密度信息的CrimeDens字段。

引用了这两个图层后,就调用UpdateLayer()函数,传入数据框(df)、更新图层(updateLayer)、源图层(sourceLayer)和用来表明仅更新符号系统的参数(True)。第4个参数True值,表明仅更新图层的符号系统,而不更新属性。

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

UpdateLayer()函数也提供移除一个图层并把另一个图层添加到该位置的功能,这两个图层可以完全不相关,因此不需要像定义图层符号系统一样,确保两个图层的几何类型和属性字段是相同的。这一功能在本质上与先调用RemoveLayer()函数再调用AddLayer()函数执行的操作是一样的。设置symbology_only参数的值为False,可以实现该功能。

在上节中,介绍了如何更新图层的符号系统。正如前文所述,UpdateLayer()可以用来更新图层的各种属性,如字段别名、定义查询等。本节将介绍如何使用UpdateLayer()函数来改变图层的各种属性。

UpdateLayer()函数可以用来更新有限数量的图层属性。所有可在“图层属性”对话框中找到的属性都可使用UpdateLayer()函数进行修改,包括字段别名、符号系统、定义查询和标注字段等。一种常见的情况是,有一个图层被添加到多个地图文档中,而GIS分析人员需要在全部地图文档中改变所有该图层实例的某个特定属性。要实现这一功能,需要在ArcMap中修改特定的图层属性并将该图层保存为图层文件,然后把保存的图层文件作为源图层,用来更新update_layer图层的属性。在本节中,首先使用ArcMap改变图层属性,保存图层文件(.lyr),然后使用Python编写脚本,调用UpdateLayer()函数,把保存的图层属性应用到将要更新的图层中。

下面按步骤介绍如何使用UpdateLayer()函数更新图层属性。

(1)在ArcMap中打开C:\ArcpyBook\Ch2\Crime_Ch2.mxd。在本节中,将要使用“Burglaries in 2009”要素类,如图2-12所示。

图2-12 “Burglaries in 2009”要素类

(2)在数据框中双击“Burglaries in 2009”要素类,打开“Layer Properties”窗口,如图2-13所示。每个选项卡表示一个属性,可以在选项卡中设置相应的图层属性参数。

图2-13 “Layer Properties”窗口

(3)单击“General”选项卡,在“Layer Name”文本框中输入文本,更改图层的名称为“Burglaries – No Forced Entry”,如图2-14所示。

图2-14 “General”选项卡

(4)单击“Definition Query”选项卡,设置定义查询,如图2-15所示。可以单击“Query Builder…”按钮构建定义查询,也可以直接键入查询表达式。

图2-15 “Definition Query”选项卡

(5)更改OFFDESC字段的别名为Offense Description,如图2-16所示。

图2-16 “Fields”选项卡

(6)在“Layer Properties”窗口单击“Fields”选项卡,如图2-16所示,已勾选的字段是可见字段,取消勾选可以使相应字段变为不可见状态。

(7)单击“OK”按钮关闭“Layer Properties”窗口。

(8)在数据框中右击“Burglaries – No Forced Entry”图层,选择“Save as Layer File”。

(9)保存文件为C:\ArcpyBook\data\BurglariesNoForcedEntry.lyr

(10)右击“Burglaries – No Forced Entry”图层,选择“Remove”。

(11)在ArcMap中单击“Add Data”按钮,从CityOfSanAntonio地理数据库添加Crimes2009要素类。该要素类将添加到数据框中,如图2-17所示。

图2-17 添加“Crimes2009”要素类

(12)在ArcMap中打开“Python”窗口。

(13)导入arcpy.mapping模块。

import arcpy.mapping as mapping

(14)引用当前活动的地图文档(Crime_Ch2.mxd),把该引用赋值给变量。

mxd = mapping.MapDocument("CURRENT")

(15)获取对Crime数据框的引用。

df = mapping.ListDataFrames(mxd, "Crime")[0]

(16)定义将要更新的图层。

updateLayer = mapping.ListLayers(mxd,"Crimes2009",df)[0]

(17)定义用于更新属性的源图层。

sourceLayer =
mapping.Layer(r"C:\ArcpyBook\data\
BurglariesNoForcedEntry.lyr")

(18)调用UpdateLayer()函数更新符号系统。

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

(19)可以通过查看 C:\ArcpyBook\code\Ch2\UpdateLayerProperties.py解决方案文件来检查代码。

(20)运行脚本。

(21)“Crimes2009”图层中与 BurglariesNoForcedEntry.lyr 文件相关联的属性将进行更新,如图2-18 所示。可以打开图层查看定义查询,还可以打开“Layer Properties”窗口,查看“Crimes2009”要素类已改变的图层属性。

图2-18 更新后的“Crimes2009”图层

本节将介绍如何启用图层的时间属性,然后编写脚本,循环遍历图层的时间范围并导出PDF地图,用来展示以7天为间隔的犯罪数据。

DataFrameTime对象可执行时间管理操作,用来管理数据框中启用时间的图层。DataFrameTime对象是引用DataFrame.time属性返回的结果,它可以检索当前时间(currentTime)、结束时间(endTime)、开始时间(startTime)、时间步长间隔(timeStepInterval)以及其他使用“TimeSliderOptions”对话框建立的属性,然后在地图文档中保存属性。数据框中的图层必须启用了时间属性才能实现这些功能。

下面按步骤介绍如何操作启用时间的图层。

(1)在ArcMap中打开C:\ArcpyBook\Ch2\Crime_Ch2.mxd

(2)在ArcMap的“Table Of Contents”窗口中确保Crime是活动的数据框。

(3)右击“Burglaries in 2009”图层,选择“Properties”,打开“Layer Properties”窗口,选择“Time”选项卡,如图2-19所示。

图2-19 “Time”选项卡

单击勾选“Enable time on this layer”复选框,启用该图层的时间属性。

(4)在“Time properties”下的“Layer Time:”选项中选择“Each feature has a single time field”;在“Time Field:”选项中选择“SPLITDT”字段;在“Time Step Interval:”选项中设置为“7.00 Days”。如图2-20所示。

图2-20 设置时间属性

单击“Calculate”按钮,计算“Layer Time Extent”,如图2-21所示。

图2-21 计算“Layer Time Extent”属性

(5)检查“Time Step Interval:”字段,有可能需要重置为“7Days”。

(6)单击“Apply”,然后单击“OK”。

(7)在ArcMap工具条上,单击“time slider”按钮,打开“Time Slider”窗口,如图2-22所示。在窗口中单击“time slider options”按钮,打开“Time Slider Options”对话框。

图2-22 “time slider”按钮

(8)在“Time Slider Options”对话框的“Time Display”选项卡中,确定“Time step interval”设置为“7.0days”,否则重新设置为“7.0days”。“Time window”选项同样设置为“7.0days”。如图2-23所示。

图2-23 “Time Display”选项卡

(9)单击“OK”。

(10)保存地图文档。必须在地图文档中保存启用时间的数据,否则编写的代码无法执行。

(11)打开“Python”窗口。

(12)导入arcpy.mapping模块。

import arcpy.mapping as mapping

(13)引用当前活动的地图文档(Crime_Ch2.mxd),把该引用赋值给变量。

mxd = mapping.MapDocument("CURRENT")

(14)检索Crime数据框。

df = mapping.ListDataFrames(mxd, "Crime")[0]

(15)生成DataFrameTime对象。

dft = df.time

(16)设置DataFrameTime.currentTime属性为DataFrameTime.startTime属性。

dft.currentTime = dft.startTime

(17)在while循环内,创建一个变量存储PDF文件名称,将地图文档的数据框导出为PDF,输出导出的PDF文件名,重置currentTime属性。while循环体的完整代码如下所示。

while dft.currentTime <= dft.endTime:
        fileName = str(dft.currentTime).split(" ")[0] +
        ".pdf"

        mapping.ExportToPDF(mxd,os.path.join(r"C:\ArcpyBook\Ch2",
        fileName), df)
        print("Exported " + fileName)
        dft.currentTime = dft.currentTime +
dft.timeStepInterval

(18)完整的脚本如图2-24 所示。可以通过查看 C:\ArcpyBook\code\Ch2\TimeEnabledLayers.py解决方案文件来检查代码。

图2-24 操作启用时间的图层的完整代码

DataFrameTime对象可以在数据框中执行时间管理操作。在本节中使用的DataFrameTime属性包括currentTimestartTimeendTimetimeStepInterval等。首先,设置currentTime属性为startTime属性。startTime属性的初始值等于计算出的“Layer Time Extent”属性的起始时间。然后,设置while循环,只要currentTime属性不大于 endTime 属性,则继续循环。在循环体内,创建 fileName 变量存储currentTime属性值与“.pdf”组成的字符串。调用ExportToPDF()函数,传入路径和文件名参数,还可以将布局视图导出为PDF文件。最后,由timeStepInterval属性更新currentTime属性,timeStepInterval属性在属性对话框的“Time Step Interval”属性中设置为“7.0 days”。


相关图书

JavaScript构建Web和ArcGIS Server应用实战
JavaScript构建Web和ArcGIS Server应用实战
ArcGIS 10.1超级学习手册
ArcGIS 10.1超级学习手册
面向ArcGIS的Python脚本编程
面向ArcGIS的Python脚本编程
精通ArcGIS Server 应用与开发
精通ArcGIS Server 应用与开发
ArcGIS Engine  地理信息系统开发从入门到精通(第二版)
ArcGIS Engine 地理信息系统开发从入门到精通(第二版)

相关文章

相关课程