如何让南极立体投影(South Polar Stereo)网格线标签呈环形排列?
问题描述
使用South Polar Stereographic投影制作南极洲地图,通过Cartopy生成了网格线,但网格线标签未按投影的环形分布显示,希望让标签贴合环形样式。
当前代码:
import cartopy.crs as ccrs import cartopy.feature as cfeature import numpy as np import matplotlib.pyplot as plt import matplotlib.patches as mpath fig = plt.figure(figsize=(12,8)) ax = plt.axes(projection=ccrs.SouthPolarStereo()) ax.set_extent([-180, 180, -90, -30], ccrs.PlateCarree()) ax.add_feature(cfeature.LAND, color='darkgrey') ax.add_feature(cfeature.OCEAN, color='lightblue') ax.add_feature(cfeature.COASTLINE, linewidth=1.25) # Draw meridian lines with labels around circular boundary ax.gridlines(crs=ccrs.PlateCarree(), draw_labels=True, linewidth=1, \ xlocs=range(-180,171,10), ylocs=[], \ color='gray', alpha=0.5, linestyle='--', zorder=10) # Draw concentric circles (but hide labels) for the parallels of the latitude ax.gridlines(crs=ccrs.PlateCarree(), draw_labels=False, linewidth=1, \ xlocs=[], ylocs=None, \ color='gray', alpha=0.5, linestyle='--', zorder=10) # Add circular boundary theta = np.linspace(0, 2*np.pi, 100) center, radius = [0.5, 0.5], 0.5 verts = np.vstack([np.sin(theta), np.cos(theta)]).T circle = mpath.Path(verts * radius + center) ax.set_boundary(circle, transform=ax.transAxes) plt.tight_layout() plt.show()
当前效果:网格线为环形经线和同心圆纬线,但经线标签是水平排列,未沿环形边界弯曲或旋转贴合环形方向。
预期效果:经线标签沿地图的环形边界呈旋转排列,贴合南极投影的圆形轮廓,每个经度标签对应其经线的方向。
解决方案
Cartopy默认的gridlines方法生成的标签不会自动适应极投影的环形排列,需要手动调整标签的旋转角度和位置,以下是两种可行方法:
方法1:自定义Gridliner标签旋转
通过获取Gridliner对象,遍历标签并根据经度计算旋转角度,让标签沿环形方向对齐:
修改后的完整代码:
import cartopy.crs as ccrs import cartopy.feature as cfeature import numpy as np import matplotlib.pyplot as plt import matplotlib.patches as mpath fig = plt.figure(figsize=(12,8)) ax = plt.axes(projection=ccrs.SouthPolarStereo()) ax.set_extent([-180, 180, -90, -30], ccrs.PlateCarree()) ax.add_feature(cfeature.LAND, color='darkgrey') ax.add_feature(cfeature.OCEAN, color='lightblue') ax.add_feature(cfeature.COASTLINE, linewidth=1.25) # 绘制网格线并获取Gridliner对象 gl = ax.gridlines(crs=ccrs.PlateCarree(), draw_labels=True, linewidth=1, xlocs=range(-180,171,10), ylocs=[], color='gray', alpha=0.5, linestyle='--', zorder=10) # 隐藏不需要的纬线标签 gl.ylabels_right = False gl.ylabels_left = False # 遍历经度标签,调整旋转角度和位置 for lon, label in zip(gl.xlocs, gl.xlabels): # 计算对应经度的旋转角度,适配南极投影视角 angle = np.deg2rad(lon) label_rot = np.rad2deg(angle) if lon <= 180 else np.rad2deg(angle) - 360 # 调整旋转方向,避免文字倒转 if 90 < lon < 270: label_rot += 180 label.set_rotation(label_rot) # 设置标签对齐方式,确保贴合环形边界 label.set_horizontalalignment('center') label.set_verticalalignment('bottom') # 绘制同心圆纬线(无标签) ax.gridlines(crs=ccrs.PlateCarree(), draw_labels=False, linewidth=1, xlocs=[], ylocs=np.arange(-80, -29, 10), color='gray', alpha=0.5, linestyle='--', zorder=10) # 添加圆形边界 theta = np.linspace(0, 2*np.pi, 100) center, radius = [0.5, 0.5], 0.5 verts = np.vstack([np.sin(theta), np.cos(theta)]).T circle = mpath.Path(verts * radius + center) ax.set_boundary(circle, transform=ax.transAxes) plt.tight_layout() plt.show()
方法2:手动绘制环形标签
如果需要更精准的控制,可使用Matplotlib的text方法手动在环形边界外侧添加标签:
在原有代码基础上替换网格线标签部分为以下代码:
# 绘制无标签的经线网格 gl = ax.gridlines(crs=ccrs.PlateCarree(), draw_labels=False, linewidth=1, xlocs=range(-180,171,10), ylocs=[], color='gray', alpha=0.5, linestyle='--', zorder=10) # 手动添加环形经度标签 theta = np.deg2rad(gl.xlocs) # 标签半径(比地图边界稍大,确保显示在外侧) r = 0.52 # 计算标签的轴坐标位置 x = center[0] + r * np.sin(theta) y = center[1] + r * np.cos(theta) for lon, tx, ty in zip(gl.xlocs, x, y): # 计算文字旋转角度,确保正向可读 rot = np.rad2deg(np.deg2rad(lon)) if 90 < lon < 270: rot += 180 # 添加标签 ax.text(tx, ty, f'{lon}°', transform=ax.transAxes, ha='center', va='center', rotation=rot, fontsize=9)
关键说明
- 南极投影下,经度对应的旋转角度需要特殊调整,避免标签倒转。
- 使用
ax.transAxes坐标系可以方便地在环形边界外侧定位标签。 - 方法1简洁高效,方法2更灵活,可自定义标签样式和位置。
内容的提问来源于stack exchange,提问作者Rony Golder
相关产品推荐
相关产品推荐

