ArcGIS软件从诞生之日起就引领着地理信息系统技术的潮流,极大地提高了制图的质量和效率,目前可以满足大多数用户的需求。但是在具有部分行业特色或存在大量重复工作的应用需求中,仅凭ArcGIS软件来完成制图工作不仅费时费力,而且工作量可能超过了可承受范围。因此,通过编程来实现自动化制图技术,则可以起到事半功倍的效果。以林地征占用项目使用林地现状图制图为例,介绍如何使用Python编写代码,利用ArcGIS软件制作脚本工具,实现使用林地现状图的批量输出及脚本工具的共享。
1 Python与arcpy简介
Python语言由Guido van Rossum设计并领导开发,是一种解释类型的编程语言,采用交互式和文件式两种运行方式。Python语言语法简洁、生态丰富、多语言集成,同时支持面向过程和面向对象两种编程方式,具备丰富的第三方库,深受程序员及用户喜爱。
当前,Python有两个不同的版本:Python2和Python3。Python2和Python3采用的编码方式有很大的差异,Python2采用ascii编码,Python3采用unicode编码。ascii是英文编码方式,不包括中文字符;unicode是世界通用编码,包含所有字符。
arcpy可以将ArcGIS和Python紧密的结合起来,在ArcGIS10发布后,Python通过可以arcpy站点包访问地理处理功能。arcpy由各种模块、函数、工具和类组成,arcpy站点包是以arcgisscripting模块为基础,并继承了arcgisscripting功能,进而构建成的站点包。其主要包括数据访问(arcpy.da)、制图模块(arcpy.mapping)、ArcGIS Spatial Analyst extension模块(arcpy.sa)以及ArcGIS Network Analyst extent模块(arcpy.na)。
2 脚本代码编写
2.1 设置编码方式
Python常见的编码方式有3种,分别为ascii编码、unicode编码和cp936(GBK)编码。ascii编码为英文字符编码,由英文字符、数字和特殊字符组成;unicode编码是一种世界通用编码,囊括了世界上所有的符号,包含“utf-8、utf-16、utf-32”以上3种实现方式。cp936是以GBK为基础的一种中文编码方式,支持简体字、繁体字和生僻字。
arcpy站点包基于Python2进行编写,Python2的编码方式采用了ascii编码,而ascii编码并未将中文纳入其中。当用户编写的代码出现中文时,Python2就会抛出SyntaxError错误,不能识别中文。为了让程序能够正常运行,需要在程序的第一行声明编码方式,将编码方式设置为cp936。
2.2导入arcpy站点包和os模块
Python包含“import 模块名、from 模块名 import 函数名、 from模块名 import *”这3种常见的模块导入方式,也可通过as指定别名[5]。用户使用Python脚本批量输出地图时,将用到arcpy站点包中mapping模块,导入模块的方式采用import os、import arcpy.mapping as mapping。将arcpy.mapping模块赋值给mapping变量,可以实现不需要在所有代码中都以arcpy.mapping为前缀,仅需引用mapping代替arcpy.mapping即可,这不仅使代码更容易阅读,而且减少了代码的编写量。
2.3 实现地图输出
arcpy站点包的mapping模块,提供了2个常用的地图输出函数,分别为ExportToPDF()和ExportToJPEG()。两个函数的参数及使用方法都一样,不同之处在于ExportToPDF()输出的是PDF格式文件,而ExportToJPEG()输出的是JPG格式文件。
ExportToPDF()、ExportToJPEG()2个函数包含10个参数[6],以其中常用的3个参数为例进行介绍,包括map_document、out_path、resolution,其中map_document实现对MapDocument对象的引用,out_path实现文件路径和文件名的字符串的输出,resolution实现输出文件分辨率的控制。
Python脚本主要通过遍历地图文档列表,调用地图输出函数,实现地图的批量输出。使用os模块获取文件列表,for循环遍历文件列表,if判断文件是否是地图文档,mxd变量获取地图文档的引用,判断用户提供的输出文件格式参数,调用方法mapping.ExportToPDF()输出地图。
3 制作脚本工具
对于多数用户而言,并不需要了解如何使用Python编写代码,来实现地图的批量输出,只需要知道如何使用ArcGIS脚本工具即可[7]。ArcGIS软件包含800多种可在Python脚本中运行的地理处理工具,我们可以利用ArcGIS软件中添加工具箱的功能,将Python脚本制作成脚本工具,通过在图形界面输入参数来完成地图的批量输出。
ArcGIS脚本工具使用arcpy站点包的GetParameterAsText()函数,通过选择或者输入的方式,设置图层参数[8]。inPath、outPath数据类型设置为文件夹,resolution数据类型设置为长整形,outFormat数据类型设置为字符串型,即可完成脚本工具的制作。
4 结语
Python脚本输出地图耗时短、性能优,在同等时间内,能更好的完成更多的工作。在不考虑计算机性能的情况下,人工输出1幅地图,大约需要耗时60s左右,输出100幅地图,大约耗时600s左右。程序计时是非常常用的功能,Python的time标准库提供系统级精确计时器的计时功能,只需记录程序开始时间和结束时间就能精确的计算出程序运行耗费的时间。经过测试,使用Python脚本输出1幅地图,需要耗时1.43966666857333s,输出100幅地图,需要耗时61.6363333861333s。相较于人工输出,使用计算机脚本输出100幅地图,可以减少538.363666613867s的时间消耗,仅为人工输出耗时的10%。
表1 人工输出地图与Python输出地图耗时对比表 |
||||||
输出数量 |
输出方式 |
耗时 |
差值 |
备注 |
||
1 |
人工 |
Python |
60s |
1.43966666857333s |
58.5603333314267s |
|
50 |
人工 |
Python |
300s |
30.8216667175s |
269.1783332825s |
|
100 |
人工 |
Python |
600s |
61.6363333861333s |
538.363666613867s |
|
ArcGIS脚本工具可共享、可移植,同一个脚本工具可提供给多个用户使用。对于大多数用户,他们并不了解Python,更不会编程,但他们掌握ArcGIS的基本操作,只需向他们提供制作好的脚本工具,他们同样能使用脚本工具,实现自动化办公,减少重复性工作,提高工作效率,从繁琐的重复性工作中解放出来,有更多的时间去完成必须要人工才能完成的工作。
# -*- coding:utf-8 -*-
import arcpy
import os
import shutil
import multiprocessing
import time
import sys
reload(sys)
sys.setdefaultencoding('utf-8')
arcpy.env.overwriteOutput = True
def get_path(in_folder):
map_paths = []
for root, dirs, files in os.walk(in_folder):
for file in files:
if file[-3:].lower() == "mxd":
map_paths.append(os.path.join(root, file))
return map_paths
def batch_export_map(a_mxd, out_folder):
mxd = arcpy.mapping.MapDocument(a_mxd)
pdf_name = os.path.basename(a_mxd).split(".")[0] + ".pdf"
arcpy.mapping.ExportToPDF(mxd, os.path.join(out_folder, pdf_name), resolution=400)
print(u"{0} export success...".format(os.path.basename(a_mxd)[:-4]))
del mxd
if __name__ == "__main__":
XIAN_NAMES = ["A", "B", "C", "D", "E", "F"]
for XIAN_NAME in XIAN_NAMES:
in_folder = u"F:\{}".format(XIAN_NAME)
out_folder = u"F:\{}".format(XIAN_NAME)
if os.path.exists(out_folder):
shutil.rmtree(out_folder)
os.makedirs(out_folder)
pool = multiprocessing.Pool(processes=10)
for a_mxd in get_path(in_folder):
pool.apply_async(batch_export_map, args=(a_mxd, out_folder))
pool.close()
pool.join()
print(u"===={} export success====".format(XIAN_NAME))