Reputation: 1823
I'd like to create a Basemap instance once (since it's expensive), and then reuse it with, say, different contourf() overlays.
To clarify, I need (basemap + contours1) and (basemap + contours2), not (basemap + contours1 + contours2) which is what this question is about.
There are examples here and here (with responses from the same author, five years apart!), but I cannot get a simple reusable snippet working.
Per that second example, my code is structured as follows:
%matplotlib inline
import numpy as np
from mpl_toolkits.basemap import Basemap
import matplotlib.pyplot as plt
def get_basemap():
fig = plt.figure('Background')
fig.add_subplot(111)
map_ = Basemap(resolution='c', projection='stere', width=12000000,
height=8000000, lat_ts=50, lat_0=50, lon_0=260.)
map_.drawcoastlines()
map_.drawmapboundary()
map_.fillcontinents(zorder=-1)
fig.canvas.draw()
background = fig.canvas.copy_from_bbox(fig.bbox)
return map_, background
def plot_thing1(map_, background, lats, lons, data):
fig = plt.figure('Contourf', frameon=False)
fig.add_subplot(111, frameon=False)
fig.canvas.restore_region(background)
x, y = map_(*np.meshgrid(lons, lats))
map_.contourf(x, y, data, zorder=0)
fig.show()
def plot_thing2(map_, background, lats, lons, ugrd, vgrd):
fig = plt.figure('Quiver', frameon=False)
fig.add_subplot(111, frameon=False)
fig.canvas.restore_region(background)
x, y = map_(*np.meshgrid(lons, lats))
map_.quiver(x, y, ugrd, vgrd, zorder=0)
fig.show()
min_lat, max_lat = 20, 70
min_lon, max_lon = 210, 310
lats = np.arange(min_lat, max_lat)
lons = np.arange(min_lon, max_lon)
shape = len(lats), len(lons)
# Run this once to get a reusable basemap
map_, background = get_basemap()
# Random data for thing1
data = np.random.rand(*shape)
plot_thing1(map_, background, lats, lons, data)
# Random data for thing2
ugrd, vgrd = np.random.rand(*shape), np.random.rand(*shape)
plot_thing2(map_, background, lats, lons, ugrd, vgrd)
But plot_thing1()
produces two "plots", one with the basemap background followed by the other with the contours by itself (instead of the contours superimposed on the basemap in one plot). And plot_thing2()
produces just the quivers.
How can I get them to appear on the same plot? (And reuse the basemap in plot_thing1()
, plot_thing2()
, etc.) This probably has to do with things getting attached to the wrong active figure/subplot/Axes, but I can't get my head around how Basemap()
fits into the matplotlib
hierarchy.
Upvotes: 2
Views: 765
Reputation: 339340
The following saves three images, the background alone, the background with the contour plot and the background with the quiver:
import numpy as np
from mpl_toolkits.basemap import Basemap
import matplotlib.pyplot as plt
def get_basemap():
fig = plt.figure('Background')
fig.add_subplot(111)
map_ = Basemap(resolution='c', projection='stere', width=12000000,
height=8000000, lat_ts=50, lat_0=50, lon_0=260.)
map_.drawcoastlines()
map_.drawmapboundary()
map_.fillcontinents(zorder=-1)
return map_
def plot_thing1(map_, lats, lons, data):
x, y = map_(*np.meshgrid(lons, lats))
c = map_.contourf(x, y, data, zorder=0)
return c
def plot_thing2(map_, lats, lons, ugrd, vgrd):
x, y = map_(*np.meshgrid(lons, lats))
q = map_.quiver(x, y, ugrd, vgrd, zorder=0)
return q
min_lat, max_lat = 20, 70
min_lon, max_lon = 210, 310
lats = np.arange(min_lat, max_lat)
lons = np.arange(min_lon, max_lon)
shape = len(lats), len(lons)
# Run this once to get a reusable basemap
m = get_basemap()
plt.savefig("background.png")
#Plot stuff on the axes
data = np.random.rand(*shape)
c = plot_thing1(m, lats, lons, data)
plt.savefig("thing1.png")
#remove the contourplot from the axes:
for member in c.collections:
member.remove()
#Plot new stuff on the axes
ugrd, vgrd = np.random.rand(*shape), np.random.rand(*shape)
q = plot_thing2(m, lats, lons, ugrd, vgrd)
plt.savefig("thing2.png")
# to remove the quiver use
# q.remove()
plt.show()
As a workaround, to display the saved images directly in a jupyter notebook, you can do
from IPython.display import Image, display
listOfImageNames = ['background.png','thing1.png', 'thing2.png']
for fn in listOfImageNames:
display(Image(filename=fn))
Upvotes: 2