4. 空间数据可视化基础:地图可视化、空间分布展示

地图可视化,说白了就是把数据“扔”到真实地理坐标上,让空间模式自己说话。我做了这么多年空间分析,真要给非技术同事汇报时,一张清晰的图胜过十页报告。

这一章咱们不扯虚的。从基础底图绘制,到点、线、面分布展示,再到热力图和聚类——全用代码砸实。

4.1 基础地图绘制:从空白到第一张图

我个人的习惯是:先用最简单的库跑通流程,再换专业工具调细节。Python 里做地图可视化的主流库,我列个表给你看。

库名适用场景标注层支持我常用的场景
matplotlib + basemap静态专题图弱论文插图、报告快照
geopandas矢量数据快速可视化中探索性分析、数据检查
folium交互式 web 地图强汇报演示、前端嵌入
plotly + mapbox动态大屏强多维交互图表

入门阶段,我建议你先用 geopandas + matplotlib ,因为库的依赖最少,不容易踩坑。我曾经在项目刚起步时就因为 mapbox token 配置问题卡了半天,教训深刻。

来看个最简单的绘制代码。

import geopandas as gpd
import matplotlib.pyplot as plt

# 读一个 shapefile(市区边界数据)
gdf = gpd.read_file('data/districts.shp')

# 快速绘图
fig, ax = plt.subplots(figsize=(8, 6))
gdf.plot(ax=ax, edgecolor='black', facecolor='lightblue')
ax.set_title('基础地图 - 市区边界')
plt.show()

嗯,这里有两个坑,我一开始全踩过:

  • CRS 不统一 —— 数据用的是 WGS84 经纬度(EPSG:4326),但绘图时默认投影是 PlateCarree,可能导致显示失真。最好显式设置 gdf = gdf.to_crs('EPSG:3857') 转成 Web Mercator。
  • 缺失文件 —— shapefile 要求同目录下必须包含 .shp、.shx、.dbf 三个文件。我曾经只拷贝 .shp 就狂报错,教训啊。

4.2 点分布可视化:散点图、气泡图与聚合点

点数据是最常见的空间数据形式。门店位置、事故点位、采样站——你想想,这些在图上展示时,重叠点是最讨厌的。几十万个经纬度堆在一起,啥也看不出来。

我常用的三种做法:

  1. 透明散点图(alpha 调小,适合几千个点)
  2. 气泡图(点的大小映射数量或属性)
  3. 聚合点(网格聚合后显示计数)

经验:当点数量超过 10 万,直接绘制散点图浏览器会卡死。我一般先做六边形网格聚合再绘图,速度快 10 倍。

代码示例:

import geopandas as gpd
import matplotlib.pyplot as plt
from shapely.geometry import Point

# 生成随机点
points = gpd.GeoDataFrame(
    {'value': [20, 35, 50, 15, 10]},
    geometry=[Point(116.3, 39.9), Point(116.4, 39.8),
              Point(116.5, 40.0), Point(116.2, 39.7),
              Point(116.6, 39.6)],
    crs='EPSG:4326'
)

# 气泡图:点大小由 value 决定
fig, ax = plt.subplots(figsize=(6,6))
points.plot(ax=ax, markersize=points['value']*2, alpha=0.7, color='#e74c3c')
ax.set_title('气泡图 - 点大小映射数值')
plt.show()

4.3 线数据可视化:路径、网络与流向

线数据比如道路、河流、快递路线。我印象最深的一个项目是分析城市外卖配送路径,线太多太密,根本看不清主干。后来我学会了线宽分级——按流量或等级设置不同线宽,层次立马出来了。

绘制时注意:

  • 线默认是实线,如果线很密,用虚线或降低透明度更好。
  • 有向线(比如交通流量方向)一定要加箭头,我用 matplotlib.patches.FancyArrowPatch 手动添加。

代码示例:

import geopandas as gpd
import matplotlib.pyplot as plt

# 假设已经有线 GeoDataFrame
lines = gpd.read_file('data/roads.shp')

fig, ax = plt.subplots(figsize=(8,6))
lines.plot(ax=ax, column='speed_class', cmap='RdYlGn',
           linewidth=1.5, legend=True, edgecolor='black')
ax.set_title('道路网 - 按速度分级着色')
plt.show()

4.4 面数据可视化:颜色地图与分区统计图

