Python地理处理还在手动拼接地图?四步自动化出图脚本(附:国土空间规划配色方案)
如果你在做“Python地理处理还在手动拼接地图?四步自动化出图脚本(附:国土空间规划配色方案)”这类工作,通常痛点不是不会制图,而是每次都要重复打开软件、加载数据、套样式、导出图片,项目一多就很容易出错。本文用一个可复用的 Python 自动化出图流程,把矢量数据读取、字段分类、规划用途配色、地图布局和批量导出串起来,适合国土空间规划、专题图批量制图和 GIS 数据检查场景。
引言:为什么要用 Python 地理处理自动化出图
很多 GIS 同学和初级工程师在做规划专题图时,会先在 QGIS 或 ArcGIS Pro 里调好一张图,再截图、复制、手动拼接,最后放到报告里。这个方式在单张图时问题不大,但一旦涉及多个行政区、多个年份、多个规划情景,手工流程就会暴露三个问题:
- 效率低:同一套图层、同一套配色,需要重复操作很多次。
- 一致性差:图例、色值、比例尺、标题位置很容易前后不一致。
- 难以复现:别人很难知道你当时到底用了哪份数据、哪套分类字段和哪组颜色。
Python 地理处理自动化出图的核心价值,是把“人工点击流程”变成“可重复运行的脚本流程”。只要输入数据字段规范、坐标系正确、分类规则明确,同一套脚本就可以稳定生成多张地图。

