QGIS制图效率太低?自动化出图脚本分享(附:Python代码)
如果你正在被“QGIS制图效率太低?自动化出图脚本分享(附:Python代码)”这个问题困扰,通常不是你操作不熟,而是制图流程里有太多重复动作:套模板、改图层样式、缩放到范围、刷新图例、导出 PDF 或 PNG。本文以 QGIS 自动化出图为核心,分享一个可直接改造的 PyQGIS 脚本,帮助你批量生成地图成果。

引言:为什么 QGIS 自动化出图值得做
在实际项目里,很多 GIS 工作并不是“做一张图”,而是“按同一规范做几十张甚至几百张图”。例如行政区专题图、地块位置图、监测点分布图、项目范围图、管线分幅图等。
如果每一张图都手动完成以下操作,效率会非常低:
- 打开 QGIS 工程文件。
- 筛选一个行政区、项目区或图幅范围。
- 调整地图画布范围。
- 修改标题、日期、编号、比例尺等文本。
- 进入布局管理器导出图片或 PDF。
- 重复上述步骤。
QGIS 自动化出图的价值就在于:把这些重复、规则明确的步骤交给脚本执行。你只需要准备好数据、模板和少量参数,PyQGIS 就可以批量完成地图布局和导出。
背景:QGIS制图效率太低通常卡在哪里
QGIS 手工制图效率低,常见原因不是软件本身慢,而是制图流程没有标准化。尤其是当制图成果需要保持统一样式时,重复劳动会被放大。
典型低效场景
- 批量行政区出图:每个区县一张专题图,需要逐个缩放、改标题、导出。
- 批量地块位置图:每个项目地块一张图,需要按地块范围生成成果。
- 批量监测点分布图:按站点、流域或行政区分组出图。
- 批量图幅出图:按标准图框或网格范围导出地图。
- 成果格式统一:每张图都要包含标题、图例、比例尺、指北针和数据来源。
适合自动化的前提
不是所有制图任务都适合脚本化。适合 QGIS 批量制图脚本处理的任务,一般具备以下特征:
- 每张图的布局结构相同。
- 图层样式可以提前配置好。
- 每张图只是范围、标题、筛选条件或输出文件名不同。
- 数据字段中有唯一编号、名称或分组字段。
- 导出格式固定,例如 PNG、PDF 或 SVG。
如果每一张图都需要大量人工审美调整,例如复杂专题地图、出版级地图集,则脚本可以承担基础出图,但最终仍需要人工校核。
原理:PyQGIS 自动化出图到底控制了什么
PyQGIS 是 QGIS 的 Python API。简单理解,它允许你用 Python 控制 QGIS 工程、图层、布局、地图范围、文本元素和导出过程。
一次标准的 QGIS 自动化出图,通常包括以下几个对象:
- QGIS 工程:保存图层、样式、布局和数据源连接。
- 矢量图层:例如行政区、地块、道路、河流、监测点。
- 布局 Layout:相当于打印版面,包含地图框、标题、图例、比例尺等元素。
- 地图项 Map Item:布局中真正显示地图内容的区域。
- 文本项 Label Item:用于动态更新标题、编号、日期等文字。
- 导出器 Exporter:负责把布局导出为图片或 PDF。
脚本的核心逻辑并不复杂:遍历每一个要出图的对象,获取它的空间范围,把布局中的地图框缩放到该范围,更新标题,然后导出文件。
建议先在 QGIS 图形界面中把工程、符号系统和布局模板调好,再用脚本做批量导出。不要试图一开始就用代码完成所有制图细节。
步骤:准备 QGIS 自动化出图工程
步骤 1:整理数据字段
本文示例假设你有一个面图层,用于按每个要素自动出图。该图层可以是行政区、地块、项目范围或网格图幅。
建议至少包含以下字段:
| 字段名 | 用途 | 示例 |
|---|---|---|
| name | 地图标题或对象名称 | 东城区 |
| code | 输出文件名编号 | 110101 |
| type | 可选,用于分类或筛选 | 行政区 |
字段名可以不同,但脚本中要对应修改。为了避免中文字段编码问题,自动化脚本里建议优先使用英文小写字段名。
步骤 2:在 QGIS 中设置图层样式
打开 QGIS 工程后,先把所有图层样式设置好,例如:
- 行政区边界线颜色和宽度。
- 地块填充色和透明度。
- 道路、水系、居民地等底图符号。
- 标签字体、大小、避让规则。
- 图层显示顺序。
样式设置完成后,保存为 QGIS 工程文件,例如:
D:/gis_project/qgis_batch_map/project.qgz
步骤 3:创建布局模板
在 QGIS 中打开“项目”菜单,进入“新建打印布局”,创建一个布局,例如命名为:
AutoMapLayout
在布局中至少放置以下元素:
- 一个地图框,项目 ID 设置为 map_main。
- 一个标题文本,项目 ID 设置为 title_label。
- 一个比例尺。
- 一个指北针。
- 一个图例,可根据需要设置为固定图例或自动图例。
项目 ID 很重要。脚本会通过这些 ID 找到布局元素并修改它们。如果 ID 写错,脚本就无法更新对应对象。
步骤 4:确认图层名称
在 QGIS 图层面板中确认用于批量出图的图层名称。本文示例使用:
export_units
也就是说,脚本会遍历名为 export_units 的面图层,并对每一个要素生成一张地图。
步骤:QGIS 批量制图 Python 代码
下面这段脚本适合在 QGIS Python 控制台中运行,也可以保存为 .py 文件后通过 QGIS 的 Python 环境执行。第一次使用建议先在 QGIS Python 控制台中测试,便于查看报错信息。
from qgis.core import (
QgsProject,
QgsLayoutExporter,
QgsRectangle
)
import os
import re
# ========== 用户需要修改的参数 ==========
project_path = r"D:/gis_project/qgis_batch_map/project.qgz"
output_dir = r"D:/gis_project/qgis_batch_map/output"
layout_name = "AutoMapLayout"
map_item_id = "map_main"
title_item_id = "title_label"
export_layer_name = "export_units"
name_field = "name"
code_field = "code"
# 地图范围外扩比例,0.10 表示向四周扩大 10%
buffer_ratio = 0.10
# 导出格式:png 或 pdf
export_format = "png"
# ========== 工具函数 ==========
def safe_filename(text):
"""清理文件名中的非法字符"""
text = str(text)
text = re.sub(r'[/:*?"<>|]', "_", text)
return text.strip()
def expand_extent(extent, ratio):
"""按比例扩大地图范围"""
width = extent.width()
height = extent.height()
# 避免点状或极小范围导致范围异常
if width == 0:
width = 1
if height == 0:
height = 1
x_buffer = width * ratio
y_buffer = height * ratio
return QgsRectangle(
extent.xMinimum() - x_buffer,
extent.yMinimum() - y_buffer,
extent.xMaximum() + x_buffer,
extent.yMaximum() + y_buffer
)
# ========== 加载工程 ==========
project = QgsProject.instance()
project.read(project_path)
if not os.path.exists(output_dir):
os.makedirs(output_dir)
# ========== 获取图层 ==========
layers = project.mapLayersByName(export_layer_name)
if not layers:
raise Exception(f"找不到图层:{export_layer_name}")
export_layer = layers[0]
# ========== 获取布局 ==========
layout_manager = project.layoutManager()
layout = layout_manager.layoutByName(layout_name)
if layout is None:
raise Exception(f"找不到布局:{layout_name}")
map_item = layout.itemById(map_item_id)
if map_item is None:
raise Exception(f"找不到地图框项目 ID:{map_item_id}")
title_item = layout.itemById(title_item_id)
if title_item is None:
raise Exception(f"找不到标题项目 ID:{title_item_id}")
# ========== 批量出图 ==========
exporter = QgsLayoutExporter(layout)
for feature in export_layer.getFeatures():
name_value = feature[name_field]
code_value = feature[code_field]
map_title = f"{name_value}位置示意图"
file_name = f"{safe_filename(code_value)}_{safe_filename(name_value)}"
# 获取当前要素范围,并适当外扩
extent = feature.geometry().boundingBox()
extent = expand_extent(extent, buffer_ratio)
# 设置地图框范围
map_item.zoomToExtent(extent)
# 更新标题
title_item.setText(map_title)
# 刷新布局
layout.refresh()
# 导出
if export_format.lower() == "png":
output_path = os.path.join(output_dir, file_name + ".png")
settings = QgsLayoutExporter.ImageExportSettings()
settings.dpi = 300
result = exporter.exportToImage(output_path, settings)
elif export_format.lower() == "pdf":
output_path = os.path.join(output_dir, file_name + ".pdf")
settings = QgsLayoutExporter.PdfExportSettings()
result = exporter.exportToPdf(output_path, settings)
else:
raise Exception("export_format 只支持 png 或 pdf")
if result == QgsLayoutExporter.Success:
print(f"导出成功:{output_path}")
else:
print(f"导出失败:{output_path}")
print("全部完成。")
代码怎么改成自己的项目
你通常只需要修改脚本开头的几个参数:
project_path:你的 QGIS 工程文件路径。output_dir:成果输出目录。layout_name:QGIS 布局名称。map_item_id:布局中地图框的项目 ID。title_item_id:布局中标题文本的项目 ID。export_layer_name:用于遍历出图对象的图层名称。name_field和code_field:用于标题和文件名的字段。buffer_ratio:地图范围外扩比例。export_format:导出为 PNG 或 PDF。
步骤:按行政区筛选后再自动出图
有些场景下,你不只是要缩放到某个要素范围,还希望每次出图时只显示当前行政区或当前地块。这时可以给图层设置子集过滤条件。
例如,假设专题图层中也有 code 字段,你可以在循环中加入类似逻辑:
# 示例:只显示当前 code 对应的数据
current_code = str(feature[code_field])
for layer_name in ["export_units", "thematic_data"]:
target_layers = project.mapLayersByName(layer_name)
if target_layers:
lyr = target_layers[0]
lyr.setSubsetString(f"code = '{current_code}'")
导出完成后,如果还要继续在 QGIS 中手工查看完整数据,可以在脚本最后清除过滤:
for layer_name in ["export_units", "thematic_data"]:
target_layers = project.mapLayersByName(layer_name)
if target_layers:
target_layers[0].setSubsetString("")
需要注意,字段类型会影响表达式写法。如果 code 是文本字段,需要加单引号;如果是整数型字段,通常不需要单引号。
常见坑:QGIS 自动化出图失败的排查重点
1. 找不到布局或地图框
如果报错提示找不到 AutoMapLayout、map_main 或 title_label,优先检查布局名称和项目 ID。
- 布局名称不是窗口标题,而是布局管理器中的名称。
- 项目 ID 需要在布局元素属性中手动填写。
- 地图框和标题文本的 ID 不能重复。
2. 导出的地图范围不对
地图范围不对通常与坐标系、要素范围或地图框刷新有关。建议检查:
- 出图图层是否有正确几何。
- 工程坐标系是否与数据坐标系一致或可正确投影。
- 是否对范围进行了合理外扩。
- 是否调用了
layout.refresh()。
如果你的数据是经纬度坐标系,地图范围外扩比例可以使用;但如果需要按米精确外扩,建议先使用投影坐标系,例如 CGCS2000 高斯投影、UTM 或地方平面坐标系。
3. 中文路径或中文字段导致异常
现代 QGIS 对中文支持已经比较好,但为了减少环境差异带来的问题,建议:
- 项目路径尽量使用英文目录。
- 脚本字段名尽量使用英文。
- 输出文件名可以包含中文,但要清理非法字符。
- 不要把工程文件放在权限受限目录,例如系统盘特殊文件夹。
4. 图例没有按预期更新
自动图例有时会显示不需要的图层,尤其是复杂工程。解决方法有两个:
- 在布局中关闭自动更新,手动保留固定图例项。
- 通过图层可见性或图例过滤控制显示内容。
如果你的批量图只需要统一图例,固定图例往往更稳定。
5. 批量导出速度仍然很慢
QGIS 批量出图慢,常见原因包括底图服务加载慢、图层符号过于复杂、标签计算量过大、数据量过大等。
- 尽量不要在批量导出中依赖在线瓦片底图。
- 大数据图层提前裁剪到项目范围。
- 复杂符号和透明叠加要谨慎使用。
- 不必要的图层在导出前关闭。
- 栅格底图可提前建立金字塔或切片。
方法比较:手工制图、地图集和 PyQGIS 脚本怎么选
| 方法 | 适用场景 | 优点 | 局限 |
|---|---|---|---|
| 手工制图 | 少量地图、需要精细设计 | 灵活,适合人工审美调整 | 重复出图效率低,容易操作不一致 |
| QGIS 地图集 | 按要素批量出图,布局规则稳定 | 无需写代码,适合常规批量地图 | 复杂逻辑和多图层联动控制不够灵活 |
| PyQGIS 脚本 | 批量出图、动态标题、筛选图层、批处理任务 | 自动化程度高,可扩展性强 | 需要了解 Python 和 QGIS API |
| 处理模型器 | 空间处理流程自动化 | 适合缓冲区、叠加、裁剪等分析流程 | 对复杂布局导出控制不如 PyQGIS 灵活 |
如果你完全不想写代码,可以先尝试 QGIS 地图集。如果你需要根据字段动态筛选多个图层、修改多个布局元素、按规则输出不同格式,那么 PyQGIS 脚本更适合。
检查清单:运行 QGIS 批量制图脚本前先确认这些项
- QGIS 工程文件可以正常打开。
- 所有数据源路径没有丢失。
- 批量出图图层名称与脚本一致。
- 用于标题和文件名的字段存在且没有空值。
- 布局名称与脚本中的
layout_name一致。 - 地图框项目 ID 已设置为
map_main或脚本指定值。 - 标题文本项目 ID 已设置为
title_label或脚本指定值。 - 输出目录存在,或脚本有权限创建目录。
- 地图比例、图例、比例尺、指北针在模板中已经调整好。
- 先测试导出 1 到 3 张图,再批量运行全部任务。
FAQ:QGIS 自动化出图常见问题
QGIS 自动化出图必须会 Python 吗?
不一定。如果只是按一个覆盖图层逐页出图,QGIS 地图集功能就能完成很多任务。但如果你要做复杂的 QGIS 批量制图脚本,例如动态筛选多个图层、自动命名文件、按条件导出不同格式,就需要使用 PyQGIS。
这段 Python 代码可以在独立 Python 里运行吗?
不建议初学者直接在系统 Python 中运行。PyQGIS 依赖 QGIS 自带环境,最稳妥的方式是在 QGIS Python 控制台中运行,或者使用 QGIS 安装目录提供的 Python 环境。
QGIS 批量导出 PDF 和 PNG 哪个更好?
如果成果用于打印、归档或进一步排版,PDF 更合适。如果成果用于网页展示、报告插图或快速预览,PNG 更方便。脚本中可以通过 export_format 参数切换。
为什么导出的图和 QGIS 画布看到的不一样?
自动化出图导出的是布局,不是主画布。你需要检查布局中的地图框范围、图层可见性、比例尺、主题和样式是否正确。有时主画布显示正常,但布局地图框没有刷新,也会导致导出结果不一致。
能不能按固定比例尺自动出图?
可以。当前示例使用 zoomToExtent 按要素范围缩放。如果你希望固定比例尺,可以在设置范围后再调用地图项的比例尺相关方法,或在模板中控制地图框比例。实际项目中,固定比例尺更适合标准图幅,按范围缩放更适合项目位置图。
如何让每张图只显示当前地块?
可以在循环中使用 setSubsetString 设置图层过滤条件,让图层只显示当前编号对应的数据。导出完成后再清除过滤条件。这样可以避免其他地块干扰当前地图表达。
QGIS 自动化出图适合超大数据吗?
可以使用,但要先优化数据。超大矢量数据建议使用 GeoPackage、PostGIS 或建立空间索引;栅格数据建议建立金字塔;在线底图不建议作为批量导出的关键依赖。
结论:先模板化,再脚本化,QGIS制图效率会明显提升
QGIS制图效率太低的根本原因,往往是重复流程没有被模板化和自动化。正确做法是先在 QGIS 中完成稳定的制图模板,再用 PyQGIS 脚本批量控制范围、标题、筛选条件和导出文件。
本文提供的 QGIS 自动化出图脚本适合作为起点。你可以先用一个面图层测试批量导出,再逐步加入图层过滤、固定比例尺、多格式输出、日志记录等功能。对 GIS 学生、初级工程师和空间数据分析人员来说,掌握这类 QGIS 批量制图脚本,能显著减少重复劳动,也能让制图成果更加统一、可复现。