简介:针对ArcGIS按图斑批量出图的实际需求,这份doc文档提供了从数据驱动页面配置到Python脚本导出的完整方案,适合需要高频处理卫片图斑、批量输出JPG成果图的GIS技术人员。文档重点讲解ArcGIS 10.2及以上版本中Data Driven Pages的启用与参数设置,包括图层、名称字段、排序字段、显示范围和比例尺的确定方法;同时介绍布局视图中动态文本的添加,使每张图自动带有图斑编号、面积、所在区域等属性信息,便于成果归档与查阅。核心部分给出基于arcpy的Python批处理脚本,通过遍历数据驱动页面并调用ExportToPNG、ExportToJPG实现一键导出,还说明了在Notepad++中执行脚本的大致流程。资源包共1个文件,为doc格式说明文档,体积约29KB,轻量易用。已有8265人学习下载,对正在搭建批量出图流程、希望提升制图效率的ArcGIS用户有直接参考价值。
1. ArcGIS按图斑批量出图:把每个图斑变成一页,再让脚本一口气跑完
某次卫片图斑核查,一次性下发800多个图斑,要求每个图斑出一张影像成果图,图名是图斑编号,图上带边界晕线和比例尺。手动出图一张三分钟,800张就是两天两夜。按图斑批量出图的核心就一句话:让页面范围跟着图斑走,每个图斑对应一页,再用脚本把几百页一次性导出。这个方案解决的是内业出图最高频的重复劳动,适合卫片执法、国土变更调查、自然资源督察这类图斑数量大、成果格式统一的场景。本文从索引面制作、模板配置讲到脚本导出和常见坑,给出一条可以直接复现的路径。
2. 批量出图方案选型:数据驱动页面与地图系列,先弄懂机制再动手
2.1 数据驱动页面与地图系列:一页对应一个要素的页面机制
ArcGIS里能实现“一图斑一页”的核心功能,在ArcMap里叫数据驱动页面(Data Driven Pages),在ArcGIS Pro里叫地图系列(Map Series)。它们的机制是同一个思路:准备一个索引图层,索引图层里的每个面要素对应输出的一页,翻到第几页,地图框就自动定位到那个面要素的范围上,页面名称也能从索引图层的字段里取。
按图斑出图正好用得上这个机制:把每个图斑的外接矩形做成索引面,矩形里包含了图斑本身和周边参考影像,索引面有多少个,输出就有多少页。你要做的只是把索引面做好、把模板配好,剩下逐页定位的事全部交给软件,不需要在每一页上去手动缩放。
我一般建议新项目直接用ArcGIS Pro,地图系列在Pro里是原生制图功能,界面和API都更干净;ArcMap的数据驱动页面在老流程里完全够用,但Pro的后续支持明显更值得投入。需要留意的是这两个功能都属于制图相关能力,动手前先确认你手上的软件版本和许可包含制图授权,别等模板配了一半才发现功能置灰。
2.2 为什么不建议用规则格网做索引:大图斑被切碎,跨页拼接会让你崩溃
很多第一次做批量出图的人,第一反应是生成一张规则格网当索引,比如用创建渔网(Create Fishnet)或格网索引要素(Grid Index Features)工具,把测区均匀切成一格格。这个思路在标准分幅出图时没问题,但放到按图斑出图上,问题非常直接。
卫片图斑的大小差异往往悬殊:有的图斑是一个大棚几亩地,有的是一整片工地几百亩。规则格网是均匀的,格网小了,大图斑被切成好几块,一个图斑出现在多页上,成果图没法直接交付;格网大了,小图斑在图面上只占一小块,周边全是空白影像,比例尺也压不实。有人说可以按最大图斑去定格网尺寸,但那样小图斑的比例尺被放大到离谱,图面信息量极低。
所以按图斑出图的正解是:一个图斑对应一个索引面,而不是用均匀格网去套。规则格网只适合“按标准图幅出图”的场景,凡是成果要求“一图斑一张”的,都应该走自定义索引面。
2.3 三种索引面候选方案:规则格网、图斑缓冲面、外接矩形怎么选
做索引面的时候,有三个候选方向,我把它们的差异整理成了一张表,这也是我每次给新同事讲批量出图时必放的对比。
| 候选方案 | 做法 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|---|
| 规则格网 | Create Fishnet 或 Grid Index Features 生成均匀网格 | 图幅均匀、页与页之间可拼接 | 大图斑被切碎、小图斑留白过大 | 标准分幅出图 |
| 图斑缓冲面 | 直接用 Buffer 工具给图斑做缓冲区 | 贴合图斑形态、范围紧凑 | 缓冲面形状不规则,页面留白不均衡 | 不适合直接做索引 |
| 外接矩形加边距 | 先取最小外接矩形,再向外缓冲一段距离 | 页面规整、留白均匀、比例尺稳定 | 需要两步处理,多一道工序 | 按图斑批量出图,推荐 |
缓冲面虽然形态上贴近图斑,但DDP和地图系列取页面范围时,本质上还是取要素的外接范围,绕了一圈最后还是矩形,而且是不规则的矩形。与其这样,不如一开始就用外接矩形加边距,页面范围干净利落,后续加图框、加比例尺也都好对齐。
3. 索引面制作实操:坐标系、外接矩形与页面范围三件事
3.1 先把坐标系统一:矢量影像对不上,九成是这一步省了
做索引面之前,我要求自己先做一件事:把矢量和影像的坐标系查清楚。卫片影像常见的坐标系是WGS84下的UTM分带,或者CGCS2000的高斯投影;而下发的图斑矢量往往也是CGCS2000,但偶尔会给你一套地理坐标。两套坐标系不统一,ArcGIS默认会做动态投影,屏幕上看着是叠在一起的,导出的成果图经过重采样,经常出现影像和边界错位几十米的情况。
我的习惯是打开工程先看每个图层的“源”信息,然后确定数据框坐标系,一般用CGCS2000的3度带高斯投影,中央经线按影像所在区域选。接下来把矢量用投影(Project)工具转过去,影像用投影栅格(Project Raster)工具转过去,两条命令在Python里也很固定:
import arcpy # 矢量投影到出图数据框的坐标系 arcpy.Project_management( in_dataset=r"D:\work\矢量数据\卫片图斑_WGS84.shp", out_dataset=r"D:\work\矢量数据\卫片图斑_CGCS2000.shp", out_coor_system=r"D:\work\坐标系\CGCS2000_3度带_117E.prj" ) # 影像重投影到同一坐标系,重采样用双线性 arcpy.ProjectRaster_management( in_raster=r"D:\work\影像\DOM_UTM.tif", out_raster=r"D:\work\影像\DOM_CGCS2000.tif", out_coor_system=r"D:\work\坐标系\CGCS2000_3度带_117E.prj", resampling_type="BILINEAR" )这两个工具的参数很直观:第一个参数是输入要素类,第二个是输出要素类,第三个是坐标系文件。坐标系文件可以提前在ArcToolbox里用“创建自定义坐标系”生成好,也可以直接引用已有的.prj。影像重投影时,重采样方法里BILINEAR适合影像纠正,如果是分类数据这类离散栅格,要用NEAREST保持数值不插值。
注意一点:有不少人图省事,直接在图层属性里把坐标系描述改掉,那个操作只是改了元数据,几何坐标一个点都没动,出图该错位还是错位。统一坐标系这事必须用工具真正执行一次。
3.2 生成索引面:先外接矩形再缓冲,一套参数照抄
坐标系统一后,索引面制作就进入了正题。我的推荐顺序是先取外接矩形,再做缓冲,这样得到的索引面四边留白均匀,页面比例也稳定。用到的工具是分析工具箱里的最小边界几何(Minimum Bounding Geometry)和缓冲(Buffer),完整流程可以一次性用Python跑完:
import arcpy arcpy.env.workspace = r"D:\work\索引面" shp = r"D:\work\矢量数据\卫片图斑_CGCS2000.shp" rect = r"D:\work\索引面\图斑外包矩形.shp" buf = r"D:\work\索引面\图斑出图索引面.shp" # 第一步:对每个图斑生成外包矩形 arcpy.MinimumBoundingGeometry_management( in_features=shp, out_feature_class=rect, geometry_type="ENVELOPE", group_option="NONE" ) # 第二步:矩形向外扩50米,作为每页的出图范围 arcpy.Buffer_analysis( in_features=rect, out_feature_class=buf, buffer_distance_or_field="50 Meters", line_side="FULL", line_end_type="FLAT" )最小边界几何里的ENVELOPE是轴对齐的外接矩形,不随图斑角度旋转,这对整个页面范围来说更稳定;GROUP字段可以按某个字段分组生成联合外接框,但按图斑出图时每个图斑独立成页,用NONE就行。缓冲距离要看图斑大小,我一般取30到50米,图斑边界复杂、图形细碎的地方可以缩到20米,先抽几个图斑试看再定。
Buffer工具里有两个参数容易忽略。一个是距离单位,如果索引面的坐标系还是地理坐标系,那么“50 Meters”会被当成以度为单位的距离,结果完全跑飞,所以这步必须放在上一步坐标系统一之后。另一个是端头类型,LINE_END_TYPE要选FLAT,这样矩形四角不会被缓冲成圆角,索引面仍然是规整矩形,页面范围才干净。
矩形做完之后,还要给索引面补一个图斑编号字段,后面动态图名和脚本都要用到它:
arcpy.AddField_management(buf, "TBH", "TEXT", field_length=30) arcpy.CalculateField_management(buf, "TBH", "!图斑编号!", "PYTHON3")这里的原则是字段名尽量用拼音缩写或英文,不要用中文。中文字段名在Python的字段计算和定义查询里很容易出编码问题,尤其是接第三方数据时不兼容。Calculate Field的表达式写法上,shapefile字段用英文感叹号包裹,地理数据库要素类字段要用英文感叹号加字段名,两个数据源写法略有差异。
3.3 配置数据驱动页面或地图系列:入口、字段与页面范围选哪个
索引面做好了,接下来把它挂到制图功能里。ArcMap里打开mxd后切到Layout视图,调出Data Driven Pages工具条,点Setup进入设置页,指定索引图层,Name Field选TBH,Sort Field也选TBH,这样翻页顺序和文件名都是按图斑编号排的。页面范围用Extent选项控制,我基本只用Best Fit。
ArcGIS Pro的思路一致:新建Layout后,在“插入”选项卡里点地图系列,选择Spatial Map Series,指定索引图层和字字段,地图框选择布局里要跟随的那一个框即可。只是Pro的面板位置和ArcMap不同,但本质参数没有变化。
页面范围里的三个选项,值得说清楚。Best Fit是自动拿索引面的范围,然后按地图框的宽高比做等比例适配,横纵比例都不变形,图永远不被拉伸,推荐默认用它。Center是以索引面中心为准,按地图框比例取范围,如果索引面的形状和地图框比例差异大,会出现单边留白过多的情况。Data Driven则是直接把索引面范围当页面范围,完全不考虑地图框比例,图会被横向或纵向拉伸,一般只有特殊行业制图才会碰。
这里还有一个制图经验:地图框的宽高比决定了很多东西。图斑整体呈长条形,布局可以考虑竖版;图斑多是片状地块,横版A4或A3更实用。宁可多花两分钟调宽高比,也别让几百张图都带着一条尴尬的空白边。
4. 模板与动态文本:让每一页的图名、比例尺和日期自己变
4.1 动态文本三件套:图名、比例尺、日期,一条语法搞定
索引面挂进数据驱动页面后,模板里每个页面显示什么,是下一步要解决的问题。手动一页页改标题根本不现实,动态文本就是为这件事设计的。ArcMap里在Layout视图的“插入”菜单下可以插入动态文本,ArcGIS Pro里同样有这个入口,区别只是对象命名不一样。
常用的三项动态文本,我整理成了一张对应表:
| 显示内容 | ArcMap 动态文本 | ArcGIS Pro 对应项 |
|---|---|---|
| 当前页图斑编号(图名) | <dyn type="page" property="name"/> | 页名称 / Page Name |
| 当前比例尺 | <dyn type="data frame" property="scale" format="1:{scale}"/> | 地图比例 / Map Scale |
| 出图日期 | <dyn type="date" property="date" format="yyyy-MM-dd"/> | 日期 / Date |
插入动态文本后,要单独选中它,在属性里把字体设置成常见中文字体,比如宋体或黑体。这个细节看似小,实际对交付PDF的影响很大,字体不对后面乱码的坑就等着你踩。图名如果希望显示成“卫片图斑-TB20240001”这种带前缀的形式,直接在动态文本前面放一个静态文本框写“卫片图斑-”就行,编号部分仍然由动态文本提供。
4.2 图斑边界与影像显示:线宽单位选不对,返工跑到天亮
图斑边界在成果图里通常要求画得醒目,常见做法是红色实线加半透明淡红填充。但这里有一个特别容易翻车的设置:线与填充边界的宽度单位。ArcGIS符号里,宽度可以用地图单位(比如米),也可以用页面单位(比如磅)。如果选了地图单位,线宽会随着比例尺缩放,而按图斑出图时每页比例尺往往不一样,结果小图斑的页里线粗得像描边,大图斑的页里线细得看不清。
解决方法是把轮廓宽度单位切到“磅”或“点”,大小固定在1.5到2磅之间,这样不管页面范围怎么变化,图面上红线粗细始终一致。很多人第一次做批量出图是不注意这个的,等几百张图导出来才发现问题,那时候返工的时间成本已经很夸张了。
影像显示同样需要提前设置。卫片影像导入ArcGIS后,默认的拉伸方式经常让影像看起来灰蒙蒙的,尤其是原始影像动态范围大时。打开影像图层属性里的符号系统,把拉伸类型设为“百分比裁剪”,下限2、上限98,或者“标准差”取2倍,影像反差会正常很多,成果图也不会被甲方吐槽“图像太黑”。
4.3 只显示当前页的图斑:一个关键选项加一条定义查询
模板配置好后,预览时会发现一个问题:页面范围是跟着当前索引面走了,但图层上所有图斑全部显示,当前页的图斑没有被单独高亮。这看起来乱,但处理起来也不复杂,分两层走。
先在数据框属性或地图系列设置里勾选“裁剪到当前页范围”的选项,ArcMap里在数据框属性的数据驱动页面选项卡下找“Clip layers to data driven pages extent”这一类选项,Pro里在地图系列对话框的地图框范围设置里,不同版本文案略有差异,但功能是一致的。勾选后,每一页就只看到与当前页范围相交的要素,这是最基础的一步。
但仅仅裁剪还不够,因为相邻较近的图斑会被一并带进当前页。我的做法是把图斑图层拆成两层:底层叫“参考图斑”,全部显示,符号用灰色半透明;顶层叫“当前图斑”,用定义查询控制在每一页只显示当前那个图斑,符号用红色实线加淡红填充。定义查询的写法不复杂,脚本每翻一页就更新一次:
lyr_current.definitionQuery = '"TBH" = \'TB20240001\''方向先立住,完整脚本放到第6章。需要提醒的是,定义查询的字段引用格式和数据类型强相关:shapefile字段名不需要双引号,地理数据库要素类字段要加双引号,字符串值用单引号,数字字段则不需要引号。最好先在一个页面上试一条查询,确认语法没问题再批量跑。
5. 按图斑批量出图避坑手册:5个高发问题的现象、原因与破解
5.1 导出的每一页都显示全图斑,页面范围没起作用
现象:脚本跑完几十页PDF,每张图都是整个测区的图斑,当前页图斑没有高亮,图面乱成一团。
原因:模板里只配置了数据驱动页面,没有配置图层的“裁剪到当前页范围”选项,也没有做只显示当前要素的定义查询,页面范围虽然变了,但图层显示范围没跟上。
解决:先按4.3在数据框或地图系列里勾选裁剪选项,再把“当前图斑”图层单独做定义查询,脚本循环中每次翻页先更新定义查询,导出后再清空,避免影响下一页。这个组合是“一图斑一页”的关键,两个环节缺一个都会出问题。
5.2 影像和矢量错位,图斑跑到影像外面
现象:导出的PDF里,图斑边界和影像上的地块对不上,有的偏移十几米,有的几十米。
原因:最常见的是矢量和影像坐标系不一致,数据框在动态投影。屏幕预览时ArcGIS做了实时纠正,看着误差不大,但导出时重采样和比例尺转换把误差暴露出来了。还有一种情况是影像本身控制点精度差,这个不属于软件设置问题,需要换影像源。
解决:按3.1的步骤,先把矢量和影像重投影到统一的CGCS2000高斯投影坐标系,固定数据框坐标系后再配模板。特别注意顺序:统一坐标系要在生成索引面之前做,因为索引面的范围和坐标系绑定,中途换坐标系,前面做的矩形范围就全废了。
5.3 图斑边界线宽不统一:小图斑线粗,大图斑线细
现象:同一批导出的成果图,图斑小的页红线粗得像描边,图斑大的页红线细到看不清。
原因:符号轮廓宽度用了地图单位,线宽随比例尺缩放。按图斑出图时每页比例尺不同,视觉宽度自然忽大忽小。
解决:打开图层符号系统,把轮廓宽度的单位从地图单位切换成“磅”或“点”,宽度值设在1.5到2。这一招对图斑边界的显示一致性立竿见影,出图之前先导出两三张不同面积的图斑对比检查一下,别等全量跑完再回头看。
5.4 批量导出几百页后内存暴涨,跑到一半崩溃
现象:脚本跑到300多页,ArcGIS直接闪退,或者进程内存涨到十几GB,越跑越卡。
原因:脚本长时间持有mxd或aprx对象,每一轮循环产生的导出缓存没有释放;批量导出PDF时打印机驱动和绘图缓存占用的内存明显高于导出PNG。
解决:给脚本加起始页码和结束页码参数,把几百页拆成每批200页以内分批跑;每批结束后主动释放对象,Python里用del和gc.collect()回收内存;输出格式优先考虑PNG或JPG,很多场景下成果图用图片格式完全够用,而且比PDF省内存得多。
import gc for i in range(start, end + 1): # 导出当前页 arcpy.mapping.ExportToPNG(mxd, out_png, resolution=200) del mxd gc.collect()5.5 交付PDF后图名中文乱码
现象:自己电脑上打开PDF一切正常,发给同事后图名变成一个个方框或乱码。
原因:PDF里的动态文本依赖系统中文字体,对方机器没有安装对应字体,或者导出时字体没有被嵌入文件。
解决:导出PDF时在PDF选项里勾选嵌入字体;模板里的动态文本统一用常见中文字体,避免使用生僻的字体族;如果交付对象那边环境不可控,最稳妥的做法是直接导出高分辨率PNG或JPG交付。卫片图斑成果图绝大多数场景下图片格式都能满足归档和检查要求,不值得为了PDF格式冒字体风险。
6. 进阶:把校验、分批和脚本拢成一条批量出图流水线
6.1 完整导出脚本(ArcMap版):一页一定义查询,批跑带进度
把前面几个环节串到一起,完整脚本长这样:
import arcpy, os, time mxd = arcpy.mapping.MapDocument(r"D:\work\出图模板\卫片图斑出图.mxd") out_dir = r"D:\work\成果PDF" os.makedirs(out_dir, exist_ok=True) lyr_current = arcpy.mapping.ListLayers(mxd, "当前图斑")[0] dp = mxd.dataDrivenPages ok, fail = [], [] t0 = time.time() for i in range(1, dp.pageCount + 1): dp.currentPage = i tbh = dp.pageRow.getValue("TBH") lyr_current.definitionQuery = '"TBH" = \'{}\''.format(tbh) out_pdf = os.path.join(out_dir, tbh + ".pdf") try: arcpy.mapping.ExportToPDF(mxd, out_pdf, resolution=200) ok.append(tbh) except Exception as e: fail.append((tbh, str(e))) lyr_current.definitionQuery = "" print("完成 {} 页,失败 {} 页,耗时 {:.0f} 秒".format(len(ok), len(fail), time.time() - t0)) if fail: print("失败图斑:", fail)循环里先设定义查询,导出,再清空定义查询,这个顺序不能反。清空放在导出之后,是为了让当前页符号渲染完成再释放,避免导出时图层状态不对。输出文件名直接用TBH字段,方便后面和原始图斑数量比对;如果图斑编号里带了斜杠等特殊字符,脚本里要先做字符替换。
6.2 缺失校验:拿输出文件夹和TBH比对,缺谁一目了然
批量跑完后,一定要做一次完整性校验。用Python把输出文件名和索引面里TBH字段的值做集合对比,缺失的图斑编号直接打印出来:
import os done = {os.path.splitext(f)[0] for f in os.listdir(out_dir) if f.endswith(".pdf")} tbhs = [r[0] for r in arcpy.da.SearchCursor(index_shp, ["TBH"])] missing = [tbh for tbh in tbhs if tbh not in done] print("应出 {} 张,已出 {} 张,缺失 {} 张".format(len(tbhs), len(done), len(missing)))这段代码花不了几秒钟,但能挡住最尴尬的交付事故。缺失清单出来后,把脚本加上起始页码参数,单独重跑缺失部分即可。
6.3 分批与并行:几百个图斑不需要一台机器跑一夜
批量出图到了几百上千张的量级,时间就变得敏感了。我的做法是给脚本加上start和end参数,把图斑拆成每批200页,多个ArcGIS进程同时跑。并行时要注意:同一个mxd文件同时被多个进程打开会锁文件,所以每个批次要复制一份mxd到独立目录,各自对应不同的页码范围。
现在我的固定流程是:先抽3个图斑出图,人工把图名、比例尺、影像、图斑高亮全部检查一遍,再分批跑全量;每批跑完自动打印缺失清单,最后随机抽20张复查。有一次我没抽检直接跑了两千多张,跑到第一千二的时候内存崩了,重启后只能从头再来,一上午就这么没了。自那以后,无论工期多紧,抽检和页码参数这两个习惯我都不会再省。这套流程现在固定在我们组的图斑出图任务里,从索引面到PDF基本就是脚本一跑的事,希望帮到你。
本文还有配套的精品资源,点击获取