Python空间分析如何快速出图?python画空间图实战技巧(附:Matplotlib与GeoPandas脚本)
引言:很多同学做完缓冲区、叠加分析、空间连接或栅格统计后,最后卡在“怎么把结果快速画成一张能汇报的图”。这篇文章围绕《Python空间分析如何快速出图?python画空间图实战技巧(附:Matplotlib与GeoPandas脚本)》这个问题,重点讲清楚用 GeoPandas 处理矢量数据、用 Matplotlib 控制图面样式、用少量脚本快速输出空间分析结果图的实战流程。
本文适合已经会一点 Python、正在使用 Shapefile、GeoPackage、GeoJSON 等 GIS 数据的读者。你不需要先掌握复杂制图系统,只要理解坐标系、字段、图层叠加和颜色分级,就可以完成常见的 Python 空间分析出图。

背景:为什么 Python空间分析 出图经常慢在最后一步
背景:在 GIS 项目里,Python 空间分析的计算环节往往并不难,真正耗时间的是把结果画清楚。常见场景包括:
- 做完行政区统计后,需要按指标分级设色。
- 做完 POI 缓冲区分析后,需要把点、缓冲区、边界叠加到一张图上。
- 做完道路或地块筛选后,需要快速导出一张 PNG 给同事确认。
- 批量分析多个城市或多个区县,需要自动出图而不是手动截图。
很多人会直接把结果导入 QGIS 或 ArcGIS Pro 再制图,这当然没问题。但如果你的分析流程本来就在 Python 里,使用 GeoPandas 和 Matplotlib 可以减少中间导入导出,尤其适合快速验证、批量出图和自动化报告。
原理:python画空间图的核心是 GeoDataFrame 加 Matplotlib 坐标轴
原理:GeoPandas 的核心数据结构是 GeoDataFrame,它可以理解为“带几何字段的表格”。每一行是一条空间要素,每个属性字段都可以用于筛选、分类和设色。
GeoPandas 的 plot() 方法底层调用 Matplotlib。也就是说,Python 空间分析出图通常分成两层:
- GeoPandas:负责读取空间数据、管理坐标系、执行空间叠加、空间连接、缓冲区等操作。
- Matplotlib:负责控制画布大小、标题、图例、颜色、字体、坐标轴、导出分辨率。
理解这一点后,python画空间图就不会停留在“能画出来”,而是可以进一步控制“图是否清楚、字段是否正确、图例是否可读、导出是否适合汇报”。
快速出图的关键不是把所有制图效果都堆上去,而是先保证坐标系正确、图层顺序正确、颜色表达正确、导出分辨率合适。
步骤:Python空间分析快速出图的完整脚本流程
步骤:下面用一个常见案例演示:读取行政区边界和 POI 点数据,统计每个行政区内的 POI 数量,并按数量分级设色出图。
1. 准备 Python 环境
建议使用 Conda 创建独立环境,避免 GeoPandas、Fiona、Shapely、PyProj 等依赖冲突。
conda create -n gisplot python=3.11
conda activate gisplot
conda install -c conda-forge geopandas matplotlib mapclassify
如果你使用 pip,也可以安装:
pip install geopandas matplotlib mapclassify
其中 mapclassify 用于自然断点、分位数等分级设色方法,在做统计专题图时很常用。
2. 读取空间数据并检查坐标系
假设有两个数据:
districts.gpkg:行政区面数据,字段中有name。poi.gpkg:POI 点数据。
import geopandas as gpd
import matplotlib.pyplot as plt
districts = gpd.read_file("data/districts.gpkg")
poi = gpd.read_file("data/poi.gpkg")
print(districts.crs)
print(poi.crs)
如果两个图层坐标系不一致,必须先统一。空间连接、叠加分析、距离计算都依赖坐标系。这里把 POI 转成行政区的坐标系:
poi = poi.to_crs(districts.crs)
3. 做空间连接并统计每个区的 POI 数量
使用 sjoin 判断点落在哪个行政区内,然后按行政区名称统计数量。
joined = gpd.sjoin(
poi,
districts[["name", "geometry"]],
how="left",
predicate="within"
)
poi_count = joined.groupby("name").size().reset_index(name="poi_count")
districts_stat = districts.merge(poi_count, on="name", how="left")
districts_stat["poi_count"] = districts_stat["poi_count"].fillna(0)
这一步完成后,districts_stat 就是一份带有统计字段的面图层,可以直接用于 Python 空间分析出图。
4. 用 GeoPandas 快速画专题图
最简版本如下:
fig, ax = plt.subplots(figsize=(8, 8))
districts_stat.plot(
column="poi_count",
ax=ax,
legend=True,
cmap="YlOrRd",
edgecolor="#666666",
linewidth=0.5
)
ax.set_title("各行政区 POI 数量分布", fontsize=16)
ax.set_axis_off()
plt.tight_layout()
plt.savefig("output/poi_count_map.png", dpi=300)
plt.show()
这段脚本已经可以完成一张基础的统计专题图。column 指定用于设色的字段,cmap 指定色带,legend=True 输出图例,dpi=300 适合常规报告或文章配图。
5. 叠加点图层,让结果更直观
如果只看面统计,有时读者不知道 POI 的空间分布细节。可以在面图层上叠加点图层:
fig, ax = plt.subplots(figsize=(9, 9))
districts_stat.plot(
column="poi_count",
ax=ax,
legend=True,
cmap="YlOrRd",
edgecolor="#555555",
linewidth=0.6,
alpha=0.85
)
poi.plot(
ax=ax,
color="#1f78b4",
markersize=8,
alpha=0.6
)
ax.set_title("POI 数量分布与点位叠加图", fontsize=16)
ax.set_axis_off()
plt.tight_layout()
plt.savefig("output/poi_count_with_points.png", dpi=300, bbox_inches="tight")
plt.show()
图层顺序很重要。通常先画面,再画线,最后画点。否则点可能被面图层盖住。
6. 使用分级方法改善专题图效果
默认连续色带有时不适合汇报。可以使用 scheme 参数进行分级设色,例如分位数分级:
fig, ax = plt.subplots(figsize=(9, 9))
districts_stat.plot(
column="poi_count",
ax=ax,
legend=True,
cmap="OrRd",
scheme="Quantiles",
k=5,
edgecolor="white",
linewidth=0.6,
legend_kwds={
"title": "POI数量",
"loc": "lower left"
}
)
ax.set_title("各行政区 POI 数量分级图", fontsize=16)
ax.set_axis_off()
plt.tight_layout()
plt.savefig("output/poi_count_quantiles.png", dpi=300, bbox_inches="tight")
plt.show()
scheme="Quantiles" 表示按分位数分级,k=5 表示分成 5 级。对于空间分析成果图,这比默认连续渐变更容易解释。
7. 处理中文标题和中文图例乱码
Matplotlib 在部分系统中会出现中文乱码。可以设置中文字体:
import matplotlib.pyplot as plt
plt.rcParams["font.sans-serif"] = ["SimHei"]
plt.rcParams["axes.unicode_minus"] = False
如果是 macOS,可以尝试:
plt.rcParams["font.sans-serif"] = ["Arial Unicode MS"]
plt.rcParams["axes.unicode_minus"] = False
如果服务器没有中文字体,建议先安装字体,或者在出图脚本中指定字体文件。否则自动批量出图时很容易出现标题为空框或方块。
常见坑:Python空间分析出图不准、不美观、导出模糊怎么办
常见坑:下面这些问题在 python画空间图时非常常见,尤其是刚从桌面 GIS 转到 Python 的读者。
坑 1:经纬度坐标系下直接做距离和缓冲区
如果数据是 EPSG:4326,单位是度,不适合直接做米级缓冲区或面积计算。应该先投影到合适的平面坐标系,例如本地高斯克吕格、UTM 或项目指定投影。
print(districts.crs)
districts_proj = districts.to_crs(epsg=3857)
poi_proj = poi.to_crs(epsg=3857)
注意:EPSG:3857 适合 Web 地图显示,不一定适合严肃面积统计。正式项目应选择本地适用投影。
坑 2:图层坐标系不一致导致空间连接结果为空
如果 gpd.sjoin() 后结果大量为空,优先检查:
- 两个图层是否有 CRS。
- 两个图层 CRS 是否一致。
- 点是否真的落在面范围内。
- 几何是否存在无效或空几何。
print(districts.crs)
print(poi.crs)
print(districts.total_bounds)
print(poi.total_bounds)
total_bounds 可以快速检查两个图层的空间范围是否明显错位。
坑 3:导出的图很模糊
导出模糊通常和 dpi、画布大小、保存参数有关。建议:
- 报告插图使用
dpi=300。 - 需要大图时增大
figsize。 - 使用
bbox_inches="tight"减少无效白边。
plt.savefig(
"output/map_high_quality.png",
dpi=300,
bbox_inches="tight",
facecolor="white"
)
坑 4:颜色好看但表达错误
专题图不是越鲜艳越好。颜色应匹配数据含义:
- 数量、密度、强度:适合单色渐变,如
YlOrRd。 - 正负变化:适合发散色带,如
RdBu。 - 类别类型:适合离散颜色,而不是连续渐变。
如果用连续色带表达行政类别、土地类型、设施类型,读者会误以为类别之间存在大小顺序。
坑 5:边界线太粗导致小区域看不清
行政区很多时,边界线过粗会压住填充色。可以调低 linewidth,或者使用白色细线增强区分:
districts_stat.plot(
column="poi_count",
edgecolor="white",
linewidth=0.3,
cmap="YlOrRd",
legend=True
)
方法比较:Matplotlib、GeoPandas、Contextily、QGIS 哪个更适合快速出图
方法比较:Python 空间分析出图并不只有一种方式。选择工具时,要看你的目标是快速验证、批量出图、论文制图,还是交互式展示。
| 方法 | 适合场景 | 优点 | 限制 |
|---|---|---|---|
| GeoPandas plot | 快速查看矢量结果、统计专题图 | 代码少,和空间分析流程衔接自然 | 高级制图能力有限 |
| Matplotlib | 控制标题、图例、布局、导出质量 | 可定制性强,适合自动化报告 | 地图专用元素需要手动处理 |
| Contextily | 叠加在线底图 | 适合城市尺度展示,空间参照更直观 | 通常需要 Web Mercator 坐标系,受网络和底图版权影响 |
| QGIS | 精细制图、地图整饰、人工排版 | 制图能力强,适合最终成果图 | 批量自动化需要额外配置 |
| Folium 或 Kepler.gl | 交互式地图展示 | 适合网页查看和探索分析 | 不一定适合静态论文或报告插图 |
如果只是 Python 空间分析快速出图,建议优先使用 GeoPandas 加 Matplotlib;如果要做正式地图版面,再把结果导入 QGIS 或 ArcGIS Pro 精修。
进阶脚本:叠加在线底图并导出空间分析结果图
如果需要让地图更容易被非 GIS 读者理解,可以叠加在线底图。常用库是 contextily。
pip install contextily
使用在线底图时,通常需要把数据转换到 Web Mercator 坐标系 EPSG:3857:
import geopandas as gpd
import matplotlib.pyplot as plt
import contextily as ctx
districts = gpd.read_file("data/districts.gpkg")
poi = gpd.read_file("data/poi.gpkg")
districts_3857 = districts.to_crs(epsg=3857)
poi_3857 = poi.to_crs(epsg=3857)
fig, ax = plt.subplots(figsize=(9, 9))
districts_3857.boundary.plot(
ax=ax,
color="red",
linewidth=1
)
poi_3857.plot(
ax=ax,
color="blue",
markersize=10,
alpha=0.7
)
ctx.add_basemap(ax, source=ctx.providers.OpenStreetMap.Mapnik)
ax.set_title("POI 点位与行政区边界叠加图", fontsize=16)
ax.set_axis_off()
plt.tight_layout()
plt.savefig("output/poi_basemap.png", dpi=300, bbox_inches="tight")
plt.show()
需要注意,在线底图涉及网络访问、服务稳定性和版权条款。正式项目中应确认底图来源是否允许用于报告或公开发布。
检查清单:python画空间图前后要检查什么
检查清单:每次用 Python 空间分析出图前,建议按下面顺序检查,能避免大多数低级错误。
- 数据是否读入成功:检查
head()、字段名和几何类型。 - 坐标系是否存在:检查
gdf.crs是否为空。 - 图层坐标系是否一致:叠加、空间连接前必须统一 CRS。
- 空间范围是否合理:用
total_bounds检查是否错位。 - 统计字段是否为空:分级设色前检查字段是否全是空值或 0。
- 分级方法是否适合:数量型字段可用分位数、自然断点或等距分级。
- 图层顺序是否正确:一般先面、后线、最后点。
- 中文字体是否正常:标题、图例、标注不能乱码。
- 导出分辨率是否足够:报告图建议
dpi=300。 - 输出文件夹是否存在:批量出图时要提前创建输出目录。
批量出图时,可以加上目录创建逻辑:
from pathlib import Path
output_dir = Path("output")
output_dir.mkdir(exist_ok=True)
plt.savefig(output_dir / "map.png", dpi=300, bbox_inches="tight")
FAQ:Python空间分析快速出图常见问题
FAQ:下面整理几个读者在使用 GeoPandas 和 Matplotlib 出图时经常遇到的问题。
1. Python空间分析出图一定要用 GeoPandas 吗?
不一定。如果你处理的是栅格数据,可能会用 Rasterio、rioxarray 和 Matplotlib;如果做交互式 Web 地图,可能会用 Folium、Plotly 或 Kepler.gl。但对于 Shapefile、GeoPackage、GeoJSON 等矢量数据,GeoPandas 是最直接的选择。
2. python画空间图为什么图层叠不上?
最常见原因是坐标系不一致。先检查 crs 和 total_bounds。如果一个图层范围是经纬度数值,另一个是米级投影坐标,直接叠加就会错位。
3. GeoPandas plot 可以做专业制图吗?
可以完成基础专题图、分析结果图和批量报告图,但如果需要比例尺、指北针、复杂标注、地图整饰和印刷级版面,QGIS 或 ArcGIS Pro 更合适。实际工作中常见做法是 Python 自动分析和初步出图,桌面 GIS 做最终排版。
4. Matplotlib 图例太丑怎么办?
可以通过 legend_kwds 调整标题、位置和显示方式。对于更复杂的图例,可以用 Matplotlib 自定义图例对象。但快速出图阶段,建议先保证图例能解释字段含义,不必一开始追求复杂版式。
5. 为什么按字段设色后整张图颜色一样?
通常有三种原因:字段值全都一样、字段是字符串而不是数值、统计结果没有正确合并到空间图层。可以检查:
print(districts_stat["poi_count"].describe())
print(districts_stat["poi_count"].dtype)
print(districts_stat[["name", "poi_count"]].head())
6. 可以批量输出多个城市的空间分析图吗?
可以。把读取数据、空间分析、出图保存封装成函数,然后循环城市列表即可。批量出图时尤其要注意关闭画布,避免内存占用持续增加。
for city in city_list:
fig, ax = plt.subplots(figsize=(8, 8))
city_gdf = districts_stat[districts_stat["city"] == city]
city_gdf.plot(column="poi_count", ax=ax, legend=True, cmap="YlOrRd")
ax.set_title(f"{city} POI数量分布")
ax.set_axis_off()
plt.savefig(f"output/{city}_poi_count.png", dpi=300, bbox_inches="tight")
plt.close(fig)
结论:用 GeoPandas 加 Matplotlib 建立可复用的出图模板
结论:Python空间分析快速出图的核心思路很简单:用 GeoPandas 管理空间数据和分析结果,用 Matplotlib 控制图面表达和导出质量。只要把坐标系、图层顺序、字段设色、图例和分辨率这几个点处理好,就能稳定产出清晰可用的空间分析结果图。
对于日常 GIS 学习和项目初稿,建议先建立一套自己的 python画空间图模板:读取数据、统一坐标系、执行分析、分级设色、叠加图层、导出 PNG。后续无论是 POI 分析、行政区统计、设施覆盖评估,还是批量城市对比,都可以在这个模板上快速改造。
如果最终成果需要发表、打印或交付甲方,可以把 Python 生成的统计结果继续导入 QGIS 或 ArcGIS Pro 做精细排版。这样既保留 Python 空间分析的自动化效率,也能获得更规范的地图制图效果。