基于ArcGIS数据驱动页面与Python脚本语言的专题图批量出图技术研究
2020-04-27邱世平潘立仁韦建飞
邱世平,潘立仁,韦建飞
(1.崇左市林业勘测设计院,广西 南宁 530001;2.广西南宁林业勘测设计院,广西 南宁 530001)
专题地图作为一种突出反映多种自然要素、人文要素以及社会经济方面等的有效工具,在国土资源、环境规划设计和林业勘测设计中得到广泛应用。然而,一些专题图件的数量较多,需要通过批处理的方式生成,例如一些专题类的地质图、林业中的林班图等[1]。
目前设计生产单位在批量出图中大多通过计算机辅助制图的方式进行。绘图类专业软件有CorelDRAW、Adobe illustrator、CAD等。地理信息系统软件有ArcGIS、MapGIS、QGIS等,拥有强大的符号库、标记库以及丰富的色彩表现功能的绘图类专业软件,图形要素不能很好地与地理信息关联,出图效率以及自动化出图的能力无法与地理信息系统软件相比。
ArcGIS功能非常强大,其根据不同的用户需求提供多种应用场景和服务,是一套完整的、可伸缩的GIS软件。ArcGIS软件中的ArcMap自带的数据驱动页面已基本能实现批处理功能,这种方式能批量生成PDF格式专题图。然而在实际生产需要中大部分的专题图的出图格式需求多样,如JPG、BMP等。另一些研究运用Python脚本语言中Arcpy库对专题图制作方法进行改进,基本实现了整个专题图制图流程的自动化,但这种操作需要建立专题变量库,当制作不同专题图时,需要建立不同的专题变量库,未充分利用ArcGIS中数据驱动页面功能[2-3]。
针对目前专题图批处理存在的问题,本文主要创新点是基于ArcGIS Python语言,根据MXD文档(ArcMap地图文档)模板结合数据驱动页面进行批量出图,提供JPG、PDF等多种格式的专题图的导出,专题图还自带坐标文件便于实际应用的需要。
1 ArcGIS中的Python脚本
从ArcGIS 9.3开始ESRI已在ArcGIS中纳入了Python,使得Python能够用于GIS平台数据分析、转换与管理,也能够快速实现地图的自动化,很大程度上提升了GIS的工作效率,特别是ArcGIS10中加入了ArcPy库,使得其arcgisscripting模块功能相较于先前版本得到更多的加强。ArcPy库能够实现地理处理过程,运用ArcPy站点功能调用其中的地理处理工具、函数以及模块。
采用ArcPy在ArcGIS平台上编写应用程序与脚本,能够共享其他人员开发的大量Python模块。ArcGIS10中引入了全新的Python窗口(图1)来增强内嵌于ArcGIS桌面的Python体验,其作为Python的解释器,替代了先前版本中的命令行窗口,但可便用ArcPy提供的Command函数来执行以前的命令行语法。在ArcGIS平台上的Python窗口,相关的开发人员能够快速地在GIS软件中应用到Python。进而便捷地实现了地理处理工具和功能的交互使用,也使Python模块和库得到充分利用。Python窗口提供了智能感知和代码自动完成功能。
图1 Python窗口代码输入与执行Fig.1 Code input and execution of Python window
2 专题图批处理的实现
2.1 研究方法及技术流程
基于MXD文档(ArcMap地图文档)的Arcpy的专题图批量出图技术流程如下所述。首先遍历文件目录中的MXD文档,然后将每个文件中所包含的图层遍历出来。获取每个图层后,需要先将图层开启显示,然后调用ArcPy库的方法将图层输出成JPG或PDF文件,完成后关闭该图层,最后遍历完毕地图也输出完毕(图2)[6-8]。
图2 批量出图技术流程Fig.2 Technical process of batch mapping
2.2 ArcPy.mapping工具
ArcPy.mapping模块里常用的类有MapDocument、DataFrame、Layer、DataDrivenPages和TextElement。MapDocument类是地图文档(.mxd文件)对应的类。初始化参数是一个字符串,一般是.mxd文件的路径:
mxd=arcpy.mapping.MapDocument(r"F:GeoDataChinaAreaChinaVector.mxd")
DataFrame类用于操作地图内的Data Frame(即下图的Layers),能够控制地图的范围、比例尺等。用ArcPy.mapping.ListDataFrames(map_document,{wildcard})函数获取。
df= arcpy.mapping.ListDataFrames(mxd)[0]
Layer类用于操作具体的图层。能够控制图斑的样式、可见性等[8]。可以用.lyr文件的路径初始化,也可以通过arcpy.mapping.ListLayers(map_document_or_layer,{wildcard},{data_frame})函数获取。
lyr1=arcpy.mapping.Layer(r" F:GeoDataChinaAreaProvince.lyr")
df.addLayer(lyr1)
lyr2=arcpy.mapping.ListLayer(mxd,"",df)[0]
DataDrivenPages类需要配合ArcMap中的Data Driven Pages工具使用。用于一个矢量文件内的全部或部分图斑每个出一张图的情况[9-10]。TextElement类用于操作地图上的文字,比如图名、页数。通过arcpy.mapping.ListLayoutElements(map_document,{element_type},{wildcard})函数获取。
txtElm=arcpy.mapping.ListLayoutElements(mxd,"TEXT_ELEMENT")[0]
常见的出图模式有2种:一个矢量文件里每个图斑出一张图,一个文件夹下每个矢量文件出一张图。
2.3 批量出图
2.3.1代码实现
首先需要制作一个在数据驱动页下设置好索引图层、字段以及比例的MXD文档。借助ArcMap工具的ArcToolBox工具箱,新建一个工具箱。在新建工具箱中添加一个脚本,之后在脚本属性中编写验证代码,脚本的代码设计如下:
1)第一步:在脚本的属性中“验证”栏下def updateParameters(self):函数中,编写遍历MXD文档的核心代码:
#以下代码是遍历MXD文档中的图层列表
qsplyrs=arcpy.mapping.ListLayers(qspmxd)//列出MXD文档的LYR图层
qsplayerList=[]
for qsplyr in qsplyrs://执行循环
qsplayerList.append(qsplyr.name) //列出图层名
uniqueLayerList=list(set(qsplayerList)) //将列出的图层名显示在下拉菜单中
uniqueLayerList.sort()
2)第二步:依次遍历获取索引图层以及索引字段
#以下代码是依次遍历获取索引图层以及索引字段
qspseleLayer=self.params[1].value
qsplayerRef=arcpy.mapping.ListLayers(qspmxd,qspseleLayer)[0]//列出图层
qspfields=arcpy.ListFields(qsplayerRef.dataSource)
qspfieldList=[]
for qspfield in qspfields://执行循环
qspfieldList.append(qspfield.name) //列出字段名
uniqueFieldList=list(set(qspfieldList)) //将列出的图层名显示在下拉菜单中
uniqueFieldList.sort()
3)第三步:获取索引字段后,将索引字段列表于“选择索引字段内容”中
qsprows=arcpy.SearchCursor(qsplayerRef.dataSource)//搜索图层的数据源
qsprow=qsprows.next()//游标移动到下一条记录
qsppageNameList=[]//驱动页名称列表
while qsprow://执行循环选择字段列表的记录
if qsprow.getValue(qspfieldName) not in qsppageNameList:
qsppageNameList.append(qsprow.getValue(qspfieldName))
qsprow=qsprows.next()
qsppageNameList.sort()
4)第四步:依次设置好余下的“选择成果放置文件夹”、“设置照片像素”等参数内容。进入核心代码批量另存为单个MXD文档
for eachPage in pageList://执行循环导出MXD文档
arcpy.AddMessage(str(eachPage)+".mxd")
pageID=ddp.getPageIDFromName(str(eachPage.strip("'")))//逐页名称赋值给pageID
ddp.currentPageID=pageID//设置pageID为当前MXD文档
if tpgs == ‘pdfzh’:
ddp.printPages(printerzh,"CURRENT")
qspmxd.saveACopy(printer+str(eachPage)+".mxd")
elif not(tpgs == ‘pdfzh’):
qspmxd.saveACopy(printer+str(eachPage)+".mxd")//另存一个MXD文档
5)第五步:批量将“选择成果放置文件夹”下的MXD文档导出为JPG或PDF图件
for qspf in os.listdir(path)://遍历文件夹下的MXD文档
if qspf[-3:].lower() ==‘mxd’:
if tpgs ==‘jpg’://当参数选择为JPG时
arcpy.AddMessage(str(qspf)+".jpge")
qspmxd=arcpy.mapping.MapDocument(os.path.join(path,afile))
arcpy.mapping.ExportToJPEG(qspmxd,os.path.join(path,afile[:-3]+‘'jpg’),resolution= qspres)//导出JPG格式图件
if tpgs == ‘pdf’://当参数选择为PDF时
arcpy.AddMessage(str(qspf)+".pdf")
qspmxd=arcpy.mapping.MapDocument(os.path.join(path,qspf))
arcpy.mapping.ExportToPDF(qspmxd,os.path.join(path,qspf[:-3]+‘pdf’),resolution=qspres)//导出PDF格式图件
2.3.2操作流程
在ArcMap布局或数据视图下设置:索引图层和索引字段的数据驱动页设置—保存MXD文档—使用本程序打开MXD文档模板—选择索引图层—选择索引图层出图字段—选择索引字段内容(在字段内容列表中选择批量成图的记录数)—设置成果放置文件夹—设置导出图片像素—设置出图格式—执行程序。制作的工具如图3所示。
3 结果分析与评价
以崇左市群力林场为实例,进行了林场森林分布图专题图的批处理工作(图4)。本文MXD文档结合数据驱动页面方法的优势主要表现在:1)充分利用了ArcGIS数据驱动页面的优势,批量生成具有坐标信息的专题图;2)充分利用了ArcGIS自带的符
图3 批量出图工具展示Fig.3 Display of batch mapping tools
号库、变量库等,不需要制作专门的变量库;3)由图5可见,导出专题图的同时,生成对应的MXD文档,便于个别图幅的灵活修改。总体而言,基于ArcGIS Python语言,根据MXD文档(ArcMap地图文档)模板结合数据驱动页面进行批量出图,提供JPG、PDF等多种格式的专题图的导出,专题图还自带坐标信息便于实际应用的需要。
由表1可以看到,ArcPy结合专题变量库方式与MXD文档结合数据驱动页面对比:1)前者操作相对复杂,需要进行专门使用培训,而后者只需要知道简单的ArcGIS操作便可熟练使用;2)前者需要编写较多的代码,设定专门的符号库、变量库等,后者能充分利用ArcGIS自身功能,简化复杂程度;3)在灵活设计方面,由于前者针对的是某一方面的专题图,当需要制作另外一种模式的专题图时,需要进行代码的大幅修改,而后者进行简单的修改就能适应不同的专题图的需求。
图5 成图目录Fig.5 Mapping catalogue
表1 2种批处理方式的对比
4 结论及讨论
本文主要创新点是基于ArcGIS Python语言,根据MXD文档(ArcMap地图文档)模板结合数据驱动页面进行批量出图。基本过程是首先遍历文件目录中的MXD文档,然后将每个文件中所包含的图层遍历出来。获取每个图层后,需要先将图层开启显示,然后调用ArcPy库的方法将图层输出成JPG或PDF文件,完成后关闭该图层,最后遍历完毕地图也输出完毕。批量出图实现过程中有2种出图模式,即一个矢量文件里每个图斑出一张图,一个文件夹下每个矢量文件出一张图。使用中需要根据实际需要选择合适的出图模式。
本文提出的批量处理方式可以达到节省人力和作业时间的目的。专题地图制作是个繁琐的作业过程。虽然本文通过MXD文档的方式解决原有批量出图的部分问题,该方法的推广将有助于专题制图更灵活的设计和更加的智能化,但完全自动化的批量出图仍需要进一步探索。