如何在matplotlib和cartopy中轻松添加具有正确位置和大小的sub_ax?

时间:2017-08-06 00:35:12

标签: cartopy

我想在第1轴的右上角添加第2轴。谷歌搜索后,我发现了两种方法: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 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())

我在matplotlib issue问了这个问题。看起来以下代码可以正常工作,只要它不是一个折纸轴。

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中轻松添加具有正确位置和大小的sub_axes?

据我了解,在ax.set_extend()之后,轴的大小会发生变化。那么也许有一种方法可以将某些sub_axes(例如:ax2的右上角)锚定在parent_axes的一个固定位置(例如:ax1的右上角)?

2 个答案:

答案 0 :(得分:2)

我可能已经想出了什么。

根据answer this question。我可以得到两个轴的位置,然后重新定位第二个轴。代码就像:

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

答案 1 :(得分:1)

由于inset_axes()不接受projection arg,因此回旋方式是使用InsetPosition()。这样,您可以按照常规方式(使用projection创建轴,然后使用InsetPosition()“链接”两个轴。使用子图或类似图形的主要优点是插入位置是固定的,您可以调整图形的大小或更改主绘图区域,并且插入相对于主轴始终位于同一位置。这是基于以下答案:specific location for inset axes,只是添加了行事方式。

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)

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

Inset example