如何将GeoPandas多边形质心坐标映射到Matplotlib坐标?
用GeoPandas质心定位Matplotlib子图的正确姿势
直接手动归一化地理坐标到Matplotlib的图坐标之所以会出错,是因为没考虑到Matplotlib的轴变换(比如图例占用空间、地图投影的非线性映射)。正确的做法是利用Matplotlib内置的坐标转换工具,一步完成地理坐标到图归一化坐标的映射。
完整实现代码
import geopandas as gpd import numpy as np import matplotlib.pyplot as plt # 读取 shp 文件并准备数据 map_gdf = gpd.read_file("my_shapefile.shp") map_gdf["values"] = np.random.rand(len(map_gdf)) # 创建画布和地图轴 fig, ax = plt.subplots(1, 1, figsize=(15, 15)) map_gdf.plot(column="values", ax=ax, legend=True, cmap="Reds") # 计算多边形质心 map_gdf["county_centers"] = map_gdf.geometry.centroid # 取第一个质心作为子图位置示例 centroid = map_gdf["county_centers"][0] # 关键:将地理坐标转换为图的归一化坐标(0-1范围) # 1. 先把地理坐标转成画布上的显示坐标 display_coords = ax.transData.transform((centroid.x, centroid.y)) # 2. 再把显示坐标转成图的归一化坐标(相对于整个画布) fig_coords = fig.transFigure.inverted().transform(display_coords) # 用转换后的坐标添加子图,偏移一半宽度让子图中心对齐质心 subax = fig.add_axes([fig_coords[0] - 0.05, fig_coords[1] - 0.05, 0.1, 0.1]) subax.pie([0.2, 0.8], labels=["A", "B"]) plt.show()
关键逻辑说明
ax.transData.transform():把地理坐标系的点转换为画布显示坐标系(以像素为单位,原点是画布左下角)fig.transFigure.inverted().transform():把显示坐标系的点转换为画布归一化坐标系(范围0-1,(0,0)对应画布左下角,(1,1)对应右上角)- 子图位置减去0.05(子图宽度/高度的一半),是为了让子图中心和质心对齐,避免子图左下角和质心重合的偏移问题
手动归一化失效的原因
你之前的手动计算只用到了数据的total_bounds,但忽略了这些关键因素:
- 地图轴会自动添加边距,实际显示范围和数据原生范围不一致
- 图例、坐标轴标签等元素会占用画布空间,导致地图轴并非铺满整个画布
- 带投影的地理数据,坐标的线性归一化会和实际显示位置产生较大偏差
内容的提问来源于stack exchange,提问作者derM
相关产品推荐
相关产品推荐

