ArcPy批量制图怎么做?GIS自动化脚本详解(附:源码)
很多同学在做项目图集、专题图、监测报告附图时,都会遇到同一个问题:ArcPy批量制图怎么做?GIS自动化脚本详解(附:源码)。如果每一张图都手动打开 ArcGIS Pro、修改图层筛选条件、调整标题、导出 PDF 或 PNG,不仅耗时,而且很容易出现漏图、标题错误、比例尺不一致等问题。本文用一个可复用的 ArcPy 批量制图脚本,讲清楚从数据准备、地图模板、参数控制到批量导出的完整流程。
引言:ArcPy批量制图适合解决什么问题
ArcPy批量制图适合处理“版式相同、范围或属性不同、需要重复导出”的地图生产任务。典型场景包括行政区专题图批量出图、地块红线图批量导出、巡查点位分区制图、管线分段图册、遥感解译成果分幅出图等。
本文使用 ArcGIS Pro 的 arcpy.mp 模块进行演示。arcpy.mp 是 ArcGIS Pro 中用于操作工程文件、地图、图层、布局和导出结果的 ArcPy 模块。相比手动制图,它的优势在于:一次配置模板,多次自动替换范围、标题、图层筛选条件和输出文件名。
本文重点不是讲所有 ArcPy API,而是给你一套可以改造的批量制图脚本思路:先做好地图模板,再用字段驱动循环导出。

