如何实现从Cartopy地理坐标到Matplotlib轴坐标系坐标的转换
解决Cartopy地理坐标转轴归一化坐标的问题
我明白你想要实现的需求:把任意地理坐标系下的点,转换为Cartopy GeoAxes的轴归一化坐标(范围[0,1],左下角(0,0)、右上角(1,1))。下面是具体的实现方案和代码示例:
核心思路
要完成这个转换,需要经过两步坐标变换:
- 将地理坐标转换为当前GeoAxes使用的投影坐标系笛卡尔坐标
- 将投影坐标系的坐标转换为Axes的归一化轴坐标(transAxes空间)
Matplotlib的变换系统和Cartopy的坐标转换可以完美配合完成这个流程,不需要额外引入第三方库。
完整代码示例
from matplotlib import pyplot as plt import cartopy.crs as ccrs def geo_to_axes_coords(ax, lon, lat, src_crs=ccrs.PlateCarree()): """ 将地理坐标转换为Cartopy GeoAxes的归一化轴坐标[0,1] 参数: ax: Cartopy GeoAxesSubplot对象 lon: 经度值(或经度数组) lat: 纬度值(或纬度数组) src_crs: 输入地理坐标使用的坐标系,默认PlateCarree 返回: 归一化轴坐标的(x, y)元组(或数组) """ # 步骤1:将地理坐标转换为Axes投影的笛卡尔坐标 target_crs = ax.projection proj_points = target_crs.transform_points(src_crs, lon, lat) # 提取x和y坐标(忽略z值) x_proj, y_proj = proj_points[..., 0], proj_points[..., 1] # 步骤2:将投影坐标转换为轴归一化坐标 # 先转成display坐标,再转成transAxes坐标 display_points = ax.transData.transform(list(zip(x_proj, y_proj))) axes_points = ax.transAxes.inverted().transform(display_points) return axes_points[:, 0], axes_points[:, 1] # 测试示例 if __name__ == "__main__": # 创建Mollweide投影的Axes ax = plt.axes(projection=ccrs.Mollweide()) ax.coastlines() # 测试点:PlateCarree(0,0),对应Mollweide投影中心 lon, lat = 0, 0 x_ax, y_ax = geo_to_axes_coords(ax, lon, lat) print(f"地理坐标({lon}, {lat})对应的轴坐标:({x_ax[0]:.2f}, {y_ax[0]:.2f})") # 输出应该是(0.50, 0.50) # 验证:用转换后的轴坐标绘图,应该和原地理坐标点重合 ax.plot(x_ax, y_ax, transform=ax.transAxes, marker='x', ms=12, color='red') ax.plot(lon, lat, transform=ccrs.PlateCarree(), marker='o', ms=10, color='blue') plt.show()
关键步骤解释
地理坐标转投影坐标:
使用target_crs.transform_points()方法,把输入的地理坐标从src_crs转换为Axes当前使用的投影坐标系(target_crs)的笛卡尔坐标。这个方法支持批量处理多个点。投影坐标转轴归一化坐标:
ax.transData.transform():将投影坐标系的点转换为Matplotlib的显示坐标(以像素为单位的屏幕坐标)ax.transAxes.inverted().transform():将显示坐标逆转换为轴的归一化坐标,也就是我们需要的[0,1]范围坐标,这个坐标直接对应ax.transAxes变换的输入。
注意事项
- 如果输入的地理点不在当前Axes的可视范围内,转换后的轴坐标会超出[0,1]范围,可以根据需求进行裁剪或判断。
- 这个方法适用于Cartopy支持的所有投影类型,包括正射投影(Orthographic)、北极立体投影等,不需要针对不同投影修改逻辑。
内容的提问来源于stack exchange,提问作者user2821
相关产品推荐
相关产品推荐

