GeoPandas绘图太丑?Matplotlib咋调?

GIS基础理论
Dr.GIS
wowwwai GIS研习社 · 工具流程与项目排障

GeoPandas绘图太丑?Matplotlib咋调? 这是很多 GIS 初学者第一次用 GeoPandas 出图时遇到的问题:数据能画出来,但颜色像默认测试图,图例挤在一起,坐标轴很碍眼,行政区边界不清楚,导出图片还发糊。其实 GeoPandas 的绘图底层主要依赖 Matplotlib,只要掌握几个关键参数,就能把“能看”的地图调成“能交作业、能放报告”的专题图。

GeoPandas绘图太丑 Matplotlib调整GeoPandas地图样式示例
GeoPandas 默认绘图与使用 Matplotlib 调整后的专题地图效果对比。

引言:GeoPandas绘图为什么看起来“太丑”

GeoPandas 的 GeoDataFrame.plot() 非常适合快速查看空间数据,但它默认不是为正式制图设计的。默认样式通常只解决一个问题:把几何对象画出来。

如果你想做的是课程作业图、项目汇报图、数据分析图,通常还需要进一步处理:

  • 调整地图配色,让不同等级更容易识别;
  • 设置边界线,避免面要素糊成一片;
  • 去掉不必要的坐标轴;
  • 添加标题、图例和注记;
  • 控制图片尺寸、分辨率和导出格式;
  • 保证坐标系和比例不变形。

本文用一个典型的面数据专题图流程,讲清楚 GeoPandas 绘图太丑时,应该如何用 Matplotlib 调整。

背景:GeoPandas绘图与Matplotlib是什么关系

GeoPandas 是 Python GIS 中常用的矢量数据处理库,常用于读取 Shapefile、GeoJSON、GeoPackage 等空间数据。Matplotlib 是 Python 里最常用的绘图库。GeoPandas 的 plot() 方法本质上会把空间几何交给 Matplotlib 的坐标轴对象进行绘制。

也就是说,GeoPandas 负责“地图数据怎么画”,Matplotlib 负责“图面怎么排版”。

很多人只写下面这一句:

gdf.plot()

这样确实能看到地图,但通常会有几个问题:

  • 默认颜色没有表达数据含义;
  • 图例没有标题,或者位置不好;
  • 坐标轴显示经纬度或投影坐标,看起来很乱;
  • 图像比例不适合论文、PPT 或公众号配图;
  • 导出图片分辨率过低;
  • 中文标题或中文图例可能乱码。

所以,解决 GeoPandas 绘图太丑的核心思路不是换一个软件,而是把 GeoDataFrame.plot() 和 Matplotlib 的 figaxlegendsavefig 配合起来。

原理:先让GeoPandas画地图,再让Matplotlib管版式

在 Matplotlib 中,一张图通常由两个核心对象组成:

  • Figure:整张画布,可以理解为最终图片;
  • Axes:具体绘图区域,可以理解为地图所在的坐标框。

GeoPandas 的 plot() 可以接收一个 ax 参数,把地图画到指定的 Matplotlib 坐标轴上。这样我们就可以控制图像大小、标题、坐标轴、图例、边距和导出效果。

import geopandas as gpd
import matplotlib.pyplot as plt

gdf = gpd.read_file("data/city_districts.shp")

fig, ax = plt.subplots(figsize=(8, 6))
gdf.plot(ax=ax)
plt.show()

这段代码比直接 gdf.plot() 多了一个关键步骤:我们手动创建了 figax。后面所有美化操作,基本都围绕这两个对象展开。

步骤:用Matplotlib调整GeoPandas地图样式

步骤1:读取数据并检查坐标系

正式绘图前,先检查数据是否能正常读取,以及坐标系是否正确。坐标系错误会导致地图变形、比例异常,甚至不同图层叠不到一起。

import geopandas as gpd
import matplotlib.pyplot as plt

gdf = gpd.read_file("data/city_districts.shp")

print(gdf.head())
print(gdf.crs)

如果是做面积、距离或城市范围专题图,建议使用合适的投影坐标系,而不是直接用经纬度坐标系。比如中国区域项目常见情况是先确认数据坐标,再根据项目范围选择合适投影。

# 示例:如果需要,可转换到已有项目指定的投影坐标系
# gdf = gdf.to_crs("EPSG:3857")

注意:不要盲目转换坐标系。真实项目中应以数据来源说明、项目规范或地方坐标标准为准。

