简体   繁体   English

如何在matplotlib和cartopy中轻松添加具有适当位置和大小的sub_axes?

[英]How to easily add a sub_axes with proper position and size in matplotlib and cartopy?

I want to add a 2nd axes at the top right corner of a 1st axes. 我想在第一轴的右上角添加第二轴。 After googling, I found two ways to do things like this: fig.add_axes() , and mpl_toolkits.axes_grid.inset_locator.inset_axes . 谷歌搜索之后,我发现有两种方法可以执行以下操作: fig.add_axes()mpl_toolkits.axes_grid.inset_locator.inset_axes But the fig.add_axes() doesn't accept transform arg. 但是fig.add_axes()不接受transform arg。 So the following code throws an error. 因此,以下代码将引发错误。 So the position can't be under the parent axes coordinates but the figure coordinates. 因此,位置不能在父轴坐标下,而在图形坐标下。

import matplotlib.pyplot as plt
import cartopy.crs as ccrs
fig, ax = plt.subplots(1, 1, subplot_kw={'projection': ccrs.PlateCarree()})
ax2 = fig.add_axes([0.8, 0, 0.2, 0.2], transform=ax.transAxes, projection=ccrs.PlateCarree()) 

And inset_axes() doesn't accept the projection arg, so I can't add ax2 as a cartopy geo-axes. inset_axes()不接受projection ARG,所以我不能添加ax2为cartopy几何轴。

from mpl_toolkits.axes_grid.inset_locator import inset_axes
import matplotlib.pyplot as plt
import cartopy.crs as ccrs
fig, ax = plt.subplots(1, 1, subplot_kw={'projection': ccrs.PlateCarree()})

# The following line doesn't work
ax2 = inset_axes(ax, width='20%', height='20%', axes_kwargs={'projection': ccrs.PlateCarree()})
# Doesn't work neither:
ax2 = inset_axes(ax, width='20%', height='20%', projection=ccrs.PlateCarree())

I've asked the question at matplotlib issue . 我在matplotlib问题上问了这个问题 It seems the following code works well as long as it's not a cartopy axes. 看起来下面的代码只要不属于“不稳定轴”就可以正常工作。

import matplotlib as mpl
fig, ax = plt.subplots(1, 1)
box = mpl.transforms.Bbox.from_bounds(0.8, 0.8, 0.2, 0.2)
ax2 = fig.add_axes(fig.transFigure.inverted().transform_bbox(ax.transAxes.transform_bbox(box)))

Question: 题:

How to easily add a sub_axes with proper position and size in matplotlib and cartopy? 如何在matplotlib和cartopy中轻松添加具有适当位置和大小的sub_axes?

As I understand, after ax.set_extend() , the size of axes will change. 据我了解,在ax.set_extend() ,轴的大小将改变。 So maybe is there a way that some point of sub_axes (eg: top right corner of ax2 ) can be anchored at one fixed position of the parent_axes (eg: top right corner of ax1 )? 因此,也许是有办法,sub_axes的一些点(例如:右上角ax2 )可以在parent_axes的一个固定位置固定(如:右上的角落ax1 )?

I may have figured something out. 我可能已经想通了。

According to the answer this question . 根据回答这个问题 I can get the position of both axes, then reposition the 2nd axes. 我可以获取两个轴的位置,然后重新定位第二个轴。 The code was like: 代码就像:

import matplotlib.pyplot as plt
from cartopy import crs as ccrs

fig, ax = plt.subplots(1, 1, subplot_kw={'projection': ccrs.PlateCarree()})
ax2 = fig.add_axes([0.8, 0.8, 0.2, 0.2], projection=ccrs.PlateCarree())
ax.set_extent([100, 120, 20, 40])
ax.coastlines()
ax2.set_global()
ax2.coastlines()
ax2.stock_img()

def reposition():
    plt.draw()
    p1 = ax.get_position()
    p2 = ax2.get_position()
    ax2.set_position([p1.x1-p2.width, p1.y1-p2.height, p2.width, p2.height])

reposition()
plt.show()

The result is just what I want. 结果就是我想要的。 在此处输入图片说明

As inset_axes() doesn't accept projection arg, the roundabout way is to use InsetPosition() . 由于inset_axes()不接受projection arg,因此回旋方式是使用InsetPosition() This way you can create an axes in the usual way (using projection ), and then "link" both axes using InsetPosition() . 这样,您可以按照通常的方式(使用projection )创建轴,然后使用InsetPosition() “链接”两个轴。 The main advantage over using subplots or similar is that the inset position is fixed, you can resize the figure or change the main plot area and the inset will always be in the same place relative to the main axes. 使用子图或类似图形的主要优点是插入位置是固定的,您可以调整图形的大小或更改主绘图区域,并且插入相对于主轴始终位于同一位置。 This was based on this answer: specific location for inset axes , just adding the cartopy way of doing things. 这是基于以下答案: 插入轴的特定位置 ,只是添加了刻角的处理方式。

import numpy as np
import matplotlib.pyplot as plt
import cartopy.crs as ccrs
import cartopy.feature as cfeature
from mpl_toolkits.axes_grid1.inset_locator import InsetPosition
from shapely.geometry.polygon import LinearRing

extent = [-60, -30, -40, -10]
lonmin, lonmax, latmin, latmax = extent

fig = plt.figure(figsize=(10, 8))
ax = fig.add_subplot(1, 1, 1, projection=ccrs.PlateCarree())
ax.set_extent(extent, crs=ccrs.PlateCarree())
ax.add_feature(cfeature.LAND)
ax.add_feature(cfeature.OCEAN)
ax.add_feature(cfeature.COASTLINE)

# inset location relative to main plot (ax) in normalized units
inset_x = 1
inset_y = 1
inset_size = 0.2

ax2 = plt.axes([0, 0, 1, 1], projection=ccrs.Orthographic(
    central_latitude=(latmin + latmax) / 2,
    central_longitude=(lonmin + lonmax) / 2))
ax2.set_global()
ax2.add_feature(cfeature.LAND)
ax2.add_feature(cfeature.OCEAN)
ax2.add_feature(cfeature.COASTLINE)

ip = InsetPosition(ax, [inset_x - inset_size / 2,
                        inset_y - inset_size / 2,
                        inset_size,
                        inset_size])
ax2.set_axes_locator(ip)

nvert = 100
lons = np.r_[np.linspace(lonmin, lonmin, nvert),
             np.linspace(lonmin, lonmax, nvert),
             np.linspace(lonmax, lonmax, nvert)].tolist()
lats = np.r_[np.linspace(latmin, latmax, nvert),
             np.linspace(latmax, latmax, nvert),
             np.linspace(latmax, latmin, nvert)].tolist()

ring = LinearRing(list(zip(lons, lats)))
ax2.add_geometries([ring], ccrs.PlateCarree(),
                   facecolor='none', edgecolor='red', linewidth=0.75)

插图示例

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM