ArcPy怎么批量制图?数据驱动模块实操详解(含:源代码)
《ArcPy怎么批量制图?数据驱动模块实操详解(含:源代码)》这篇教程解决一个很常见的 GIS 自动化问题:同一套地图版式,需要按行政区、网格、项目分幅或调查单元批量导出 PDF、PNG 或 JPG,手动切换范围和保存文件既慢又容易出错。
本文以 ArcMap 中的 ArcPy 数据驱动页面为主线,演示如何用 arcpy.mapping 调用 Data Driven Pages 批量制图。最后也会说明 ArcGIS Pro 中对应的 Map Series 思路,避免把 ArcMap 脚本直接搬到 ArcGIS Pro 后报错。

引言:ArcPy批量制图适合解决什么问题
ArcPy批量制图最适合处理“版式固定、范围不同、内容按区域切换”的地图生产任务。例如每个县导出一张专题图、每个调查网格导出一张巡查图、每个工程分区导出一张施工底图。
如果你已经在 ArcMap 中做好一个标准 MXD 地图模板,只是需要按照索引图层一页一页导出,那么使用 数据驱动页面加 ArcPy 脚本,比人工操作更稳定,也更容易复用。
本文使用的典型环境如下:
- 软件:ArcMap 10.x
- Python:ArcGIS Desktop 自带 Python 2.7
- 核心模块:
arcpy.mapping - 核心对象:
MapDocument、DataDrivenPages - 输入文件:已配置数据驱动页面的 MXD 模板
- 输出结果:按行政区名称或编号命名的 PDF、PNG、JPG 地图文件
背景:为什么要用数据驱动页面做ArcPy批量制图
在实际项目中,很多地图不是只出一张,而是几十张、几百张甚至上千张。人工制图通常会遇到这些问题:
- 每次手动缩放到目标区域,范围不一致。
- 手动修改标题、图名、编号,容易漏改。
- 导出文件命名不统一,后期整理困难。
- 地图模板更新后,需要重新导出全部成果。
- 同一项目多人操作,制图标准不一致。
ArcMap 的数据驱动页面可以把一个索引图层中的每一个要素变成一页地图。ArcPy 再负责循环这些页面并导出文件,这就是常见的 ArcPy数据驱动页面批量导出工作流。
一个标准批量制图任务通常包含三类数据:
- 索引图层:控制每张图的地图范围,例如行政区面、标准分幅网格、项目区块。
- 业务图层:真正需要展示的专题数据,例如土地利用、管线、影像、监测点。
- 版式元素:标题、图例、比例尺、指北针、制图日期、制图单位等。
原理:ArcPy数据驱动模块如何控制每一页地图
数据驱动页面的核心逻辑很简单:索引图层有多少个要素,就可以生成多少个页面。每个页面对应索引图层中的一个要素,地图框会根据该要素的范围自动定位。
在 ArcPy 中,常用对象关系如下:
arcpy.mapping.MapDocument:打开 MXD 地图文档。mxd.dataDrivenPages:访问 MXD 中已经配置好的数据驱动页面。ddp.pageCount:获取总页数。ddp.currentPageID:设置当前页面。ddp.pageRow:读取当前页面对应索引要素的属性。arcpy.mapping.ExportToPDF:将当前版式导出为 PDF。arcpy.mapping.ExportToPNG:将当前版式导出为 PNG。
需要注意,ArcPy 并不是凭空生成地图。它依赖你在 ArcMap 中提前配置好的 MXD 模板。脚本只负责自动翻页、读取属性、替换文本、导出文件。
实务建议:先在 ArcMap 中手工检查 2 到 3 页效果,确认范围、图名、图例和标注都正确,再运行 ArcPy 批量导出。不要一开始就直接导出几百张。
步骤:ArcPy怎么批量制图的完整操作流程
步骤一:准备索引图层
索引图层是 ArcPy批量制图的基础。它可以是行政区面、图幅网格、缓冲区面或任意面要素图层。每一个要素通常对应一张输出地图。
索引图层建议至少包含以下字段:
| 字段名 | 用途 | 示例 |
|---|---|---|
NAME |
地图标题或区域名称 | 西湖区 |
CODE |
输出文件编号 | 330106 |
SCALE |
可选,用于控制制图比例尺 | 10000 |
PAGE_NO |
页码或排序字段 | 001 |
字段命名尽量使用英文、数字和下划线,避免中文字段名导致脚本编码问题。输出文件名也建议使用编号加名称的形式,例如 330106_西湖区.pdf。
步骤二:在 ArcMap 中配置数据驱动页面
打开 ArcMap,加载业务图层和索引图层,然后进入数据驱动页面配置。典型设置如下:
- 打开 MXD 模板文件。
- 确认地图处于 Layout View 版式视图。
- 启用 Data Driven Pages。
- 选择索引图层作为 Index Layer。
- 选择名称字段,例如
NAME。 - 选择排序字段,例如
PAGE_NO或CODE。 - 设置地图范围、边距和比例尺策略。
- 翻页检查每一页是否能够正确定位。
这一步非常关键。ArcPy数据驱动页面批量导出时,如果 MXD 中没有启用 Data Driven Pages,脚本会无法获得有效的 dataDrivenPages 对象。
步骤三:设置动态文本和版式元素
批量制图不只是导出不同范围,还常常需要自动修改标题、页码或行政区名称。ArcMap 可以通过数据驱动页面动态文本实现一部分需求,也可以通过 ArcPy 修改文本元素。
推荐做法是给需要脚本控制的文本元素设置明确名称。例如:
- 地图标题文本元素名称:
txt_title - 制图日期文本元素名称:
txt_date - 区域编号文本元素名称:
txt_code
在 ArcMap 中右键文本元素,打开属性,设置元素名称。这样 ArcPy 可以通过 ListLayoutElements 找到它并修改内容。
步骤四:编写ArcPy批量导出PDF源代码
下面是一个完整的 ArcPy批量制图 PDF 导出脚本。请根据你的本地路径和字段名修改参数。
# -*- coding: utf-8 -*-
import arcpy
import os
import datetime
# 输入 MXD 模板路径
mxd_path = r"D:GISProjectBatchMaptemplate.mxd"
# 输出目录
out_dir = r"D:GISProjectBatchMapoutput_pdf"
# 当前制图日期
map_date = datetime.datetime.now().strftime("%Y-%m-%d")
if not os.path.exists(out_dir):
os.makedirs(out_dir)
# 打开地图文档
mxd = arcpy.mapping.MapDocument(mxd_path)
# 获取数据驱动页面对象
ddp = mxd.dataDrivenPages
# 检查是否启用数据驱动页面
if ddp is None:
raise Exception("当前 MXD 未启用 Data Driven Pages,请先在 ArcMap 中配置数据驱动页面。")
# 获取版式文本元素
title_elements = arcpy.mapping.ListLayoutElements(mxd, "TEXT_ELEMENT", "txt_title")
date_elements = arcpy.mapping.ListLayoutElements(mxd, "TEXT_ELEMENT", "txt_date")
code_elements = arcpy.mapping.ListLayoutElements(mxd, "TEXT_ELEMENT", "txt_code")
# 循环导出每一页
for page_id in range(1, ddp.pageCount + 1):
ddp.currentPageID = page_id
# 当前页面对应的索引要素属性
row = ddp.pageRow
# 根据索引图层字段读取名称和编号
name = row.getValue("NAME")
code = row.getValue("CODE")
# 处理空值
if name is None:
name = "未命名"
if code is None:
code = str(page_id)
# 更新版式文本
if len(title_elements) > 0:
title_elements[0].text = u"{}专题图".format(name)
if len(date_elements) > 0:
date_elements[0].text = u"制图日期:{}".format(map_date)
if len(code_elements) > 0:
code_elements[0].text = u"区域编号:{}".format(code)
# 清理文件名中的非法字符
safe_name = unicode(name).replace("/", "_").replace("", "_").replace(":", "_")
safe_code = unicode(code).replace("/", "_").replace("", "_").replace(":", "_")
out_pdf = os.path.join(out_dir, u"{}_{}.pdf".format(safe_code, safe_name))
# 导出当前页面
arcpy.mapping.ExportToPDF(
mxd,
out_pdf,
resolution=300,
image_quality="BEST",
colorspace="RGB",
compress_vectors=True,
image_compression="ADAPTIVE"
)
arcpy.AddMessage(u"已导出:{}".format(out_pdf))
print(u"已导出:{}".format(out_pdf))
# 清理对象
del mxd
print(u"全部地图导出完成。")
这段代码的重点有三个:
- 通过
ddp.currentPageID控制当前导出的页面。 - 通过
ddp.pageRow读取当前索引要素属性。 - 通过
ExportToPDF将当前版式输出为独立 PDF。
步骤五:导出PNG或JPG图片
如果项目需要上传到系统、插入报告或用于 Web 预览,可以把 PDF 导出改为 PNG 或 JPG。下面是 PNG 导出的核心代码。
out_png = os.path.join(out_dir, u"{}_{}.png".format(safe_code, safe_name))
arcpy.mapping.ExportToPNG(
mxd,
out_png,
resolution=200,
color_mode="24-BIT_TRUE_COLOR",
background_color="255,255,255",
transparent_color=None
)
如果地图包含较多线划、注记和矢量边界,PDF 更适合归档和打印;如果只是预览或嵌入系统页面,PNG 通常更方便。
步骤六:按字段控制比例尺
有些区域面积差异很大,统一比例尺会导致小区域过空、大区域显示不全。可以在索引图层中增加 SCALE 字段,然后在循环中设置数据框比例尺。
df = arcpy.mapping.ListDataFrames(mxd)[0]
scale_value = row.getValue("SCALE")
if scale_value not in [None, 0, ""]:
df.scale = float(scale_value)
如果你使用数据驱动页面自带的范围和边距控制,就不一定需要脚本设置比例尺。两种方式不要混用得太复杂,否则排查范围问题会比较困难。
常见坑:ArcPy批量制图最容易出错的地方
1. MXD没有启用数据驱动页面
很多脚本报错不是代码问题,而是 MXD 模板没有正确启用 Data Driven Pages。请先在 ArcMap 中手动翻页,如果不能翻页,ArcPy 也无法批量导出。
2. 字段名写错或字段为空
脚本中的 NAME、CODE、SCALE 必须和索引图层字段完全一致。字段名大小写、下划线、中文字段都可能引发问题。
建议先用下面代码查看当前页面有哪些字段:
fields = arcpy.ListFields(ddp.indexLayer)
for f in fields:
print(f.name)
3. 中文路径和中文文件名导致编码问题
ArcMap 的 Python 环境是 Python 2.7,中文路径、中文文件名、中文字段值更容易遇到编码问题。建议项目路径尽量使用英文,例如 D:GISProjectBatchMap。
如果必须使用中文名称,脚本文件顶部应保留:
# -*- coding: utf-8 -*-
同时尽量使用 unicode 字符串处理输出文件名。
4. 输出文件名包含非法字符
行政区名称、项目名称中可能包含 /、、:、* 等字符,这些字符不能直接作为 Windows 文件名。批量导出前必须清理。
5. 图例、标注或比例尺在部分页面失控
批量制图时,某些页面可能因为要素过密、标注过多、范围过小导致版式拥挤。建议抽查以下页面:
- 面积最大的索引要素。
- 面积最小的索引要素。
- 业务要素数量最多的区域。
- 名称最长的区域。
- 边界形状最复杂的区域。
6. 在ArcGIS Pro中运行ArcMap脚本
arcpy.mapping 是 ArcMap 的制图模块。ArcGIS Pro 使用的是 arcpy.mp,对应对象也从 Data Driven Pages 变成了 Map Series。两者不能直接混用。
方法比较:ArcMap数据驱动页面、ArcGIS Pro Map Series和纯脚本制图
| 方法 | 适用场景 | 优点 | 限制 |
|---|---|---|---|
| ArcMap Data Driven Pages + arcpy.mapping | 已有 ArcMap MXD 模板,需要批量导出地图 | 成熟稳定,适合老项目和存量 MXD | 依赖 ArcMap,Python 2.7,和 ArcGIS Pro 不兼容 |
| ArcGIS Pro Map Series + arcpy.mp | 使用 ArcGIS Pro APRX 项目制图 | 适合新项目,布局和符号能力更现代 | 脚本写法与 ArcMap 不同,需要重写 |
| 纯 ArcPy 控制范围和导出 | 不使用数据驱动页面,只按要素范围循环导出 | 自由度高,可完全控制范围、图层和文本 | 代码量更大,版式维护成本更高 |
| QGIS Atlas + PyQGIS | 开源 GIS 环境下批量制图 | 无需 ArcGIS 授权,适合开源工作流 | 与 ArcPy 脚本不通用,需要学习 PyQGIS |
如果你的项目已经使用 ArcMap,并且 MXD 模板已经做好,优先选择 ArcPy数据驱动页面批量导出。如果是新项目,尤其是团队已经迁移到 ArcGIS Pro,则建议直接使用 Map Series 和 arcpy.mp。
检查清单:运行ArcPy批量制图前必须确认
- MXD 可以正常打开,所有图层数据源没有红色感叹号。
- 已经启用 Data Driven Pages,并且可以在 ArcMap 中手动翻页。
- 索引图层是面图层,每个要素对应一张地图。
- 索引图层中存在脚本要读取的
NAME、CODE等字段。 - 字段值没有大量空值,输出文件名不会重复。
- 输出目录存在,或脚本有权限创建目录。
- 文本元素名称与脚本中的
txt_title、txt_date、txt_code一致。 - 已抽查最大区域、最小区域、要素最多区域的版式效果。
- 脚本运行环境是 ArcMap 自带 Python,而不是普通 Python 或 ArcGIS Pro Python。
- 正式导出前先测试 3 到 5 页,确认文件名、范围、清晰度和图面内容都正确。
FAQ:ArcPy怎么批量制图常见问题
Q1:ArcPy批量制图一定要先配置数据驱动页面吗?
不一定。但如果你的任务是按索引图层一页一页导出地图,先配置数据驱动页面是最省事的做法。否则需要用脚本自己控制数据框范围、比例尺、文本和导出逻辑,代码会更复杂。
Q2:为什么脚本提示没有 dataDrivenPages?
通常是 MXD 没有启用 Data Driven Pages,或者脚本打开的不是你配置好的那个 MXD。请在 ArcMap 中打开同一个 MXD,确认数据驱动页面工具条可以正常翻页。
Q3:ArcPy数据驱动页面批量导出时如何按行政区名称命名?
可以通过 ddp.pageRow 读取索引图层的行政区名称字段,例如 NAME,再拼接到输出文件路径中。注意清理文件名中的非法字符,并避免不同区域名称重复。
Q4:批量导出的 PDF 为什么有些页面范围不合适?
常见原因包括索引要素形状差异过大、数据驱动页面边距设置不合理、比例尺被脚本固定、索引图层几何错误。建议先在 ArcMap 中手动翻到问题页面,确认是模板设置问题还是脚本设置问题。
Q5:ArcGIS Pro 能运行本文的 arcpy.mapping 脚本吗?
不能直接运行。ArcGIS Pro 使用 arcpy.mp,批量制图对应的是 Map Series。ArcMap 的 arcpy.mapping.MapDocument、mxd.dataDrivenPages 不能直接用于 ArcGIS Pro 的 APRX 项目。
Q6:批量导出图片时分辨率应该设置多少?
用于打印或归档的地图,PDF 通常设置 300 dpi。用于网页预览或系统上传的 PNG,可以根据页面大小设置 150 到 200 dpi。分辨率越高,文件越大,导出时间也越长。
Q7:ArcPy批量制图能不能同时导出PDF和PNG?
可以。在同一个循环中分别调用 ExportToPDF 和 ExportToPNG 即可。但如果页数很多,建议先导出一种格式并检查结果,再批量导出另一种格式,避免一次运行时间过长。
结论:用模板化思路稳定完成ArcPy批量制图
ArcPy批量制图的关键不是把脚本写得多复杂,而是先把 MXD 模板、索引图层、数据驱动页面和版式元素设计清楚。模板稳定,脚本只需要负责翻页、读字段、改文本和导出文件。
对于 ArcMap 项目,推荐采用 Data Driven Pages + arcpy.mapping 的组合完成批量制图;对于 ArcGIS Pro 新项目,则应使用 Map Series + arcpy.mp。无论选择哪种方法,正式导出前都要先抽查典型页面,确认范围、标注、图例和文件命名没有问题。
按照本文流程,你可以把人工重复导出的地图生产任务,整理成可复用的 ArcPy批量制图脚本。后续只要更新数据或模板,就能快速重新生成整套地图成果。