背景:手动拼接地图最容易出错的地方
在国土空间规划、用地现状分析、生态红线核查、城镇开发边界制图等项目中,地图通常不是一张,而是一批。例如按区县出图、按乡镇出图、按用地类型出图、按规划方案出图。
手动拼接地图常见错误包括:
- 颜色不统一:同一个“城镇建设用地”在不同图中使用了不同颜色。
- 图层顺序错乱:边界线、道路、水系和用地面层叠放顺序不一致。
- 范围不一致:有些图裁剪到行政区边界,有些图显示了多余区域。
- 坐标系混乱:面积计算、比例尺显示和地图范围出现偏差。
- 导出分辨率不同:报告中有的图清晰,有的图模糊。
因此,自动化出图不是为了替代制图审美,而是为了把标准化、重复性、容易出错的部分固定下来。Python 脚本尤其适合处理“同一套规则、多张地图输出”的任务。
原理:Python 自动化出图到底自动了什么
Python 地理处理自动化出图通常包含四个核心环节:
- 读取空间数据:使用 GeoPandas 读取 Shapefile、GeoPackage、GeoJSON 等矢量数据。
- 统一坐标系:确保输入图层使用适合制图和面积表达的投影坐标系。
- 按字段套用样式:根据用地类型、规划分区、管控类型等字段配置颜色。
- 输出地图文件:使用 Matplotlib 导出 PNG、PDF 或 SVG,便于放入报告或进一步排版。
其中 GeoPandas 负责空间数据读取和属性处理,Matplotlib 负责绘图和导出。对于更复杂的制图,例如自动图例、指北针、比例尺、地图整饰,也可以继续扩展 Cartopy、contextily 或 QGIS Python API。
本文示例选择 GeoPandas 加 Matplotlib,是因为它安装相对简单、脚本结构清晰,适合快速完成国土空间规划配色方案的自动化专题图输出。
步骤:四步完成 Python 地理处理自动化出图脚本
步骤一:准备数据和字段
示例假设你有一份规划用地图层,文件为 landuse.gpkg,图层中至少包含一个用地类型字段,例如 land_type。这个字段的值可以是“耕地”“林地”“草地”“城镇建设用地”“村庄建设用地”“水域”等。
建议数据准备时先检查三件事:
- 几何是否有效:面要素是否存在自相交、空几何或破碎面。
- 分类字段是否规范:同一种用地不要同时出现“城镇建设用地”“城镇用地”“城镇建设”等多个写法。
- 坐标系是否明确:数据必须有正确的 CRS,避免绘图范围和面积判断错误。
import geopandas as gpd
input_path = "data/landuse.gpkg"
gdf = gpd.read_file(input_path)
print(gdf.crs)
print(gdf.columns)
print(gdf["land_type"].value_counts())
如果 gdf.crs 输出为 None,说明数据没有定义坐标系。这时不要直接出图,应先确认源数据真实坐标系,再进行定义或转换。
步骤二:设置国土空间规划配色方案
国土空间规划配色方案的关键是“稳定”和“可解释”。颜色不一定要追求复杂,但要保证同一类用地在所有图中保持一致。下面给出一套常用的示例配色,实际项目应以甲方、地方标准或单位制图规范为准。
| 用地类型 | 建议色值 | 说明 |
|---|---|---|
| 耕地 | #FFF2B2 |
浅黄色,适合表达农业生产空间 |
| 园地 | #D9F0A3 |
黄绿色,区别于耕地和林地 |
| 林地 | #78C679 |
绿色,表达生态空间 |
| 草地 | #C2E699 |
浅绿色,弱于林地 |
| 水域 | #74A9CF |
蓝色,表达河湖水面 |
| 城镇建设用地 | #E34A33 |
红色,突出建设空间 |
| 村庄建设用地 | #FDBB84 |
橙色,与城镇建设用地区分 |
| 交通运输用地 | #969696 |
灰色,适合道路、铁路等线性空间 |
| 其他用地 | #DDDDDD |
浅灰色,作为兜底类别 |
color_map = {
"耕地": "#FFF2B2",
"园地": "#D9F0A3",
"林地": "#78C679",
"草地": "#C2E699",
"水域": "#74A9CF",
"城镇建设用地": "#E34A33",
"村庄建设用地": "#FDBB84",
"交通运输用地": "#969696",
"其他用地": "#DDDDDD"
}
gdf["plot_color"] = gdf["land_type"].map(color_map).fillna("#DDDDDD")
这里使用 fillna("#DDDDDD") 是为了处理未匹配类别。自动化出图时,不建议让脚本因为某个新增分类直接崩溃,但也不能忽略它。更稳妥的方式是输出未匹配类别清单,便于制图前检查。
unknown_types = sorted(set(gdf["land_type"]) - set(color_map.keys()))
if unknown_types:
print("以下用地类型未配置颜色:")
for item in unknown_types:
print(item)
步骤三:绘制单张专题图
下面的代码会绘制一张用地类型专题图,并导出为 PNG。为了让脚本更适合报告使用,示例中关闭坐标轴,设置标题,添加简单图例,并控制导出分辨率。
import matplotlib.pyplot as plt
from matplotlib.patches import Patch
output_path = "output/landuse_map.png"
fig, ax = plt.subplots(figsize=(10, 8))
gdf.plot(
ax=ax,
color=gdf["plot_color"],
edgecolor="#666666",
linewidth=0.15
)
ax.set_title("国土空间规划用地类型图", fontsize=16)
ax.set_axis_off()
legend_items = []
for land_type, color in color_map.items():
if land_type in set(gdf["land_type"]):
legend_items.append(Patch(facecolor=color, edgecolor="#666666", label=land_type))
ax.legend(
handles=legend_items,
title="用地类型",
loc="lower left",
frameon=True,
fontsize=9,
title_fontsize=10
)
plt.tight_layout()
plt.savefig(output_path, dpi=300, bbox_inches="tight")
plt.close()
这一步已经可以替代很多手工截图流程。对于普通报告插图,dpi=300 通常能满足打印和 Word/PDF 排版需求。如果是 Web 页面展示,可以导出较小尺寸的 PNG 或 WebP,以减少页面加载压力。
步骤四:按行政区批量自动出图
真正节省时间的是批量出图。假设你还有一份行政区边界 district.gpkg,字段 name 存储区县名称。下面脚本会按行政区裁剪用地图层,并为每个行政区导出一张图。
import os
import geopandas as gpd
import matplotlib.pyplot as plt
from matplotlib.patches import Patch
land_path = "data/landuse.gpkg"
district_path = "data/district.gpkg"
output_dir = "output/maps"
os.makedirs(output_dir, exist_ok=True)
land = gpd.read_file(land_path)
district = gpd.read_file(district_path)
if land.crs != district.crs:
district = district.to_crs(land.crs)
color_map = {
"耕地": "#FFF2B2",
"园地": "#D9F0A3",
"林地": "#78C679",
"草地": "#C2E699",
"水域": "#74A9CF",
"城镇建设用地": "#E34A33",
"村庄建设用地": "#FDBB84",
"交通运输用地": "#969696",
"其他用地": "#DDDDDD"
}
land["plot_color"] = land["land_type"].map(color_map).fillna("#DDDDDD")
for idx, row in district.iterrows():
district_name = row["name"]
boundary = gpd.GeoDataFrame([row], crs=district.crs)
clipped = gpd.overlay(land, boundary, how="intersection")
if clipped.empty:
print(f"{district_name} 无用地图斑,跳过")
continue
fig, ax = plt.subplots(figsize=(10, 8))
clipped.plot(
ax=ax,
color=clipped["plot_color"],
edgecolor="#666666",
linewidth=0.12
)
boundary.boundary.plot(
ax=ax,
color="#000000",
linewidth=0.8
)
ax.set_title(f"{district_name} 国土空间规划用地类型图", fontsize=16)
ax.set_axis_off()
legend_items = []
existing_types = set(clipped["land_type"])
for land_type, color in color_map.items():
if land_type in existing_types:
legend_items.append(Patch(facecolor=color, edgecolor="#666666", label=land_type))
ax.legend(
handles=legend_items,
title="用地类型",
loc="lower left",
frameon=True,
fontsize=9,
title_fontsize=10
)
out_file = os.path.join(output_dir, f"{district_name}_用地类型图.png")
plt.tight_layout()
plt.savefig(out_file, dpi=300, bbox_inches="tight")
plt.close()
print(f"已导出:{out_file}")
到这里,一个基础版 Python 地理处理自动化出图脚本就完成了。它可以批量生成行政区专题图,并保持相同的国土空间规划配色方案、图例规则和导出参数。
常见坑:自动化出图不准、不美观、导出失败怎么排查
坑一:坐标系不一致导致裁剪结果为空
如果用地图层和行政区边界坐标系不同,直接进行 overlay 可能会得到空结果,或者裁剪位置明显错位。处理方法是先检查 CRS,并把辅助图层转换到主图层坐标系。
print(land.crs)
print(district.crs)
if land.crs != district.crs:
district = district.to_crs(land.crs)
坑二:中文字段或中文文件名乱码
Shapefile 对中文字段名和编码支持较弱,容易出现乱码或字段名被截断。建议项目数据优先使用 GeoPackage,文件后缀为 .gpkg。如果必须使用 Shapefile,应确认编码,并避免过长字段名。
坑三:图例类别太多,地图看起来很乱
自动图例不是越全越好。如果分类超过 15 个,报告读者很难快速理解。可以考虑合并小类,或者分成多张专题图,例如建设用地专题图、生态空间专题图、农业空间专题图。
坑四:面边线太粗,导出后像“黑块”
大量小图斑叠加时,边线宽度过大会严重影响效果。可以把 linewidth 调低到 0.05 到 0.2,或者在小比例尺总览图中取消图斑边线。
坑五:空间叠加速度慢
如果数据量很大,gpd.overlay 可能比较慢。可以先按边界外包框粗筛,再做精确裁剪;也可以安装空间索引依赖,并尽量使用 GeoPackage 或 Parquet 这类更适合批处理的数据格式。
方法比较:Python、QGIS、ArcGIS Pro 哪种出图方式更适合
| 方法 | 适合场景 | 优点 | 限制 |
|---|---|---|---|
| Python GeoPandas + Matplotlib | 批量专题图、快速报告插图、数据检查图 | 脚本可复现,批量处理方便,适合自动化流水线 | 高级版式、复杂标注和地图整饰需要额外开发 |
| QGIS 布局管理器 | 正式制图、地图册、需要人工微调的专题图 | 制图能力强,样式配置直观,支持地图集 | 批量规则复杂时仍需要 PyQGIS 辅助 |
| ArcGIS Pro 布局与 ArcPy | 规范化生产、企业级 GIS 项目、制图模板复用 | 布局模板成熟,ArcPy 自动化能力强 | 软件授权成本较高,环境部署相对重 |
| WebGIS 前端截图 | 在线地图展示、动态专题图预览 | 交互体验好,适合网页端发布 | 用于正式报告出图时,分辨率和版式控制较麻烦 |
如果你的目标是快速生成一批风格统一的专题图,Python 地理处理自动化出图非常合适。如果目标是正式图集出版,建议使用 Python 完成数据预处理和批量初稿,再进入 QGIS 或 ArcGIS Pro 做最终版式检查。
检查清单:运行脚本前后必须确认的事项
- 数据格式:优先使用 GeoPackage,减少 Shapefile 字段名和编码问题。
- 坐标系:所有参与裁剪、叠加和绘图的图层 CRS 必须明确。
- 分类字段:
land_type或项目实际字段不能有空值、错别字和混合写法。 - 配色方案:国土空间规划配色方案要统一存放,不要在多个脚本中重复手写。
- 未知类别:脚本应输出未匹配颜色的类别清单,避免图斑被默认灰色掩盖。
- 图层顺序:面层在下,边界线和重点要素在上。
- 导出分辨率:报告图建议使用 300 dpi,网页图可根据页面尺寸压缩。
- 文件命名:批量出图要避免特殊符号,建议使用行政区名加专题图类型。
- 结果复核:至少抽查几张图,确认范围、图例、颜色和标题都正确。
FAQ:Python 地理处理自动化出图常见问题
Python 自动化出图可以完全替代 QGIS 制图吗?
不建议这样理解。Python 适合批量、标准化、可复现的地图输出;QGIS 更适合人工精修、复杂标注和正式版式。实际项目中,两者结合效率最高。
国土空间规划配色方案有没有固定标准?
不同地区、不同项目和不同制图规范可能存在差异。本文提供的是常用示例配色,正式项目应优先采用地方技术指南、甲方模板或单位内部制图规范。
为什么我导出的地图没有图例?
常见原因是分类字段值和 color_map 中的键不一致。例如数据里是“城镇用地”,配色表里是“城镇建设用地”。可以先运行 value_counts() 检查真实字段值。
Python 批量出图能导出 PDF 吗?
可以。把 plt.savefig() 的输出路径改为 .pdf 即可,例如 plt.savefig("output/map.pdf", bbox_inches="tight")。如果要进入矢量排版软件继续编辑,PDF 或 SVG 会比 PNG 更合适。
大数据量图斑绘图很慢怎么办?
可以先按行政区裁剪,再绘图;也可以对小比例尺地图做简化处理,减少节点数量。对于非常大的数据集,可考虑使用 PostGIS 先完成裁剪、聚合和分类,再用 Python 读取结果出图。
自动化出图时如何保证每张图范围一致?
可以在绘图时固定 xlim 和 ylim,或者统一使用行政区边界的外包框加固定缓冲距离。批量制图时,范围规则必须写进脚本,而不是靠人工拖动地图窗口。
结论:把重复制图流程交给脚本,把精力留给判断
Python 地理处理自动化出图的重点不是炫技,而是把重复、标准化、容易出错的制图步骤固化下来。对于国土空间规划专题图,最值得自动化的部分包括数据读取、坐标系统一、规划用途配色、行政区批量裁剪和统一导出。
建议你先从本文的四步脚本开始:准备字段、配置国土空间规划配色方案、绘制单张图、扩展为批量出图。等流程稳定后,再逐步增加比例尺、指北针、标注、底图、图框和 PDF 模板。这样既能提升效率,也能让每一张图都有清晰、可追溯的生成过程。