I'm using Cartopy to display the GSHHSFeature coastlines in multiple Matplotlib subplots and overlay different data on them.
import matplotlib.pyplot as pltimport cartopy.crs as ccrsimport cartopy.feature as cfeatureimport numpy as npxss = np.linspace(-21, 36, 36)extent = [-21, 36, 33, 64] # west,east,south,northrows=3cols=2fig, ax = plt.subplots(nrows=rows, ncols=cols, figsize=(13, 15), subplot_kw={'projection': ccrs.PlateCarree()})for i in range(rows): for j in range(cols): ax[i][j].set_extent(extent) ax[i][j].add_feature(cfeature.GSHHSFeature(scale="intermediate", edgecolor="black", facecolor="#bca89f")) # Plot individual data sets on subplots ax[i][j].plot(xss, np.random.uniform(low=33, high=64, size=(len(xss),)), color='cyan', zorder=20, transform=ccrs.PlateCarree(), linewidth=2) # Write map title ax[i][j].set_title("Row:"+str(i)+", Col:"+str(j))plt.tight_layout()plt.show()
Drawing the coastlines is a time consuming operation, particularly when using a ‘full’ dataset scale. Since the basemap is the same in each subplot, I was looking for ways to create it only once and reuse it in the loop.
Is there a way I can either cache the feature or even the entire subplot axis and define functions like ax[i][j].plot_my_basemap(map_ax)
or ax[i][j] = copy_axis_from(map_ax)
?
# Create a plot axes of choicemap_ax = plt.axes(projection=ccrs.PlateCarree())map_ax.set_extent(extentd)# Request and process the basemap featuresmap_ax.add_feature(cfeature.GSHHSFeature(scale="intermediate", edgecolor="black", facecolor="#bca89f"))fig, ax = plt.subplots(nrows=3, ncols=2, figsize=(13, 15), subplot_kw={'projection': ccrs.PlateCarree()})for i in range(rows): for j in range(cols): ax[i][j].plot_my_basemap(map_ax) # Plot individual data sets on subplots ax[i][j].plot(xss, np.random.uniform(low=33, high=64, size=(len(xss),)), color='cyan', zorder=20, transform=ccrs.PlateCarree(), linewidth=2) # Write map title ax[i][j].set_title("Row:"+str(i)+", Col:"+str(j))plt.tight_layout()plt.show()
The answer to this question (from which I adapted my example) shows how to do it with Google tiled images, but this approach doesn't work in my case because the coastlines are not image objects, but cartopy.mpl.feature_artist.FeatureArtist.
I also tried to reuse directly map_ax, change its properties and assign it to the subplots, but this doesn't work in matplotlib:
for i in range(rows): for j in range(cols): props = ax[i][j].properties() props = dict((k, props[k]) for k in ["position", "subplotspec"]) ax[i][j] = map_ax.update(props) # Plot individual data sets on subplots ax[i][j].plot(xss, np.random.uniform(low=33, high=64, size=(len(xss),)), color='cyan', zorder=20, transform=ccrs.PlateCarree(), linewidth=2) # Write map title ax[i][j].set_title("Row:"+str(i)+", Col:"+str(j))
I was hoping to be able to define and reuse something like Basemap objects https://github.com/matplotlib/basemap/issues/354 (but I don't want to use Basemap because it's going to be substituted by Cartopy and it has already compatibility issues with Matplotlib 3.8)