第四章 查找和修复数据源 ||| 第六章 使用脚本执行地理处理工具
我们将在本章介绍以下案例:
- 创建页面布局元素列表
- 为页面布局元素赋唯一名称
- 调用ListLayoutElements()函数限制返回的页面布局元素
- 更新页面布局元素属性
- 获取可用的打印机列表
- 调用PrintMap()函数打印地图
- 将地图导出为PDF文件
- 将地图导出为图片文件
- 调用PDFDocumentCreate()和PDFDocumentOpen()函数创建地图册
引言
ArcGIS10推出的arcpy.mapping
模块提供了许多与自动化地图生产相关的功能。
arcpy.mapping
模块可用于自动化地图生产,创建地图册,导出为图像或PDF文件以及创建并管理PDF文件。在本章中,你将会学习如何使用arcpy.mapping
模块来实现多个与地图生产和打印有关的地理处理任务。
创建页面布局元素列表
在地理处理脚本中,自动化地图生产的第一步通常是生成一个页面布局元素的列表。举个例子,你可能想在地图打印或创建PDF文件之前修改地图的标题。在本案例中,标题内容保存在一个文本元素中(text element)。你可以先生成一个地图页面视图中的文本元素列表然后再修改地图标题,其中第一步就是生成文本元素列表。
Getting ready
ArcMap中有两种视图形式,分别为数据视图(data view)和页面视图(layout view)。数据视图是在不考虑任何特定页面大小或布局的情况下浏览地理数据和属性数据,分析数据,符号化图层以及管理数据。页面视图如同将地图打印在纸张上面,通过增加地图元素用来创建产品级别的地图。这些地图元素包括地图图框,图层,图例,标题,指北针,比例尺以及标题栏。页面布局中的每一个对象都作为arcpy.mapping
中的一个页面布局元素类。这些页面布局元素类的示例见下图:
我们可以为每一个元素赋唯一的元素名称,这样就可以在程序中访问这些元素。名称是在ArcMap中定义的。arcpy.mapping
模块提供了一个ListLayoutElements()
函数来返回包含所有页面布局元素的列表。在本案例中,你将学习如何使用ListLayoutElements()
函数来生成页面布局元素列表。
How to do it...
按照以下步骤学习如何生成页面布局元素列表:
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
How it works...
ListLayoutElements()
函数以多种页面布局类的形式返回到页面布局元素列表。元素可以是以下对象实例:GraphicElement,LegendElement,PictureElement,TextElement
或者是MapSourroundElement
。每一个元素都可以赋唯一名称。不要求为每一个元素赋予名称,不过这在通过脚本来访问这些元素的时候就会很有用。在脚本中,我们在输出元素名称前先确认元素是否被赋了名称。这样处理的原因在于ArcMap并不要求页面布局要素一定要赋一个名称。
为页面布局元素赋予唯一名称
在ArcMap中给所有的页面布局元素赋唯一名称是一个良好的习惯。这在地理处理脚本需要对某一元素进行修改的时候就会很重要。比如,你可能需要更新公司logo的图标。不需要人工来更新所有的地图文档文件,你只需要编写一个地理处理脚本通过程序的方式让所有地图文档文件中使用新的图标。不过要实现这一想法,你就需要为页面布局元素赋予唯一名称。这样你就可以访问单个页面布局元素了。
Getting ready
正如我前一个案例中提过到的,每个页面布局元素隶属于某种页面元素类并且都可以赋一个名称。元素名称可以在Python脚本中用于引用某个特定元素。你可以在ArcMap中为每个页面布局元素赋予唯一名称。在本案例中,你会使用ArcMap来为页面布局元素赋名称。
How to do it...
按照以下步骤来学习如何在ArcMap中给页面布局元素赋名称:
1.在ArcMap中打开C:\ArcpyBook\Ch5\Crime_Ch5.mxd
文件。
2.切换至页面视图,你将看到如下图类似的界面:
3.根据元素类型不同元素名称的赋予方式也不同。点击最上方的数据框Crime。如下图所示会出现选择句柄:
4.右键单击Crime
数据框选择属性(Properties)弹出数据框属性(Data Frame Properties)对话框,如下图所示。名称****(Name)属性定义了该元素名称。在本案例中,该元素名称为Crime
:
5.关闭数据框属性(Data Frame Properties)对话框。
6.在页面视图下选择2009 Crime Legend,右键单击该元素选择属性(Properties)弹出属性窗口。
7.设置图例的元素名称不同于数据框。点击大小和位置(Size and Position)选项卡。
8.元素名称(Element Name)文本框则是用来设置该页面元素的名称。如下图所示,修改为2009 Crime Legend
:
9.你还可以定义文本元素名称。选择标题元素(Crime and Its Impact on School Test Performance
),右键单击该元素选择属性(Properties)。
10.如下图所示,点击大小和位置(Size and Position)选项卡来定义该元素名称:
How it works...
页面视图中的每一个元素都可以赋一个名称,该名称可以在地理处理脚本中用于访问指定元素。你应该尽量为每个元素定义一个名称。尽管并一定去为每一个元素定义一个唯一的元素名称,甚至还可以为所有元素赋予一个名称,不过如果你想通过Python脚本来访问这些页面元素的话,最好的做法就是给每个页面元素赋名称并确保每一个元素名称都是唯一的。你还应尽量保证元素名称仅包含字母和下划线。
There's more...
你可以在ListLayoutElements()
函数中使用页面元素名称作为通配符参数来限制该函数返回的页面布局元素。在下一个案例中,你将学习如何使用通配符和元素类型参数来限制返回的页面布局元素列表中的内容。
调用ListLayoutElements()函数限制返回的页面布局元素
页面布局中会包含大量的页面布局元素,对于某个特定的地处理脚本而言,许多页面元素不需要的。ListLayoutElements()
函数通过两个参数来限制返回的页面布局元素。第一个参数用来定义需要返回的元素类型,第二个参数使用通配符来查找要返回的元素。
Getting ready
页面布局元素包含了图形(graphic),图例(legend),图片(picture),文本(text)以及数据框(data frame)等多种元素类型。当需要返回页面布局元素列表时,你可以限制返回的元素类型。在本案例中,你将编写脚本通过元素类型和通配符参数来筛选返回的页面布局元素。
How to do it...
按照以下步骤学习如何通过定义返回的元素类型和通配符来限制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
How it works...
ListLayoutElements()
是一个非常灵活的函数,该函数最基本用法是用来返回地图文档页面视图中所有页面布局元素的列表。不过该函数还提供了两个可选参数用来筛选返回的列表内容。第一个是元素类型筛选器用来指定想要返回的页面布局元素类型。你还是可以提供一个通配符来筛选返回的列表内容。两个筛选器可以一起使用。比如,在本案例中我们指定仅返回元素名称包含“Crime”
的LEGEND_ELEMENT
对象。函数返回了仅包含一个页面布局元素的列表。
ListLayoutElements()
函数可使用以下元素类型筛选关键字参数:DATAFRAME_ELEMENT,GRAPHIC_ELEMENT,LEGEND_ELEMENT,MAPSURROUND_ELEMENT,PICTURE_ELEMENT,TEXT_ELEMENT
更新页面布局元素属性
每一个页面布局元素的属性都可以通过程序来修改。比如,LegendElement
对象允许更改图例在页面中的位置,更改图例标题以及获取图例项等属性。
Getting ready
页面布局元素的类型包括图形,图例,文本,地图以及图片等。每一个页面布局元素都对应了arcpy.mapping
包中的一个类。你可以利用这些类提供的不同属性在程序中来更改元素。
DataFrame
类提供了访问地图文档中数据框属性的功能。该对象可使用地图单位也可以使用页面布局单位。比如像位置和大小等这类的页面布局属性可以通过elementPositionX,elementPositionY,elementWidth,elementHeight
属性来设置。
GraphicElement
类是一个更为通用的元素类型,像插入表,图,轮廓线,标记,线以及多边形等图形都可以添加到页面布局中。如果你想通过Python脚本来访问每一个图形元素的话,你需要为每一个图形元素设置name
属性(其他的页面布局元素同理)。
LegendElement
提供调整图例位置和修改图例标题的功能,同时也提供访问图例项以及关联的父数据框的功能。LegendElement
对象仅与单个数据框有关联。
MapsurroundElement
包括指北针,图示比例尺以及文本比例尺,与LegendElement
一样也是与单个数据框有关联。该对象包含的属性可以用于重新调整其在页面布局中的位置。
PictureElement
指页面布局中的栅格或图片。该对象最常用的属性是获取并设置数据源,当你需要在多个地图文档中更新某个图片(比如说logo)的时候就会相当有帮助。比如,你可以编写脚本遍历所有的地图文档文件将当前的图片替换为新的logo图片。你还可以重新定位或缩放对象。
TextElement
是指页面布局中的文本信息,包括插入的文本,注释,文本框以及标题等,但不包括图例标题以及插入图表中的文本。该对象提供的属性可用于修改文本字符串内容,这在需要在页面布局多个位置或多个地图文档中修改相同文本字符串的时候会极为有用。当然,该对象也支持重新定位文本的功能。
页面布局中的返回的每一个元素都是某类元素对象的一个实例。在本案例中,我们将通过程序使用Legend
对象中的title
属性来更改Crime
图例的标题并获取图例项所引用的图层对象列表。
How to do it...
按照以下步骤来学习如何更新某个页面布局元素的属性:
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,"LENEND_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.更新后的结果如下图所示:
How it works...
每个页面布局元素均提供了一组属性和方法。在该案例中,我们使用了Legend
对象的title
属性。该对象的其他属性可以用于设置元素的宽度和高度,位置以及其他属性。Legend
对象提供的方法可以用于调整图例显示的列数,列出元素项以及移除和更新元素项等。
获取可用打印机列表
ListPrinterNames()
函数是arcpy
提供的另一个列表函数,该函数用于生成一个当前可用的打印机列表。跟我们之前介绍的其他列表函数一样,ListPrinterNames()
函数通常是作为多步骤流程脚本中开始步骤。
Getting ready
在调用PrintMap()
函数打印地图之前,通常的做法是先调用ListPrinterNames()
函数,该函数将会返回本地计算机上可用的打印机列表。某个特定的打印机可通过迭代返回的打印机列表来查找并作为PrintMap()
函数的输入参数。
How to do it..
按照以下步骤来学习如何在脚本中调用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 printName in mapping.ListPrinterNames():
print printName
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
How it works...
ListPrinterNames()
函数返回的列表中包含了当前所有可用的打印机。之后你可以调用PrintMap()
函数将打印任务提交给计算机中的某一个打印机,这部分内容将会在下一个案例中介绍。
调用PrintMap()函数打印地图
使用PrintMap()
函数将地图文档布局发送给打印机很容易实现。默认情况下打印任务将会发送到随地图文档保存的默认打印机,不过你可以指定打印任务要发送的打印机。
Getting ready
arcpy.mapping
模块提供的PrintMap()
函数用于打印ArcMap中的地图文档布局或数据框。调用该函数之前,通常的步骤是先调用ListPrinterNames()
函数。某个特定的打印机可通过迭代返回的打印机列表来查找并作为PrintMap()
函数的输入参数。
PrintMap()
函数用于打印某特定数据框或地图文档布局。默认情况下,该函数会使用随地图文档保存的默认打印机,如果地图文档中未提供默认打印机则使用系统默认打印机。正如之前所提到的,你还可以使用ListPrinterNames()
函数获取可用的打印机列表,然后选择其中一个打印机作为PrintMap()
函数的输入参数。在本案例中,你将学习如何时候调用PrintMap()
函数来打印地图文档页面布局。
How to do it...
按照以下步骤来学习如何调用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)
How it works...
PrintMap()
函数接受一个必选参数和几个可选参数。必选参数是地图文档的引用。第一个可选参数是打印机名称。在本案例中,我们没有指定要使用的打印机。由于没有指定打印机,函数将使用随地图文档保存的打印机或在地图文档未提供打印机的情况下使用系统默认打印机。第二个可选参数是我们希望打印的数据框,在本案例中该参数是Test_Performance
数据框。其他的可选参数是输出的打印文件以及图像质量,这些并未在案例中涉及。
将地图导出为PDF文件
你可能只想将地图或页面视图创建成可共享的PDF文件,而不是发送到打印机打印。Arcpy
中的制图模块提供的ExportToPDF()
函数可以完成此任务。
Getting ready
PDF是非常流行的跨平台查看和打印的文件交换格式。arcpy
的制图模块中的ExportToPDF()
函数可将数据框或地图页面布局导出为PDF格式文件。默认情况下ExportToPDF()
会导出地图页面布局,不过你可以传递一个可选参数来指定要导出的特定的数据框。在本案例中,你将学习如何将地图页面布局和数据框导出为PDF文件。
How to do it...
按照以下步骤来学习如何将地图导出为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文件。
How it works...
ExportToPDF()
函数接受两个必选参数,包括一个地图文档文件的引用参数以及输出的PDF文件参数。我们编写的第一个脚本中,函数接受了地图文档引用参数和输出的PDF文件参数。我们并没有传递用来指定输出的数据框的可选参数,因此ExportToPDF()
函数会输出地图页面布局。该函数还接受许多可选参数,包括一个指定的数据框参数以及许多与输出内容和输出文件的质量有关的参数。我们编写的第二个脚本就指定了要导出的数据框参数。你可以参考ArcGIS帮助页面来获取每一个可选参数的详细信息。
将地图导出为图片文件
我们还可以使用arcpy.mapping
模块提供的众多函数将地图内容或页面视图导出为图片文件。图片导出函数会根据所要创建的图片文件类型不同而在函数名称有所区别,不过函数接受的参数几乎没什么区别。
Getting ready
arcpy.mapping
模块除了提供了将数据框和地图页面布局导出为PDF文件的功能外,还提供了许多可用于将地图内容导出为图片文件的函数。支持导出的图片格式包括AI,BMP,EMF,EPS,GIF,JPEG,SVG以及TIFF。每个函数接受的参数取决于所创建的图片类型。这些函数中就包括ExportToJPEG(),ExportToGIF()
以及ExportToBMP()
等。在本案例中,你将学习如何将地图导出为图片文件。
How to do it...
按照以下步骤来学习如何将地图文档中的数据或页面视图导出为图片文件:
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.ExportToJPEG(mxd,r"C:\ArcpyBook\Ch5\DataFrameCrime2.jpg",df,world_file=True)
8.运行脚本。我们会看到一个DataFrameCrime2.jpw
新文件。用文本编辑器打开该文件,将看到如下内容:
470.520239851286190
0.000000000000000
0.000000000000000
-496.256971063348490
1972178.761771137800000
13815440.387677660000000
How it works...
你会注意到ExportToJPEG()
函数与ExportToPDF()
函数看起来很像。需要注意的一点是所有的导出函数在可选参数是有区别的。每一个ExportTo<Type>
函数会根据创建的文件类型的不同而接受的参数也不同。
调用PDFDocumentCreate()和PDFDocumentOpen()函数创建地图册
对于GIS专业人员来讲,创建地图册与他人共享是很普遍的事情。地图册可以简单理解为针对某一特定区域的地图集,通常还会包含一个索引图。考虑到PDF作为常用的交换格式,地图册通常为PDF格式文件。
Getting ready
除了可将地图导出为PDF文件,你还可以管理现有PDF文件或创建新的PDF文件。你可以合并页面,设置文档打开方式,添加文件附件以及创建或更改文档安全性设置。PDFDocumentOpen()
函数用于打开一个现有PDF文件来进行管理操作。PDFDocumentCreate()
函数则会创建一个新的PDF文件。这些函数经常用来创建地图册,本案例中我们就学习如何创建地图册。
How to do it...
1.打开IDLE,创建一个新的脚本窗口。
2.导入arcpy.mapping
和os
模块:
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页面到刚创建的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\CrimeBook.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\CrimeBook.pdf
。该地图册会包含我们在前面的案例中生成两个的PDF文件的内容。
How it works...
PDFDocumentCreate()
函数接受文件路径和文件名参数创建一个新的PDF文件。该PDF文件在你向其中插入或添加其他PDF页面或调用PDFDocument.saveAndClose()
方法前并不会真在在磁盘中创建。appendPages()
和insertPages()
方法分别用于向PDF文件中增加页面或插入页面。
PDFDocumentOpen()
函数接受一个PDF地址参数并返回一个PDFDocument
类的实例。文档打开后,你就可以修改PDF文件属性,向文档中添加或插入文件或添加文件附件。执行完所有操作后需调用PDFDocument.saveAndClose()
方法来保存这些修改。
There's more...
通过PDFDocument
对象可以设置许多PDF文件属性,包括页面数量,附件,标题,作者,摘要,关键字,打开方式以及页面布局等。你还可以调用
PDFDocument.updateDocSecurity()
设置密码,加密和安全性限制等机制来更改文档的安全性设置。