ArcPy怎么批量制图?数据驱动模块实操详解(含:源代码)

GIS基础理论
Dr.GIS
wowwwai GIS研习社 · 工具流程与项目排障

《ArcPy怎么批量制图?数据驱动模块实操详解(含:源代码)》这篇教程解决一个很常见的 GIS 自动化问题:同一套地图版式,需要按行政区、网格、项目分幅或调查单元批量导出 PDF、PNG 或 JPG,手动切换范围和保存文件既慢又容易出错。

本文以 ArcMap 中的 ArcPy 数据驱动页面为主线,演示如何用 arcpy.mapping 调用 Data Driven Pages 批量制图。最后也会说明 ArcGIS Pro 中对应的 Map Series 思路,避免把 ArcMap 脚本直接搬到 ArcGIS Pro 后报错。

ArcPy批量制图 数据驱动页面批量导出流程示意图
ArcPy 批量制图的核心流程:准备 MXD 模板、配置数据驱动页面、用脚本循环导出每一页地图。

引言:ArcPy批量制图适合解决什么问题

ArcPy批量制图最适合处理“版式固定、范围不同、内容按区域切换”的地图生产任务。例如每个县导出一张专题图、每个调查网格导出一张巡查图、每个工程分区导出一张施工底图。

如果你已经在 ArcMap 中做好一个标准 MXD 地图模板,只是需要按照索引图层一页一页导出,那么使用 数据驱动页面加 ArcPy 脚本,比人工操作更稳定,也更容易复用。

本文使用的典型环境如下:

  • 软件:ArcMap 10.x
  • Python:ArcGIS Desktop 自带 Python 2.7
  • 核心模块:arcpy.mapping
  • 核心对象:MapDocumentDataDrivenPages
  • 输入文件:已配置数据驱动页面的 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,加载业务图层和索引图层,然后进入数据驱动页面配置。典型设置如下:

  1. 打开 MXD 模板文件。
  2. 确认地图处于 Layout View 版式视图。
  3. 启用 Data Driven Pages。
  4. 选择索引图层作为 Index Layer。
  5. 选择名称字段,例如 NAME
  6. 选择排序字段,例如 PAGE_NOCODE
  7. 设置地图范围、边距和比例尺策略。
  8. 翻页检查每一页是否能够正确定位。

这一步非常关键。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. 字段名写错或字段为空

脚本中的 NAMECODESCALE 必须和索引图层字段完全一致。字段名大小写、下划线、中文字段都可能引发问题。

建议先用下面代码查看当前页面有哪些字段:

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 中手动翻页。
  • 索引图层是面图层,每个要素对应一张地图。
  • 索引图层中存在脚本要读取的 NAMECODE 等字段。
  • 字段值没有大量空值,输出文件名不会重复。
  • 输出目录存在,或脚本有权限创建目录。
  • 文本元素名称与脚本中的 txt_titletxt_datetxt_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.MapDocumentmxd.dataDrivenPages 不能直接用于 ArcGIS Pro 的 APRX 项目。

Q6:批量导出图片时分辨率应该设置多少?

用于打印或归档的地图,PDF 通常设置 300 dpi。用于网页预览或系统上传的 PNG,可以根据页面大小设置 150 到 200 dpi。分辨率越高,文件越大,导出时间也越长。

Q7:ArcPy批量制图能不能同时导出PDF和PNG?

可以。在同一个循环中分别调用 ExportToPDFExportToPNG 即可。但如果页数很多,建议先导出一种格式并检查结果,再批量导出另一种格式,避免一次运行时间过长。

结论:用模板化思路稳定完成ArcPy批量制图

ArcPy批量制图的关键不是把脚本写得多复杂,而是先把 MXD 模板、索引图层、数据驱动页面和版式元素设计清楚。模板稳定,脚本只需要负责翻页、读字段、改文本和导出文件。

对于 ArcMap 项目,推荐采用 Data Driven Pages + arcpy.mapping 的组合完成批量制图;对于 ArcGIS Pro 新项目,则应使用 Map Series + arcpy.mp。无论选择哪种方法,正式导出前都要先抽查典型页面,确认范围、标注、图例和文件命名没有问题。

按照本文流程,你可以把人工重复导出的地图生产任务,整理成可复用的 ArcPy批量制图脚本。后续只要更新数据或模板,就能快速重新生成整套地图成果。