背景:为什么手工制图容易出错
在 GIS 项目中,批量地图通常具有相同的版式结构:图名、图例、比例尺、指北针、底图、专题图层基本一致,区别只在于某个行政区、某个地块、某个编号或某个时间批次。
如果使用手工方式制作 50 张、100 张甚至更多地图,常见问题包括:
- 地图范围不一致,有的图过大,有的图裁切不完整。
- 标题或编号手动修改出错,例如 A 区图名写成 B 区。
- 图层筛选条件忘记更新,导致导出内容不对应。
- 导出格式、分辨率、文件命名不统一。
- 后期数据更新后,需要重新逐张制图,维护成本很高。
ArcPy自动化制图的核心价值就是把这些重复操作脚本化。你只需要维护一个 ArcGIS Pro 工程模板和一张控制字段表,后续批量导出地图即可交给 Python 脚本完成。
原理:ArcPy批量制图的核心逻辑
ArcPy批量制图通常由四个部分组成:工程模板、数据字段、布局元素和导出参数。
1. 工程模板
工程模板一般是一个已经配置好的 ArcGIS Pro 工程文件,也就是 .aprx 文件。模板中需要提前设置好地图、图层样式、布局、图例、比例尺、指北针和文本框。
脚本不建议从零开始创建所有制图元素。更稳定的做法是:人工先完成一张标准图,然后让 ArcPy 只负责批量替换范围、属性过滤、标题和输出路径。
2. 数据字段
批量制图通常需要一个唯一字段作为循环依据。例如行政区名称字段 NAME、地块编号字段 PARCEL_ID、图幅编号字段 SHEET_NO。脚本会逐个读取字段值,并为每个值导出一张地图。
3. 图层定义查询
定义查询是 ArcGIS 中用于筛选图层要素的 SQL 条件。例如:
NAME = '东城区'
在 ArcPy 中,可以通过修改图层的 definitionQuery 属性,让当前地图只显示某个行政区或某个地块。这就是实现 ArcPy按属性批量出图的关键。
4. 地图框范围
布局中的地图框,也就是 Map Frame,决定最终导出的可视范围。脚本可以根据当前要素的几何范围设置地图框 extent,并适当放大一点边界,避免图形贴边。
步骤:ArcPy批量制图完整操作流程
步骤一:准备数据和字段
假设我们有一个行政区面图层,字段如下:
| 字段名 | 含义 | 示例 |
|---|---|---|
| NAME | 行政区名称,用于标题和筛选 | 东城区 |
| CODE | 行政区代码,用于文件命名 | 110101 |
| TYPE | 区域类型,可选 | 街道 |
建议在正式写脚本前,先检查以下内容:
- 字段值是否唯一,避免一个名称对应多个区域却只想导出一张图。
- 字段中是否有空值,空值会影响标题和文件名生成。
- 字段值是否包含斜杠、冒号、星号等不能用于文件名的字符。
- 数据坐标系是否正确,避免地图范围定位异常。
步骤二:制作 ArcGIS Pro 地图模板
打开 ArcGIS Pro,新建工程并完成一张标准地图。建议按以下方式整理:
- 地图名称设置为 Main Map。
- 布局名称设置为 Batch Layout。
- 地图框名称设置为 Main Map Frame。
- 需要批量筛选的图层名称设置为 行政区边界。
- 标题文本框名称设置为 Title Text。
这些名称非常重要,因为脚本会根据名称查找对象。如果名称写错,脚本通常不会直接制图失败,但会出现找不到图层、找不到布局元素的问题。
步骤三:设置输出目录
建议单独建立一个输出文件夹,例如:
D:GISProjectbatch_mapsoutput
不要把输出文件直接放在工程根目录或数据目录中。批量导出时文件数量较多,单独目录更方便检查和归档。
步骤四:编写 ArcPy 批量导出地图源码
下面是一份可改造的 ArcPy 批量制图脚本。它会读取行政区边界图层的字段值,按每个行政区设置定义查询,自动缩放到当前区域,更新标题,并导出 PNG 图片。
import arcpy
import os
import re
# 1. 参数配置
aprx_path = r"D:GISProjectbatch_mapstemplate.aprx"
output_folder = r"D:GISProjectbatch_mapsoutput"
map_name = "Main Map"
layout_name = "Batch Layout"
map_frame_name = "Main Map Frame"
target_layer_name = "行政区边界"
title_element_name = "Title Text"
name_field = "NAME"
code_field = "CODE"
export_dpi = 300
buffer_ratio = 1.15
# 2. 文件名清洗函数
def safe_filename(text):
text = str(text)
text = re.sub(r'[/:*?"<>|]', "_", text)
text = text.strip()
return text if text else "unknown"
# 3. 打开 ArcGIS Pro 工程
aprx = arcpy.mp.ArcGISProject(aprx_path)
maps = aprx.listMaps(map_name)
if not maps:
raise RuntimeError(f"找不到地图:{map_name}")
m = maps[0]
layouts = aprx.listLayouts(layout_name)
if not layouts:
raise RuntimeError(f"找不到布局:{layout_name}")
layout = layouts[0]
map_frames = layout.listElements("MAPFRAME_ELEMENT", map_frame_name)
if not map_frames:
raise RuntimeError(f"找不到地图框:{map_frame_name}")
mf = map_frames[0]
title_elements = layout.listElements("TEXT_ELEMENT", title_element_name)
if not title_elements:
raise RuntimeError(f"找不到标题文本框:{title_element_name}")
title_element = title_elements[0]
target_layers = m.listLayers(target_layer_name)
if not target_layers:
raise RuntimeError(f"找不到图层:{target_layer_name}")
target_layer = target_layers[0]
# 4. 确保输出目录存在
os.makedirs(output_folder, exist_ok=True)
# 5. 读取唯一值并循环出图
fields = [name_field, code_field]
with arcpy.da.SearchCursor(target_layer, fields) as cursor:
for row in cursor:
name_value = row[0]
code_value = row[1]
if name_value is None:
print("跳过空名称记录")
continue
# 注意:字符串字段需要加单引号
where_clause = f"{arcpy.AddFieldDelimiters(target_layer, name_field)} = '{name_value}'"
target_layer.definitionQuery = where_clause
# 根据筛选后的图层获取范围
extent = mf.getLayerExtent(target_layer, False, True)
if extent is None:
print(f"未获取到范围,跳过:{name_value}")
continue
# 适当放大范围,避免图形贴边
width = extent.XMax - extent.XMin
height = extent.YMax - extent.YMin
x_center = (extent.XMin + extent.XMax) / 2
y_center = (extent.YMin + extent.YMax) / 2
new_width = width * buffer_ratio
new_height = height * buffer_ratio
new_extent = arcpy.Extent(
x_center - new_width / 2,
y_center - new_height / 2,
x_center + new_width / 2,
y_center + new_height / 2
)
mf.camera.setExtent(new_extent)
# 更新标题
title_element.text = f"{name_value}专题图"
# 输出文件名
output_name = f"{safe_filename(code_value)}_{safe_filename(name_value)}_专题图.png"
output_path = os.path.join(output_folder, output_name)
# 导出PNG
layout.exportToPNG(output_path, resolution=export_dpi)
print(f"已导出:{output_path}")
# 6. 清除定义查询
target_layer.definitionQuery = ""
# 7. 可选:保存工程副本,保留最后一次制图状态
# aprx.saveACopy(r"D:GISProjectbatch_mapstemplate_result.aprx")
print("批量制图完成。")
步骤五:运行脚本
运行脚本前,建议使用 ArcGIS Pro 自带的 Python 环境。常见方式有三种:
- 在 ArcGIS Pro 的 Python 窗口中测试核心代码。
- 使用 ArcGIS Pro 安装目录中的 Python 命令行运行 .py 文件。
- 在 PyCharm 或 VS Code 中配置 ArcGIS Pro 的 Python 解释器后运行。
如果你是初学者,建议先在 ArcGIS Pro 中打开模板工程,确认图层、布局和地图框名称无误,再运行脚本。这样更容易定位错误。
步骤六:检查导出结果
ArcPy批量导出地图完成后,不要只看文件数量,还要抽查地图内容。至少检查以下项目:
- 输出文件数量是否等于预期行政区数量。
- 每张图的标题是否和地图内容一致。
- 范围是否完整,边界是否被裁切。
- 图例、比例尺、指北针是否正常显示。
- 中文文件名是否正常,是否出现乱码或非法字符。
常见坑:ArcPy自动化制图容易失败的地方
1. 图层名称和脚本名称不一致
ArcPy 查找图层通常依赖名称。如果 ArcGIS Pro 中图层叫“行政区”,脚本中写的是“行政区边界”,就会报错或找不到对象。建议在模板工程中统一命名,并避免使用多个同名图层。
2. 字符串字段没有正确加引号
定义查询中,文本字段需要使用单引号,例如:
NAME = '东城区'
数值字段则不需要单引号,例如:
OBJECTID = 1
如果字段类型判断错误,ArcPy按属性批量出图时会出现查询为空、范围获取失败等问题。
3. 字段值中包含单引号
如果行政区名称或项目名称中包含英文单引号,SQL 条件可能出错。实际项目中应尽量避免在关键字段中使用特殊符号,或者在脚本中增加转义处理。
4. 地图范围过小或贴边
直接使用要素范围时,图形可能紧贴图框边缘。本文脚本使用 buffer_ratio 参数对范围进行放大。一般可以从 1.10 到 1.30 之间调整,具体取决于版式和图面留白要求。
5. 输出文件被占用
如果导出的 PNG 或 PDF 正在被图片查看器、PDF 阅读器或其他程序打开,脚本再次导出同名文件时可能失败。批量运行前建议关闭输出目录中的旧文件。
6. 布局元素没有命名
很多人只修改了文本框内容,却没有修改元素名称。ArcPy 的 listElements 查找的是元素名称,不一定是你看到的文字内容。请在 ArcGIS Pro 的布局元素属性中确认名称。
方法比较:ArcPy批量制图、地图系列和手工导出怎么选
| 方法 | 适合场景 | 优点 | 限制 |
|---|---|---|---|
| 手工导出 | 少量地图、一次性任务 | 上手简单,所见即所得 | 效率低,容易出错,不适合大量重复制图 |
| ArcGIS Pro 地图系列 | 按索引图层批量出图 | 无需大量代码,适合标准图册 | 复杂动态文本、复杂筛选和多数据源联动时不够灵活 |
| ArcPy批量制图 | 需要脚本控制范围、标题、图层、输出格式和文件名 | 灵活、可复用、适合自动化生产 | 需要理解 ArcPy、模板工程和字段规则 |
如果你的任务只是按一个索引图层导出标准图册,可以优先考虑 ArcGIS Pro 的地图系列功能。如果你需要同时控制多个图层筛选条件、标题字段、输出命名、分辨率、格式,或者要和数据处理流程连在一起,ArcPy批量制图更合适。
检查清单:运行ArcPy批量制图前请逐项确认
- ArcGIS Pro 工程文件 .aprx 可以正常打开。
- 地图名称、布局名称、地图框名称和脚本中完全一致。
- 目标图层名称唯一,没有多个同名图层。
- 用于循环的字段存在,且字段值不为空。
- 用于文件命名的字段不包含非法字符,或脚本已做清洗。
- 图层坐标系正确,范围可以正常缩放。
- 输出目录存在,且当前用户有写入权限。
- 导出格式、DPI 和页面尺寸符合项目要求。
- 先用 2 到 3 条记录测试,再全量批量运行。
- 批量完成后抽查标题、范围、图例和输出文件数量。
FAQ:ArcPy批量制图常见问题
Q1:ArcPy批量制图必须使用 ArcGIS Pro 吗?
本文脚本使用的是 ArcGIS Pro 的 arcpy.mp 模块,因此需要 ArcGIS Pro 环境。ArcMap 时代也有 arcpy.mapping,但接口和工程文件体系不同,不建议直接混用。
Q2:可以把 PNG 改成 PDF 吗?
可以。把导出语句替换为 PDF 导出即可。例如:
layout.exportToPDF(output_path, resolution=300)
同时把输出文件名后缀从 .png 改为 .pdf。对于正式报告或图册,PDF 通常更适合;对于网页展示或快速预览,PNG 更方便。
Q3:如何一次导出多个图层组合?
可以在循环中同时修改多个图层的 definitionQuery,或者控制图层 visible 属性。例如地块图层按 PARCEL_ID 筛选,影像解译图层按 BATCH_ID 筛选。关键是保证字段之间有明确对应关系。
Q4:为什么脚本能运行,但导出的图是空白的?
常见原因有三个:定义查询没有匹配到要素、地图框范围没有定位到目标图层、目标图层不可见。建议先打印 where_clause,再在 ArcGIS Pro 中手动测试该查询条件是否有结果。
Q5:ArcPy批量导出地图时可以自动修改比例尺吗?
可以。除了使用 extent 控制范围,也可以直接设置地图框相机比例尺。例如:
mf.camera.scale = 50000
如果项目要求所有地图使用统一比例尺,可以采用固定 scale;如果区域大小差异很大,使用 extent 自动适配通常更合理。
Q6:批量制图脚本需要每次都打开 ArcGIS Pro 界面吗?
不一定。只要 Python 环境正确、许可可用、路径配置正确,可以直接运行 .py 文件。但调试模板元素、检查布局和验证符号化时,仍建议在 ArcGIS Pro 界面中先做好模板。
结论:用模板加脚本,让GIS制图从重复劳动变成自动流程
ArcPy批量制图的关键不是把所有制图工作都写成代码,而是把“固定的版式”交给 ArcGIS Pro 模板,把“重复变化的部分”交给 ArcPy 脚本。这样既能保留人工制图的版面质量,又能提高批量导出的效率和一致性。
实际项目中,你可以从本文源码开始改造:先替换 .aprx 路径、图层名称、字段名称和输出目录,再用少量记录测试,确认范围、标题和文件名都正确后,再进行全量导出。只要模板和字段规则稳定,ArcPy自动化制图就可以成为 GIS 项目中非常可靠的生产工具。