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

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

我想在第一个轴的右上角添加第二个轴。经过谷歌搜索后,我发现了两种方法可以做到这样的事情:

fig.add_axes()
mpl_toolkits.axes_grid.inset_locator.inset_axes
。但是
fig.add_axes()
不接受
transform
arg。所以下面的代码会抛出错误。所以位置不能在父轴坐标下,而是在图形坐标下。

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

并且

inset_axes()
不接受
projection
参数,因此我无法将
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())

我在matplotlib问题中提出了这个问题。只要它不是 cartopy 轴,下面的代码似乎就可以很好地工作。

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

问题:

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

据我了解,在

ax.set_extend()
之后,轴的大小将会改变。那么也许有一种方法可以将子轴的某个点(例如:
ax2
的右上角)锚定在父轴的一个固定位置(例如:
ax1
的右上角)?

python matplotlib cartopy cartography scitools
3个回答
9
投票

由于

inset_axes()
不接受
projection
arg,迂回的方法是使用
InsetPosition()
。这样您就可以按照通常的方式创建一个轴(使用
projection
),然后使用
InsetPosition()
“链接”两个轴。与使用子图或类似图相比,主要优点是插图位置是固定的,您可以调整图形大小或更改主图区域,并且插图将始终位于相对于主轴的相同位置。这是基于这个答案:插入轴的特定位置,只需添加 cartopy 的做事方式。

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)

Inset example


4
投票

我可能已经想出一些办法了。

根据回答这个问题。我可以获得两个轴的位置,然后重新定位第二个轴。代码就像:

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

结果正是我想要的。 enter image description here


0
投票

自 Matplotlib v3.6 起,Axes.inset_axes 方法接受 position 关键字。 所以现在就简单多了:

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

fig, ax = plt.subplots(1, 1, subplot_kw={'projection': ccrs.PlateCarree()})
ax_ins = ax.inset_axes([0.8, 0.8, 0.2, 0.2], projection=ccrs.PlateCarree())

ax.coastlines()
ax_ins.coastlines()

plt.show()

enter image description here

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