步骤2:设置画布大小和地图比例

默认图像尺寸往往不适合展示。可以用 figsize 控制画布宽高,用 ax.set_aspect("equal") 尽量保持地图比例。

fig, ax = plt.subplots(figsize=(9, 7))

gdf.plot(
    ax=ax,
    color="#d9e8f5",
    edgecolor="#4a4a4a",
    linewidth=0.6
)

ax.set_aspect("equal")
plt.show()

这里的几个参数很常用:

  • color:面填充颜色;
  • edgecolor:边界线颜色;
  • linewidth:边界线宽度;
  • figsize:整张图的大小。

对行政区、地块、网格等面数据来说,边界线非常重要。没有边界线时,多个面要素容易看成一整块。

步骤3:按字段做专题图配色

如果地图需要表达某个指标,比如人口、GDP、POI 数量、风险等级,就不要只用单一颜色。GeoPandas 可以通过 column 参数按字段渲染。

fig, ax = plt.subplots(figsize=(9, 7))

gdf.plot(
    column="population",
    ax=ax,
    cmap="YlOrRd",
    legend=True,
    edgecolor="#ffffff",
    linewidth=0.5
)

ax.set_title("各区人口分布图", fontsize=16, pad=12)
ax.set_axis_off()

plt.show()

常见配色建议:

  • 连续数值:YlOrRdBluesGreens
  • 正负差异:RdBucoolwarm
  • 分类数据:Set2tab20
  • 避免过度使用彩虹色:很多时候不利于阅读。

如果你的字段是中文或分类字段,也可以直接用于分类制图,但要注意图例可能较长,需要调整位置。

步骤4:调整图例,让专题图更像正式成果

GeoPandas 的 legend=True 很方便,但默认图例不一定美观。可以通过 legend_kwds 设置图例标题、方向和缩放。

fig, ax = plt.subplots(figsize=(9, 7))

gdf.plot(
    column="population",
    ax=ax,
    cmap="YlOrRd",
    legend=True,
    edgecolor="#ffffff",
    linewidth=0.5,
    legend_kwds={
        "label": "人口数量",
        "orientation": "vertical",
        "shrink": 0.65
    }
)

ax.set_title("各区人口分布图", fontsize=16, pad=12)
ax.set_axis_off()

plt.show()

如果图例太占地方,可以尝试:

  • 增大 figsize
  • 减少分类数量;
  • 使用横向图例;
  • 导出后在版式软件中再做精细排版;
  • 对分类字段先合并过细的类别。

步骤5:去掉坐标轴、设置标题和边距

很多 GIS 专题图并不需要直接显示坐标轴。尤其是行政区分布图、统计专题图、空间分析结果图,坐标轴经常会干扰阅读。

fig, ax = plt.subplots(figsize=(9, 7))

gdf.plot(
    column="population",
    ax=ax,
    cmap="YlOrRd",
    legend=True,
    edgecolor="#ffffff",
    linewidth=0.5
)

ax.set_title("各区人口分布图", fontsize=16, pad=14)
ax.set_axis_off()

plt.tight_layout()
plt.show()

plt.tight_layout() 可以自动调整边距,减少标题、图例和图像之间的挤压。但在复杂地图中,它不是万能的。如果图例仍然被裁切,需要手动调整画布大小或使用 bbox_inches="tight" 导出。

步骤6:处理中文字体乱码

如果 Matplotlib 中的中文标题显示为方框,说明当前环境没有正确设置中文字体。可以在脚本开头指定字体。

import matplotlib.pyplot as plt

plt.rcParams["font.sans-serif"] = ["SimHei"]
plt.rcParams["axes.unicode_minus"] = False

如果你使用的是 macOS 或 Linux,SimHei 不一定存在。可以改成系统中已有的中文字体。例如:

# macOS 常见可尝试字体
plt.rcParams["font.sans-serif"] = ["Arial Unicode MS"]

# Linux 服务器常见做法是先安装中文字体,再指定字体名称

在 Jupyter Notebook 中,如果改了字体仍不生效,可以重启 Kernel 后再运行。

步骤7:叠加边界、点位和标注

实际 GIS 出图常常不是单图层。比如底图是区县面,叠加采样点、站点或道路。可以多次调用 plot(),画到同一个 ax 上。

districts = gpd.read_file("data/city_districts.shp")
stations = gpd.read_file("data/stations.geojson")

stations = stations.to_crs(districts.crs)

fig, ax = plt.subplots(figsize=(9, 7))

