我试图弄清楚在使用极地立体投影时如何更改 cartopy 中网格线标签(更具体地说,纬度标签)的位置(
NorthPolarStereo
)。我的轴目前看起来像这样:
import matplotlib.pyplot as plt
import matplotlib.path as mpath
import numpy as np
import cartopy.crs as ccrs
# Helper function
# from https://nordicesmhub.github.io/NEGI-Abisko-2019/training/example_NorthPolarStereo_projection.html
def polarCentral_set_latlim(lat_lims, ax):
ax.set_extent([-180, 180, lat_lims[0], lat_lims[1]], ccrs.PlateCarree())
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)
fig = plt.figure(figsize=(6,6))
ax = fig.add_subplot(1,1,1,projection=ccrs.NorthPolarStereo(central_longitude=0))
ax.coastlines(linewidth=0.5,color='k')
ax.gridlines(color='C7',lw=1,ls=':',draw_labels=True,rotate_labels=False,ylocs=[60,70,80])
polarCentral_set_latlim((50,90),ax)
奇怪的是,即使
central_longitude
设置为不同的值,纬度标签也始终绘制在 150E 左右。最好,我想将它们与第 180 条经线对齐(类似于此图中的标签),但我在 gridlines
函数的文档中找不到用于设置其位置的选项。我是否忽略了某些内容,或者我是否必须使用 plt.text()
手动放置它们
创建
gridlines
后,可以访问一些标签并将其移动到新位置。
我使用替代方法来定义绘图的圆形边界,以免干扰网格线的标签。
import cartopy.crs as ccrs #cartopy v0.19
import matplotlib.pyplot as plt
import matplotlib.path as mpath
import numpy as np
# Value for r_extent is obtained by trial and error
# get it with `ax.get_ylim()` after running this code
r_extent = 4651194.319
r_extent *= 1.005 #increase a bit for better result
# Projection settings
lonlat_proj = ccrs.PlateCarree()
use_proj = ccrs.NorthPolarStereo(central_longitude=0)
fig = plt.figure(figsize=[7, 7])
ax = plt.subplot(1, 1, 1, projection=use_proj)
ax.set_extent([-180, 180, 50, 90], lonlat_proj)
#ax.stock_img() # add bluemarble image
ax.coastlines(lw=0.5, color="black", zorder=20) # add coastlines
# draw graticule (meridian and parallel lines)
gls = ax.gridlines(draw_labels=True, crs=lonlat_proj, lw=1, color="gray",
y_inline=True, xlocs=range(-180,180,30), ylocs=range(0,90,10))
# set the plot limits
ax.set_xlim(-r_extent, r_extent)
ax.set_ylim(-r_extent, r_extent)
# Prep circular boundary
circle_path = mpath.Path.unit_circle()
circle_path = mpath.Path(circle_path.vertices.copy() * r_extent,
circle_path.codes.copy())
#set circular boundary
#this method will not interfere with the gridlines' labels
ax.set_boundary(circle_path)
ax.set_frame_on(False) #hide the boundary frame
plt.draw() # Enable the use of `gl._labels`
# Reposition the tick labels
# Labels at 150d meridian will be moved to 180d
for ea in gls._labels:
# No _labels if not run `plt.draw()`
pos = ea[2].get_position()
#print("Position:", pos[0], pos[1])
if (pos[0]==150):
ea[2].set_position([180, pos[1]])
plt.show()
编辑(2023 年 3 月 3 日)
上面的代码对于 Cartopy v0.19 运行良好。新版本中的
gridlines
发生了变化,部分代码需要更新。
这是相关代码:-
# ...
for ea in gls.label_artists:
pos = ea.get_position()
if pos[0] == 150:
print("Position:", pos, ea.get_text() )
ea.set_position([180, pos[1]])
plt.show()
可能是因为我使用了 cartopy 版本(0.21.1),但 @swatchai 的答案对我不起作用。然而,可以做一些轻微的改变,并且效果很好。
plt.draw()
for ea in gls.label_artists:
# return ea of mpl.text type, e.g. Text(135, 30, '30°N')
pos = ea.get_position()
if pos[0] == 135:
ea.set_position([180, pos[1]])
这对我来说是一个很好的解决方案。无论如何,这里有一点改进。 使用 图.canvas.draw() 比 plt.draw() 更好。 如果您发现上面的答案不起作用,请尝试这个,它对我有用。