将 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()
最后的情节。
我想使用 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,我发现了类似的问题
这是代码。
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()
最后的情节。