districts.plot(
    ax=ax,
    color="#f2f2f2",
    edgecolor="#666666",
    linewidth=0.6
)

stations.plot(
    ax=ax,
    color="#d7191c",
    markersize=28,
    alpha=0.85
)

ax.set_title("监测站点空间分布图", fontsize=16, pad=12)
ax.set_axis_off()

plt.tight_layout()
plt.show()

多图层叠加时,最常见的问题是坐标系不一致。因此每次叠加前都建议检查:

print(districts.crs)
print(stations.crs)

如果坐标系不同,应使用 to_crs() 转成同一个坐标系。

步骤8:导出高清图片

很多人觉得 GeoPandas 绘图太丑,其实还有一个原因是导出图片分辨率太低。正式使用时,不建议直接截图,而应该用 savefig() 导出。

fig, ax = plt.subplots(figsize=(9, 7))

gdf.plot(
    column="population",
    ax=ax,
    cmap="YlOrRd",
    legend=True,
    edgecolor="#ffffff",
    linewidth=0.5,
    legend_kwds={
        "label": "人口数量",
        "shrink": 0.65
    }
)

ax.set_title("各区人口分布图", fontsize=16, pad=12)
ax.set_axis_off()

plt.savefig(
    "output/population_map.png",
    dpi=300,
    bbox_inches="tight",
    facecolor="white"
)

plt.show()

导出参数建议:

  • dpi=300:适合报告、论文和打印;
  • bbox_inches="tight":减少白边并避免图例被裁切;
  • facecolor="white":避免透明背景在文档里变黑;
  • png:适合常规位图输出;
  • svgpdf:适合矢量编辑和出版排版。

常见坑:GeoPandas绘图不好看的原因不只一个

坑1:字段类型不对,导致专题图颜色异常

如果用于制图的字段看起来是数字,但实际是字符串,颜色分级可能不符合预期。可以先检查字段类型。

print(gdf["population"].dtype)

必要时转换为数值:

gdf["population"] = gdf["population"].astype(float)

坑2:空值没有处理,地图出现缺块

专题字段里有空值时,部分区域可能不着色。可以先统计空值数量。

print(gdf["population"].isna().sum())

如果空值有业务含义,建议单独设置缺失值样式,而不是简单删除。

gdf.plot(
    column="population",
    cmap="YlOrRd",
    legend=True,
    missing_kwds={
        "color": "lightgrey",
        "edgecolor": "white",
        "hatch": "///",
        "label": "缺失值"
    }
)

坑3:坐标系不一致,叠加图层错位

点、线、面叠加时,如果一个图层是 EPSG:4326,另一个图层是投影坐标系,就会出现错位或看不到图层的问题。

points = points.to_crs(polygons.crs)

注意:to_crs() 的前提是原始 CRS 已经正确。如果数据本身没有 CRS,需要先确认真实坐标系,再使用 set_crs() 定义。

坑4:图例被裁切或挤压

图例被裁切通常和画布大小、图例位置、导出边界有关。优先尝试:

  • 增大 figsize
  • 使用 bbox_inches="tight"
  • 减少图例分类;
  • 调整 legend_kwds 中的 shrink
  • 将图例改成横向。

坑5:边界线太粗,地图显得很脏

面要素数量很多时,边界线过粗会让地图显得混乱。可以降低线宽,或只显示上一级行政边界。

gdf.plot(
    column="value",
    cmap="Blues",
    edgecolor="white",
    linewidth=0.2
)

坑6:默认分类不符合 GIS 专题图表达

GeoPandas 默认连续渲染不一定适合所有指标。如果要做分级设色图,可以结合 scheme 参数使用分类方法。该功能通常依赖 mapclassify

gdf.plot(
    column="population",
    cmap="YlOrRd",
    scheme="Quantiles",
    k=5,
    legend=True,
    edgecolor="white",
    linewidth=0.4
)

常见分级方式包括:

  • Quantiles:分位数,每一类数量接近;
  • EqualInterval:等间距,便于解释;
  • NaturalBreaks:自然断点,适合数据聚类明显的情况。

方法比较:GeoPandas、Matplotlib、QGIS该怎么选

