Reputation: 37
I'm currently working with some data that involves the land use type (i.e., forested, desert, water, etc.) that comes up as different colors on my cartopy maps. I want to add a legend or equivalent that shows which land type each color represents, but can't seem to get it to work. The land use type data plotting on top of the cartopy map requires me using pcolormesh. Is there any way to get a legend of sorts onto the cartopy plot that shows which color each land use type is?
Below is my cartopy portion of my code:
proj = ccrs.LambertConformal(central_longitude=cLon, central_latitude=cLat)
res = '10m'
fig_1 = plt.figure(figsize=(20,20))
ax_1 = plt.subplot(1,1,1,projection=proj)
ax_1.set_extent([lonW,lonE,latS,latN])
ax_1.add_feature(cfeature.LAND.with_scale(res))
ax_1.add_feature(cfeature.OCEAN.with_scale(res))
ax_1.add_feature(cfeature.COASTLINE.with_scale(res))
ax_1.add_feature(cfeature.LAKES.with_scale(res), alpha = 0.5)
ax_1.add_feature(cfeature.STATES.with_scale(res));
ax_1.set_title('Land Use Type: Western United States', fontsize=20)
ax_1.pcolormesh(cat_land_lons, cat_land_lats, cat_land, transform=ccrs.PlateCarree(), zorder=3)
ax_1.legend(['Forested', 'Water', 'Desert', 'Farmland', 'Urban'])
Upvotes: 0
Views: 1789
Reputation: 64463
It difficult to be specific without knowing what your data looks like. But given some example Landcover data and assigned colors. Things might be a little different if your LCC data is not consecutive like this.
lc_colors = {
'Forested': "g", # value=0
'Water': "b", # value=1
'Desert': "y", # value=2
'Farmland': "c", # value=3
'Urban': "r", # value=4
}
yy, xx = np.mgrid[35:45:1, -120:-110:1]
zz = np.random.randint(0, len(lc_colors), xx.shape)
You can define a colormap and normalizer:
cmap = mpl.colors.LinearSegmentedColormap.from_list("lcc", list(lc_colors.values()))
bounds = np.arange(len(lc_colors)+1)
norm = mpl.colors.BoundaryNorm(bounds, cmap.N)
Using proxy artists for the legend:
import matplotlib.pyplot as plt
import matplotlib as mpl
import matplotlib.patches as mpatches
import cartopy.crs as ccrs
import cartopy.feature as cfeature
import numpy as np
proj = ccrs.LambertConformal(central_longitude=-110, central_latitude=40)
fig, ax = plt.subplots(figsize=(6,6), facecolor="w", dpi=86, subplot_kw=dict(projection=proj))
ax.set_title('Land Use Type: Western United States', fontsize=15)
im = ax.pcolormesh(xx, yy, zz, transform=ccrs.PlateCarree(), cmap=cmap, norm=norm)
ax.set_extent([-125, -95, 30, 50], crs=ccrs.PlateCarree())
res = '110m'
ax.add_feature(cfeature.LAND.with_scale(res))
ax.add_feature(cfeature.OCEAN.with_scale(res))
ax.add_feature(cfeature.COASTLINE.with_scale(res))
ax.add_feature(cfeature.LAKES.with_scale(res), alpha=0.5)
ax.add_feature(cfeature.STATES.with_scale(res), lw=0.5, alpha=.5)
labels, handles = zip(*[(k, mpatches.Rectangle((0, 0), 1, 1, facecolor=v)) for k,v in lc_colors.items()])
ax.legend(handles, labels, loc=4, framealpha=1)
Or instead of using the last two lines from the snippet above, use the result from pcolormesh
with a colorbar:
cb = fig.colorbar(im, ax=ax, shrink=.3, aspect=8)
cb.set_ticks(bounds[:-1]+0.5)
cb.set_ticklabels(lc_classes.keys())
Using a proper legend with the proxy artists is probably better from a dataviz perspective, since a colorbar might suggest some sort of order to the classes.
Upvotes: 2