I'm trying to make a plot using basemap with an inset zoom. I'm having trouble with the inset box from mark_inset() to appear anywhere besides the lower left hand corner. It works for projection='cyl' but not for projection='geos' which is what I want.
from mpl_toolkits.basemap import Basemap
from mpl_toolkits.axes_grid1.inset_locator import zoomed_inset_axes
from mpl_toolkits.axes_grid1.inset_locator import mark_inset
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(111)
map1 = Basemap(projection='geos', lat_0=0, lon_0=0)
map1.drawmapboundary()
map1.drawcoastlines()
axins = zoomed_inset_axes(ax, 7, loc=3)
axins.set_xlim(-12, 5)
axins.set_ylim(50, 60)
map2 = Basemap(projection='geos', lon_0=0, llcrnrlon=-12, llcrnrlat=50, urcrnrlon=5, urcrnrlat=60[enter image description here][1])
map2.drawcoastlines()
mark_inset(ax, axins, loc1=2, loc2=4, fc="none", ec="0.5")
Bumping this...can confirm it's an issue.
I haven't tried every projection, but of the dozen I have tried, 'cyl' is the only one where mark_inset works. All others locate it at lower left.
I encountered the same problem. This is because Basemap works internally with projected coordinates - except for the cyl
projection; read here :
Calling a Basemap class instance with the arguments lon, lat will convert lon/lat (in degrees) to x/y map projection coordinates (in meters). [...]
For cylindrical equidistant projection (cyl), this does nothing (ie x,y == lon,lat).
To make the marking work properly, you need to first extract the inset map limits, convert them to geographic coordinates, and finally re-project them again onto the main map.
I wrote a small replacement function for mark_inset
that additionally needs the Basemap objects m
& m2
of both maps (main and inset):
def mark_inset(ax, ax2, m, m2, loc1=(1, 2), loc2=(3, 4), **kwargs):
"""
Patched mark_inset to work with Basemap.
Reason: Basemap converts Geographic (lon/lat) to Map Projection (x/y) coordinates
Additionally: set connector locations separately for both axes:
loc1 & loc2: tuple defining start and end-locations of connector 1 & 2
"""
# Doesn't work for Basemap
# rect = TransformedBbox(inset_axes.viewLim, parent_axes.transData)
# axzoom_geoLims = np.array(m2(*ax2.viewLim._points.T, inverse=True))
axzoom_geoLims = m2(ax2.get_xlim(), ax2.get_ylim(), inverse=True)
rect = TransformedBbox(Bbox(np.array(m(*axzoom_geoLims)).T), ax.transData)
pp = BboxPatch(rect, fill=False, **kwargs)
ax.add_patch(pp)
p1 = BboxConnector(ax2.bbox, rect, loc1=loc1[0], loc2=loc1[1], **kwargs)
ax2.add_patch(p1)
p1.set_clip_on(False)
p2 = BboxConnector(ax2.bbox, rect, loc1=loc2[0], loc2=loc2[1], **kwargs)
ax2.add_patch(p2)
p2.set_clip_on(False)
return pp, p1, p2
Note: the function is based on another answer that allows to set different start and end locations for the connectors. Hence, you can do that with this function as well.
Note2: the ax2
object doesn't need to be necessarily an inset object - it can be any axis object (eg, also a subplot). Therefore, a better name for the function would be mark_geo_zoom
. ;-)
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.