面数据是行政边界、土地利用单元。最经典的就是分区统计图了。你想想看,一堆面数据给 non‑technical 的 boss 看,你只用两个参数:column 和 cmap,一张图就能说出重点区域。

我会特别留意分类方法:

方法适用缺点
等间隔数值范围明确极端值可能导致多数区域一个色
分位数分布不均匀色块间差异可能不明显
自然间断点(Jenks)寻找天然分组计算量稍大

小技巧:用 mapclassify.NaturalBreaks 可以自动算出 Jenks 断点,省去手动试的麻烦。

代码示例:

import geopandas as gpd
import matplotlib.pyplot as plt
import mapclassify

gdf = gpd.read_file('data/districts.shp')
# 使用自然间断点分类
classifier = mapclassify.NaturalBreaks(gdf['population'], k=5)
gdf['pop_class'] = classifier.yb

fig, ax = plt.subplots(figsize=(8,6))
gdf.plot(ax=ax, column='pop_class', cmap='Blues',
         edgecolor='white', linewidth=0.5, legend=True)
ax.set_title('人口密度分区 - 自然间断点')
plt.show()

4.5 空间分布密度估计:热力图

热力图,我愿称之为「空间可视化的核武器」。不管是犯罪率还是房价,一张热力图可以让分布模式一目了然。背后算法是 Kernel Density Estimation (KDE),说白了就是用平滑曲线估计密度。

用 geopandas 做热力图有现成方法:

import geopandas as gpd
import matplotlib.pyplot as plt

points = gpd.read_file('data/crime_points.shp')
fig, ax = plt.subplots(figsize=(8,6))
points.plot(ax=ax, kind='kde', cmap='hot', alpha=0.7, shade=True)
ax.set_title('犯罪事件热力图 - KDE')
plt.show()

注意:KDE 的带宽(bw_method)很敏感,太小会过拟合,太大就模糊成一片。我一般先试试 Scott 规则,再手动微调。

4.6 空间聚类可视化:把分组画到图上

空间聚类的结果(比如 DBSCAN、K‑Means 的标签)直接涂到地图上,就能看清聚类形状。我做过一个商场选址项目,用 DBSCAN 把消费热点聚出来,再把不同簇用不同颜色标在地图上,客户当场拍板。

import geopandas as gpd
from sklearn.cluster import DBSCAN
import matplotlib.pyplot as plt

points = gpd.read_file('data/shops.shp')
# 将经纬度转为数组
coords = points[['geometry']].apply(lambda g: [g.x, g.y], axis=1).tolist()

clustering = DBSCAN(eps=0.01, min_samples=3).fit(coords)
points['cluster'] = clustering.labels_

fig, ax = plt.subplots(figsize=(8,6))
points.plot(ax=ax, column='cluster', cmap='Set1',
            markersize=10, edgecolor='black', legend=True)
ax.set_title('DBSCAN 聚类结果可视化')
plt.show()

避坑指南:我曾经在投影坐标下直接用经纬度算欧氏距离,结果导致聚类完全走偏。一定要记得把经纬度转成平面坐标(如 EPSG:3857 或 UTM 投影)再送入聚类算法。

4.7 知识体系总览

下面这张图把本章的知识脉络串起来了。从底图绘制开始,到点线面展示,再到密度估计和聚类——你跟着这条线走就不会乱。

空间数据可视化知识体系(第4章) 基础地图绘制 点分布(散点/气泡) 线分布(路网/流向) 面分布(分区统计) 密度估计(热力图) 空间聚类可视化 路径:底图 → 点/线/面 → 热力图 → 聚类 每个环节都需注意投影正确与数据密度

4.8 小总结

地图可视化在空间特征工程里,就像你建房子前的设计图。没有图,你看不到全局,也就没法决定下一步特征怎么做。我个人习惯:每个空间数据集到手,一定先花 10 分钟做三张图——点分布散点图、热力图、面颜色的分区图。看完这三张图,数据质量、分布规律、异常区域基本上就心里有数了。

嗯,这里有个细节你记住:配色别用彩虹色,那玩意儿在灰度打印时根本分不清。我一般用 ColorBrewer 的调色板(plt.cm.Set2 或 plt.cm.Blues),既专业又清晰。

好了,地图可视化入门就到这里。代码凑齐后,下个小节我们会开始做真正的空间特征工程——从点数据里提取邻域特征、缓冲区特征等。但那是后面的事了。你先把这些可视化功夫练扎实,后面做特征提取才不会被数据挡路。