Reputation: 2608
Matplotlibs basemap module hast the ability to draw a background for a map, with inbuilt functions for some basic maps and the ability to tie into arcgis maps.
Both options work well, but are really slow (see also here), especially the arcgis option.
For a single plot, this is not a big issue, but with multiple plots (around 500 in my case) this becomes quite the waiting exercise, plus, I wouldn't want to send hundreds of requests to arcgis, that always fetch the identical map anyways.
But how do I set up/download a background map once, and keep using it in a loop that is plotting many versions of it?
I have adapted the great circle example from the documentation with an etopo background a a loop through some colors for a test:
from mpl_toolkits.basemap import Basemap
import numpy as np
import matplotlib.pyplot as plt
# create new figure, axes instances.
fig=plt.figure()
ax=fig.add_axes([0.1,0.1,0.8,0.8])
# setup mercator map projection.
m = Basemap(llcrnrlon=-100.,llcrnrlat=20.,urcrnrlon=20.,urcrnrlat=60.,\
rsphere=(6378137.00,6356752.3142),\
resolution='l',projection='merc',\
lat_0=40.,lon_0=-20.,lat_ts=20.)
# nylat, nylon are lat/lon of New York
nylat = 40.78; nylon = -73.98
# lonlat, lonlon are lat/lon of London.
lonlat = 51.53; lonlon = 0.08
# draw great circle route between NY and London
m.drawcoastlines()
m.etopo()
# draw parallels
m.drawparallels(np.arange(10,90,20),labels=[1,1,0,1])
# draw meridians
m.drawmeridians(np.arange(-180,180,30),labels=[1,1,0,1])
colors = ('r','b','k','y')
for p_color in colors:
m.drawgreatcircle(nylon,nylat,lonlon,lonlat,linewidth=2,color=p_color)
filename = '%s.png' % p_color
plt.savefig(filename, dpi=100)
The above works, but only because I'm not closing the plot. With my real figures, I'll quickly run out of memory. If I add a plt.close()
at the end of the loop, I loose my background map. Same when I put the the setup of the plot into the loop:
from mpl_toolkits.basemap import Basemap
import numpy as np
import matplotlib.pyplot as plt
# create new figure, axes instances.
# setup mercator map projection.
m = Basemap(llcrnrlon=-100.,llcrnrlat=20.,urcrnrlon=20.,urcrnrlat=60.,\
rsphere=(6378137.00,6356752.3142),\
resolution='l',projection='merc',\
lat_0=40.,lon_0=-20.,lat_ts=20.)
# nylat, nylon are lat/lon of New York
nylat = 40.78; nylon = -73.98
# lonlat, lonlon are lat/lon of London.
lonlat = 51.53; lonlon = 0.08
# draw great circle route between NY and London
m.drawcoastlines()
m.etopo()
# draw parallels
m.drawparallels(np.arange(10,90,20),labels=[1,1,0,1])
# draw meridians
m.drawmeridians(np.arange(-180,180,30),labels=[1,1,0,1])
colors = ('r','b','k','y')
for p_color in colors:
fig=plt.figure()
ax=fig.add_axes([0.1,0.1,0.8,0.8])
m.drawgreatcircle(nylon,nylat,lonlon,lonlat,linewidth=2,color=p_color)
filename = '%s.png' % p_color
plt.savefig(filename, dpi=100)
plt.close()
It only appears to work (ignoring the first option with its memory issues) when I do the whole m.Basemap…
, m.etopo
stuff into the loop, but this is way too slow.
How can I setup ´m´ once, and keep using it?
I could probably MacGyver something by plotting the background map once, plotting my data onto a transparent background and then combine it with imagemagick, but I feel like there should be a better solution.
Upvotes: 1
Views: 1948
Reputation: 339340
I guess the idea would be to keep the basemap plot and not change it. In the loop add the artist you want to have changing from image to image, save the figure, then remove the artist.
from mpl_toolkits.basemap import Basemap
import numpy as np
import matplotlib.pyplot as plt
# create new figure, axes instances.
# setup mercator map projection.
fig=plt.figure()
ax=fig.add_axes([0.1,0.1,0.8,0.8])
m = Basemap(llcrnrlon=-100.,llcrnrlat=20.,urcrnrlon=20.,urcrnrlat=60.,\
rsphere=(6378137.00,6356752.3142),\
resolution='l',projection='merc',\
lat_0=40.,lon_0=-20.,lat_ts=20.)
# nylat, nylon are lat/lon of New York
nylat = 40.78; nylon = -73.98
# lonlat, lonlon are lat/lon of London.
lonlat = 51.53; lonlon = 0.08
# draw great circle route between NY and London
m.drawcoastlines()
m.etopo()
# draw parallels
m.drawparallels(np.arange(10,90,20),labels=[1,1,0,1])
# draw meridians
m.drawmeridians(np.arange(-180,180,30),labels=[1,1,0,1])
colors = ('r','b','k','y')
for p_color in colors:
gc = m.drawgreatcircle(nylon,nylat,lonlon,lonlat,linewidth=2,color=p_color)
filename = 'output{}.png'.format(p_color)
plt.savefig(filename, dpi=100)
# remove previous plot from axes
for line in gc:
line.remove()
del gc
Upvotes: 1