方法 适合场景 优点 局限
GeoPandas 默认 plot 快速检查数据、调试空间处理结果 代码少,出图快 默认样式简单,不适合正式制图
GeoPandas + Matplotlib Python 自动化制图、批量专题图、分析报告 可重复、可批量、样式可控 复杂排版需要写较多代码
QGIS 布局管理器 正式地图版式、比例尺、指北针、图框制图 制图元素完整,交互式调整方便 批量自动化需要额外配置或脚本
ArcGIS Pro 布局 规范制图、企业项目、地图册输出 专业制图能力强,布局工具成熟 软件授权和环境成本较高

如果你只是想快速看一下数据,GeoPandas 默认绘图就够了。如果你要把 Python GIS 分析结果自动生成多张图,GeoPandas 加 Matplotlib 更合适。如果你要做标准地图成果,包括比例尺、指北针、图框、坐标网,QGIS 或 ArcGIS Pro 的布局工具会更省心。

检查清单:调整GeoPandas地图前先看这几项

  • 是否确认了数据 CRS,不同图层是否已经统一坐标系?
  • 专题字段是否为正确的数据类型?
  • 是否处理了空值、异常值和极端值?
  • 配色是否符合数据类型:连续、分类、正负差异?
  • 面边界线是否过粗或过细?
  • 是否去掉了不必要的坐标轴?
  • 标题、图例、单位是否完整?
  • 中文字体是否正常显示?
  • 导出时是否设置了 dpibbox_inches
  • 最终图片是否在 Word、PPT、网页或论文模板中实际检查过?

FAQ:GeoPandas绘图太丑的常见问题

GeoPandas绘图太丑,是不是不适合做地图?

不是。GeoPandas 更偏向空间数据分析和自动化处理,默认绘图只是快速预览。只要结合 Matplotlib 调整配色、图例、边界和导出参数,完全可以做出清晰的专题图。但如果需要比例尺、指北针、图框和复杂版式,建议再用 QGIS 或 ArcGIS Pro 完成最终排版。

Matplotlib怎么调整GeoPandas地图颜色?

最常用的是在 gdf.plot() 中设置 colorcolumncmap。单色地图用 color,专题图用 column 指定字段,再用 cmap 指定色带。

gdf.plot(column="value", cmap="Blues", legend=True)

GeoPandas地图怎么去掉坐标轴?

使用 Matplotlib 的 ax.set_axis_off() 即可。通常行政区专题图、点位分布图和报告插图都可以去掉坐标轴,让画面更简洁。

fig, ax = plt.subplots(figsize=(8, 6))
gdf.plot(ax=ax)
ax.set_axis_off()

GeoPandas图例太丑怎么调?

可以使用 legend_kwds 调整图例标题、方向和缩放。例如:

gdf.plot(
    column="value",
    legend=True,
    legend_kwds={
        "label": "指标值",
        "orientation": "vertical",
        "shrink": 0.7
    }
)

如果是复杂分类图,建议先减少类别数量,或者把图例放到导出后的版式中单独处理。

GeoPandas导出的图片为什么很糊?

通常是因为直接截图,或者 savefig() 没有设置足够的 dpi。建议使用:

plt.savefig("map.png", dpi=300, bbox_inches="tight", facecolor="white")

如果后续还要在 Illustrator、Inkscape 或论文模板中编辑,可以导出 SVG 或 PDF。

GeoPandas中文标题乱码怎么办?

需要设置 Matplotlib 中文字体。Windows 环境可尝试:

plt.rcParams["font.sans-serif"] = ["SimHei"]
plt.rcParams["axes.unicode_minus"] = False

如果字体不存在,需要换成系统已安装的中文字体,或者先安装中文字体。

GeoPandas能不能加比例尺和指北针?

可以,但 GeoPandas 和 Matplotlib 并不像 QGIS 布局管理器那样内置完整地图制图元素。简单比例尺、指北针可以用 Matplotlib 手工绘制或借助扩展库实现;如果是正式地图成果,建议使用 QGIS 或 ArcGIS Pro 做最终制图。

结论:GeoPandas负责空间数据,Matplotlib负责图面表达

遇到 GeoPandas 绘图太丑,不要只停留在 gdf.plot() 这一层。正确做法是:先用 GeoPandas 读取、处理和渲染空间数据,再用 Matplotlib 控制画布、标题、图例、坐标轴、字体和导出质量。

一个实用的工作流是:检查 CRS,选择专题字段,设置配色和边界,关闭无用坐标轴,处理中文字体,最后用 savefig() 导出高清图片。掌握这套流程后,GeoPandas 绘图不仅能用于数据检查,也能稳定产出适合 GIS 作业、分析报告和 Web 文章配图的专题地图。