使用极地立体投影在 cartopy 中放置纬度标签

问题描述 投票:0回答:3

我试图弄清楚在使用极地立体投影时如何更改 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()

手动放置它们
python matplotlib cartopy
3个回答
2
投票

创建

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()

1
投票

可能是因为我使用了 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]])


0
投票

这对我来说是一个很好的解决方案。无论如何,这里有一点改进。 使用 图.canvas.draw() 比 plt.draw() 更好。 如果您发现上面的答案不起作用,请尝试这个,它对我有用。

© www.soinside.com 2019 - 2024. All rights reserved.