将 Insetposition 用于带有 Cartopy 的 Inset Axes 时出现问题

Trouble using Insetposition for Inset Axes with Cartopy

我想使用 Cartopy 在地图上创建插图。我想将 x 和 y 插入位置指定为父轴的函数,以便子轴始终位于父轴内。例如,0,0 对齐左下角的插入轴,1,1 对齐右上角的插入轴,但在这两种情况下,插入图都在父级内部。我使用以下方法实现了这一点:

import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1.inset_locator import InsetPosition
import cartopy.crs as ccrs

ax = plt.axes(projection=ccrs.PlateCarree(), label='1')
ax.coastlines()

iax = plt.axes([0, 0, 1, 1], projection=ccrs.PlateCarree(), label='2')
iax.coastlines()

size = .5
inset_x = 1
inset_y = 1

left = inset_x - inset_x*size
bottom = inset_y - inset_y*size

ip = InsetPosition(ax, [left, bottom, size, size]) #posx, posy, width, height
iax.set_axes_locator(ip)

working fine when extents not set

问题是我是否将新范围应用于插图。根据新设置范围的纵横比,我的 x 或 y 插入位置转换为父轴内的位置 - 0-y 导致插入离开底部,1-y 导致它在顶部偏移.发生这种情况时,偏移是对称的,并且仅发生在一个位置轴中,另一个轴按预期运行。我试过使用 get_position,但在使用 Cartopy 时这似乎并不直观,因为返回的 bbox 不反映绘图范围的纵横比。例如,在应用 InsetPosition 之前添加:

# extent=[-20,60,40,65] # this breaks y positioning
extent=[-20,60,0,65] # this breaks x positioning
iax.set_extent(extent, crs=ccrs.PlateCarree())

not working as expected

我可以手动将它们调整到我想要的位置,但更正与 bbox height/width 或我想检查的任何其他值的差异不匹配。有什么建议吗?

如果我将左侧和底部位置更改为:

left = inset_x - size/2
bottom = inset_y - size/2

不管设置的范围如何,它总是始终如一地工作,但它会使插图与角重叠。 works consistently but not desired results

附加说明 - 如果您使用普通(非 GeoAxes)图并使用 set_aspect 更改插图的方位,则可以发现相同的行为。我仍然没有弄清楚前置和 post-方面变化之间的 bbox 大小关系(父级和插图)以及它如何影响特定的插图放置。

@Hagbeard,我发现了类似的问题,我进一步细化了@gepcel的代码,使其更能满足您的需求。

这是代码。

import matplotlib.pyplot as plt
#from mpl_toolkits.axes_grid1.inset_locator import InsetPosition
import cartopy.crs as ccrs

ax = plt.axes(projection=ccrs.PlateCarree(), label='1')
ax.coastlines()

size = .2 # Figure Standardized coordinates (0~1)
#GeoAxes has a width/height ratio according to self's projection
#Therefore, Here only set  a same width and height

iax = plt.axes([0, 0, size, size], projection=ccrs.PlateCarree(), label='2')
iax.coastlines()

extent=[-20,60,40,65]
#extent=[-20,60,0,65]
iax.set_extent(extent, crs=ccrs.PlateCarree())

def set_subplot2corner(ax,ax_sub,corner="bottomright"):
    ax.get_figure().canvas.draw()
    p1 = ax.get_position()
    p2 = ax_sub.get_position()
    if corner == "topright":
        ax_sub.set_position([p1.x1-p2.width, p1.y1-p2.height, p2.width, p2.height])
    if corner == "bottomright":
        ax_sub.set_position([p1.x1-p2.width, p1.y0, p2.width, p2.height])
    if corner == "bottomleft":
        ax_sub.set_position([p1.x0, p1.y0, p2.width, p2.height])
    if corner == "topleft":
        ax_sub.set_position([p1.x0, p1.y1-p2.height, p2.width, p2.height])

set_subplot2corner(ax,iax,corner="topright")

# Do not support a interactive zoom in and out
# so plz save the plot as a static figure
plt.savefig("corner_subfig.png",bbox_inches="tight")
#plt.show()

最后的情节。