ArcPy批量出图:arcpy.mp导出PDF和批量制图
做县区图册、乡镇专题图、巡查成果图或项目汇报图时,ArcPy批量出图可以把几十到几百张地图从手动导出变成可复现流程。真正稳定的做法不是让脚本从零画一张图,而是在 ArcGIS Pro 中先做好 APRX 模板、布局、图层样式和地图系列,再用 arcpy.mp 控制范围、文字、图层和 PDF 导出。
本文围绕一个常见场景展开:已经有行政区边界、专题数据和 ArcGIS Pro 版式模板,需要按区县或项目单元批量生成 PDF。我们会讲清楚 arcpy.mp 导出 PDF 的对象关系、批量导出多个 Layout 的写法、Map Series 按页输出的写法,以及脚本失败时应该先查哪些地方。
问题背景:为什么 ArcPy批量出图比手动导出稳定
手动导出地图最容易出错的地方不是“点错按钮”,而是每张图的范围、比例尺、标题、图层显隐、图例、输出分辨率和文件名必须保持一致。图件数量一多,人很难保证每次操作完全相同。某一页忘记改标题,某一页缩放比例不同,某一页 PDF 没嵌入字体,最后都会变成返工。
ArcPy批量出图适合解决这种重复性制图问题:同一套版式、同一套符号系统、同一类输出格式,只是每张图的空间范围、标题文字、查询条件或页码不同。脚本把这些变量整理成循环,输出结果就更容易检查、复跑和归档。
但要注意,ArcPy 不是排版设计软件。它更适合驱动已经设计好的 ArcGIS Pro 项目。也就是说,图框、指北针、比例尺、图例、动态文本、专题样式、页面尺寸和地图系列,最好先在 ArcGIS Pro 里调好,再交给脚本批量执行。
核心原理:PDF 导出依赖 APRX、Layout 和 Map Series
arcpy.mp 是 ArcGIS Pro 中用于地图自动化的 ArcPy 子模块。它的入口通常是 arcpy.mp.ArcGISProject,也就是一个 .aprx 工程。工程里可以包含多个 Map、多个 Layout、图层、表、样式和地图系列。脚本通过这些对象找到需要操作的布局,再导出 PDF。
批量 PDF 输出的核心对象关系可以这样理解:
- ArcGISProject:代表一个 ArcGIS Pro 工程,是脚本访问地图、布局和工程属性的入口。
- Map:代表地图内容,包括图层、表、坐标系和图层顺序。
- Layout:代表一张页面版式,包含地图框、标题、图例、比例尺、图片和文字元素。
- MapFrame:Layout 中承载地图的地图框,可以控制显示范围和比例尺。
- Map Series:地图系列,用索引图层驱动分页,适合行政区图册、分幅图和项目单元图册。
- ExportFormat:导出格式对象,例如 PDF、PNG、JPEG、TIFF,用来设置输出路径、分辨率、字体和图层属性。
如果使用较新的 ArcGIS Pro 环境,建议优先使用 arcpy.mp.CreateExportFormat("PDF") 创建 PDF 格式对象,再调用 layout.export(pdf) 或 mapSeries.export(pdf)。很多旧教程会写 exportToPDF,它在旧脚本中仍常见,但新项目更适合按当前 arcpy.mp 的 export 方法组织代码。
批量制图的关键不是把所有排版动作都写进 Python,而是让 ArcGIS Pro 模板负责版式,ArcPy 脚本负责批量替换变量和导出。
ArcPy批量出图准备:模板工程、图层和版式命名
开始写脚本前,先把 ArcGIS Pro 工程整理成可被脚本稳定引用的状态。很多导出失败并不是代码复杂,而是模板工程里对象名称混乱、图层数据源断开、布局元素没有命名,导致脚本找不到正确对象。
- 保存一个专用 APRX 模板。不要直接在生产工程上反复试脚本,可以另存为
atlas_template.aprx,先保证手动打开时每张图都能正常显示。 - 给 Layout 起唯一名称。例如
A3_乡镇专题图、A4_项目位置图。不要让多个布局同名,也不要依赖列表顺序猜测第几个布局。 - 给 MapFrame 和文本元素命名。例如地图框叫
主地图框,标题文本叫图名,日期文本叫制图日期。脚本会用这些名称定位元素。 - 检查图层数据源。所有图层都应能在当前机器上访问,路径、数据库连接和网络盘权限要提前确认。
- 固定输出规格。页面尺寸、方向、比例尺规则、分辨率、字体、图例显示和 PDF 命名规则,都要在脚本前确定。
对 ArcPy批量出图来说,模板越规范,脚本越短。不要把“修正图例位置”“重新设计标题样式”“临时改符号”放进批处理脚本里,否则后期维护会非常困难。
arcpy.mp导出PDF:批量导出多个 Layout
最简单的需求是:一个 APRX 工程里已经有多个布局,每个布局都设计好了,只需要一次性导出成多个 PDF。这类 arcpy.mp导出PDF 不需要地图系列,只要遍历 aprx.listLayouts() 即可。
import arcpy
from pathlib import Path
aprx_path = r"D:\gis_projects\county_atlas\atlas_template.aprx"
out_dir = Path(r"D:\gis_projects\county_atlas\output_pdf")
out_dir.mkdir(parents=True, exist_ok=True)
aprx = arcpy.mp.ArcGISProject(aprx_path)
for layout in aprx.listLayouts():
file_name = layout.name
for bad in ["\\", "/", ":", "*", "?", '"', "<", ">", "|"]:
file_name = file_name.replace(bad, "_")
pdf_path = out_dir / f"{file_name}.pdf"
pdf = arcpy.mp.CreateExportFormat("PDF", str(pdf_path))
pdf.resolution = 300
pdf.embedFonts = True
pdf.georefInfo = True
pdf.setLayersAndAttributes("LAYERS_ONLY")
layout.export(pdf)
print(f"exported: {pdf_path}")
del aprx
这段脚本适合导出一批已经排好的专题图。它做了三件关键事:第一,用 listLayouts() 获取所有布局;第二,把 Layout 名称处理成合法文件名;第三,为每张图创建 PDF 输出对象并设置分辨率、字体和地理参考信息。
如果只想导出某一个布局,不要写 aprx.listLayouts()[0] 这种不稳定写法。更稳妥的是通过唯一名称查找:
layout = aprx.listLayouts("A3_乡镇专题图")[0]
这样即使以后工程里新增了布局,脚本也不会因为列表顺序变化而导出错对象。
arcpy批量导出地图:用 Map Series 按行政区分页
如果要按乡镇、街道、网格、分幅号或项目单元输出一套图册,优先考虑 ArcGIS Pro 的 Map Series。它用一个索引图层驱动每一页的范围、页名和动态文本,比手工循环设置范围更稳。
arcpy批量导出地图的典型流程是:先在 ArcGIS Pro 中启用地图系列,选择索引图层和名称字段,调好动态标题、页码、图例约束和地图框范围;确认手动预览每页都正常后,再用 arcpy.mp 批量导出。
import arcpy
from pathlib import Path
aprx = arcpy.mp.ArcGISProject(r"D:\gis_projects\county_atlas\county_atlas.aprx")
layout = aprx.listLayouts("A3_乡镇图册")[0]
series = layout.mapSeries
if series is None or not series.enabled:
raise RuntimeError("这个布局没有启用 Map Series,请先在 ArcGIS Pro 中配置地图系列。")
out_dir = Path(r"D:\gis_projects\county_atlas\pdf_by_town")
out_dir.mkdir(parents=True, exist_ok=True)
pdf = arcpy.mp.CreateExportFormat("PDF")
pdf.resolution = 300
pdf.embedFonts = True
options = arcpy.mp.CreateExportOptions("MAPSERIES")
options.setExportPages("CURRENT")
for page_number in range(1, series.pageCount + 1):
series.currentPageNumber = page_number
page_name = str(series.pageRow.NAME)
clean_name = page_name
for bad in ["\\", "/", ":", "*", "?", '"', "<", ">", "|"]:
clean_name = clean_name.replace(bad, "_")
pdf.filePath = str(out_dir / f"{page_number:03d}_{clean_name}.pdf")
series.export(pdf, options)
print(f"exported page {page_number}: {page_name}")
del aprx
上面代码每次把地图系列切到当前页,再导出当前页 PDF。示例里的 NAME 是索引图层字段名,实际项目中要替换成你的页名字段,例如 TOWN_NAME、GRID_ID 或 MAP_NO。
如果希望输出一个多页 PDF 图册,可以不用循环每页文件名,直接让 Map Series 导出全部页面:
pdf = arcpy.mp.CreateExportFormat(
"PDF",
r"D:\gis_projects\county_atlas\乡镇专题图册.pdf"
)
pdf.resolution = 300
pdf.embedFonts = True
series.export(pdf)
这种方式适合正式图册归档。逐页 PDF 适合分发给不同负责人、上传系统或后续单页审核。选择哪一种,取决于成果交付方式。
arcpy批量制图:更新标题、范围和图层可见性
并不是所有项目都适合 Map Series。有些专题图需要按业务规则切换图层、修改标题、调整范围、替换数据源,或者不同页面使用不同专题字段。这时可以用脚本直接控制布局元素,完成更灵活的 arcpy批量制图。
import arcpy
from pathlib import Path
aprx = arcpy.mp.ArcGISProject(r"D:\gis_projects\landuse\landuse_template.aprx")
layout = aprx.listLayouts("A3_专题图模板")[0]
map_frame = layout.listElements("MAPFRAME_ELEMENT", "主地图框")[0]
title = layout.listElements("TEXT_ELEMENT", "图名")[0]
boundary_fc = r"D:\gis_projects\landuse\data.gdb\town_boundary"
target_layer = map_frame.map.listLayers("乡镇边界")[0]
out_dir = Path(r"D:\gis_projects\landuse\pdf")
out_dir.mkdir(parents=True, exist_ok=True)
with arcpy.da.SearchCursor(boundary_fc, ["NAME", "SHAPE@"]) as rows:
for name, shape in rows:
safe_value = name.replace("'", "''")
target_layer.definitionQuery = f"NAME = '{safe_value}'"
file_name = name
for bad in ["\\", "/", ":", "*", "?", '"', "<", ">", "|"]:
file_name = file_name.replace(bad, "_")
title.text = f"{name}土地利用现状图"
map_frame.camera.setExtent(shape.extent)
map_frame.camera.scale *= 1.10
pdf_path = out_dir / f"{file_name}土地利用现状图.pdf"
pdf = arcpy.mp.CreateExportFormat("PDF", str(pdf_path))
pdf.resolution = 300
pdf.embedFonts = True
layout.export(pdf)
target_layer.definitionQuery = ""
del aprx
这段代码的思路是用边界要素逐个驱动出图:按名称过滤目标图层,更新标题,把地图框缩放到当前要素范围,再输出 PDF。它适合页面逻辑比较特殊的项目,但也更依赖脚本质量。字段名、查询语句、文件名、比例尺规则和异常处理都要认真检查。
如果每页只是按索引范围切换,Map Series 更省心;如果每页要切换多个图层、多个标题字段或多个专题变量,自定义循环更灵活。不要一开始就写很复杂的循环,先判断 ArcGIS Pro 自带地图系列能不能满足需求。
常见坑:导出失败、空白 PDF 和字体问题
批量脚本出错时,不要只盯着最后一行报错。制图自动化涉及工程、数据、版式和输出路径,任何一处不规范都可能失败。
- 使用 CURRENT 运行位置不对。
ArcGISProject("CURRENT")只适合在 ArcGIS Pro 内部 Python 窗口或脚本工具中引用当前工程。独立脚本更建议写完整.aprx路径。 - Layout 或元素名称不唯一。
listLayouts()和listElements()返回的是列表。如果同名对象很多,脚本可能拿到错误对象。 - 地图系列没有启用。
layout.mapSeries可能是None,也可能存在但未启用。导出前必须检查。 - 输出文件名包含非法字符。行政区名称、项目名称里可能有斜杠、冒号、引号等字符,写入 PDF 前要清理。
- PDF 空白或范围不对。常见原因是地图框名称找错、范围设置到空几何、图层定义查询过滤掉全部要素,或图层数据源断开。
- 中文字体替换。正式交付的 PDF 建议设置
embedFonts = True,并确认制图机器安装了模板使用的字体。 - 文件体积过大。高分辨率影像、复杂矢量和图层属性会放大 PDF。可根据交付需求调整分辨率、图层属性、影像压缩和是否保留地理参考信息。
- 比例尺不一致。如果项目要求统一比例尺,不要只用
setExtent,还要明确设置或取整map_frame.camera.scale。 - 没有先手动导出样张。批处理前至少手动导出 1 到 3 张代表性页面,确认图例、标注、范围、PDF 字体和输出质量没有问题。
工具和方法对比:手动导出、Map Series 和脚本循环
不同出图任务不需要同一种方法。下面的对比可以帮助你选择更稳的流程。
| 方法 | 适合场景 | 优点 | 限制 |
|---|---|---|---|
| 手动导出 Layout | 只导出一两张图,或临时检查样张 | 直观,适合设计阶段快速调整 | 数量一多容易漏改标题、范围和输出参数 |
| ArcGIS Pro Map Series | 行政区图册、标准分幅、网格巡查图、项目单元图册 | 动态文本、页码、索引范围和图册逻辑稳定 | 复杂业务条件切换不如脚本循环灵活 |
| arcpy.mp 遍历 Layout | 一个工程里已有多张排好版的专题图 | 代码短,适合统一导出 PDF、PNG 或 TIFF | 不负责自动生成页面内容,前期版式必须已经做好 |
| arcpy.mp 自定义循环 | 每页需要修改标题、查询条件、图层显隐、范围或数据源 | 灵活,能嵌入项目业务规则 | 更容易受字段、查询、文件名和异常数据影响 |
| 旧式 exportToPDF 脚本 | 维护历史项目或旧版单位环境 | 旧代码存量多,容易在老项目中见到 | 新项目建议优先采用 export 格式对象写法,便于后续扩展 |
如果是标准图册,推荐先用 Map Series;如果是已有多个布局,推荐遍历 Layout;如果每页规则都不同,再考虑自定义脚本循环。方法选对了,脚本会简单很多。
实用检查清单:批处理前后分别看什么
运行脚本前
- APRX 是否能在 ArcGIS Pro 中正常打开,所有图层是否无断链。
- Layout、MapFrame、TextElement、目标图层名称是否唯一。
- 地图系列是否已经启用,索引图层和页名字段是否正确。
- 输出目录是否存在,脚本账号是否有写入权限。
- 样张 PDF 是否已经手动导出并检查字体、图例、比例尺和范围。
运行脚本时
- 打印当前导出的页码、页名和输出路径,方便定位失败页面。
- 对空几何、空名称、重复名称和非法文件名做处理。
- 优先从少量页面测试,再扩大到全部页面。
- 不要在同一个输出目录里混放旧版和新版 PDF,避免误判结果。
导出完成后
- 核对 PDF 数量是否等于 Layout 数量、地图系列页数或输入要素数量。
- 抽查首页、中间页、末页,以及边界特别大或特别小的页面。
- 检查中文字体、图例、标注、比例尺、页码和图名是否正确。
- 检查 PDF 文件大小是否异常,异常过小可能是空白页,异常过大可能需要调整导出参数。
- 把脚本、APRX 模板、输入数据版本和输出结果一起归档,保证下次可以复跑。
FAQ:批量出图、PDF 导出和自动制图
ArcPy批量出图一定要会写复杂 Python 吗?
不一定。标准图册的核心通常是 ArcGIS Pro 模板和 Map Series,Python 只负责批量导出和少量参数控制。初学者可以先从遍历 Layout 导出 PDF 开始,再逐步加入标题替换、范围控制和图层查询。
arcpy.mp导出PDF时,应该用 exportToPDF 还是 export?
新项目建议优先使用 CreateExportFormat("PDF") 加 export 的写法,参数更容易和其他格式统一管理。旧脚本里常见 exportToPDF,维护历史项目时可以继续理解它,但不要把旧写法当作唯一方案。
arcpy批量导出地图为什么导出的页面都是同一个范围?
常见原因是 Map Series 没有启用、循环里没有更新 currentPageNumber,或者自定义循环中只改了标题,没有调用 map_frame.camera.setExtent()。如果用地图系列,还要确认索引图层和页名字段设置正确。
arcpy批量制图能不能自动修改图例和标注?
可以控制一部分图例、图层可见性、定义查询和文本元素,但不建议把复杂排版全部写进脚本。更稳的方式是在模板里先调好图例样式、标注规则和动态文本,脚本只替换变量和导出。
批量导出的 PDF 文件很大怎么办?
先判断交付是否必须保留图层、属性和地理参考信息。如果只是普通审阅图,可以降低分辨率、关闭部分 PDF 图层属性或调整影像压缩;如果是正式 GIS 成果,则要在文件大小和可编辑、可量测能力之间做取舍。
脚本在 ArcGIS Pro 里能跑,独立运行却失败怎么办?
先检查是否使用了 ArcGISProject("CURRENT")。它只适合在 ArcGIS Pro 内部引用当前工程。独立运行时应使用完整 APRX 路径,并确保调用的是 ArcGIS Pro 自带的 Python 环境,而不是普通系统 Python。
结论:把批量制图拆成模板和脚本两部分
ArcPy批量出图最稳的思路,是让 ArcGIS Pro 负责制图表达,让 arcpy.mp 负责自动化执行。先把 APRX 模板、Layout、Map Series、图层样式和动态文本做好,再用脚本批量设置页面、范围、标题和 PDF 输出参数。
如果只是统一导出已有布局,用 arcpy.mp 遍历 Layout 导出 PDF 就够;如果要按行政区或网格生成图册,用 arcpy批量导出地图 的 Map Series 流程更稳;如果每页还有复杂业务规则,再写自定义 arcpy批量制图 循环。把这三类场景分清楚,脚本会更短,成果也更容易复核。
-
QGIS虚拟图层SQL查询:连接表和空间筛选 2026-06-13 01:55:21
-
DEM流向:水文分析和流域划分前处理 2026-06-13 01:50:34
-
无人机正射影像:航测正射和影像正射流程 2026-06-12 22:19:43
-
无人机航测精度:像控点布设和飞行高度计算 2026-06-12 20:49:03
-
OpenLayers点击事件:图层点击事件和坐标拾取 2026-06-12 01:38:49
-
QGIS Processing报错:Processing错误和处理工具箱打不开 2026-06-11 20:55:46
-
Sentinel2云掩膜:大气校正、GEE去云和NDVI检查 2026-06-11 13:42:34
-
ArcGIS Pro字段计算器:数值涵义和顺序编号 2026-06-11 11:39:27
-
ArcPy栅格计算:arcpy.sa和栅格计算器排查 2026-06-11 10:48:22
-
ArcPy字段计算:AddField、字段映射和更新游标 2026-06-11 09:49:34
-
Leaflet加载WMTS:瓦片地图和离线地图配置 2026-06-11 03:40:08
-
ArcPy投影转换:定义投影、重投影和空间参考 2026-06-10 20:51:20
-
OpenLayers图层不显示:WMTS、TIF加载和原因排查 2026-06-10 19:22:44
-
ArcPy批量裁剪:批处理栅格处理和输出检查 2026-06-10 18:47:40
-
GeoPandas裁剪:clip、读取SHP和GeoJSON裁剪流程 2026-06-10 08:45:06
-
QGIS修复无效几何:修复几何和几何修复流程 2026-06-10 03:48:19
-
遥感监督分类:遥感图像监督分类步骤和精度验证 2026-06-09 18:16:55
-
无人机航线规划软件:规划方法和规划步骤 2026-06-09 15:16:34
-
无人机测绘流程:软件有哪些、数据处理和精度 2026-06-09 13:32:14
-
Cesium影像加载失败:本地影像和TIF加载排查 2026-06-09 09:02:22