pythonmatplotlibgiscartopycontourf

How to create legend with proxy artist for contourf plot


I am trying to create a graphic where I overlay multiple contour plots on a single image. So I want to have colorbars for each of the plots, as well as a legend indicating what each contour represents. However Matplotlib will not allow me to create a separate legend for my contour plots. Simple example:

import matplotlib as mpl
import matplotlib.pyplot as plt
import cartopy
import cartopy.crs as ccrs
import numpy as np



def create_contour(i,j):
    colors = ["red","green","blue"]
    hatches = ['-','+','x','//','*']
    fig = plt.figure()
    ax = plt.axes(projection=ccrs.PlateCarree())
    ax.set_extent((-15.0,15.0,-15.0,15.0))
    delta = 0.25
    x = np.arange(-3.0,3.0,delta)
    y = np.arange(-2.0,2.0,delta)
    X, Y = np.meshgrid(x, y)
    data = np.full(np.shape(X), 1.0)
    plot = ax.contourf(X,Y,data, levels = [float(i),float(i+1)], hatch=[hatches[j]], colors = colors[i], label="label")
    plt.legend(handles=[plot], labels=["label"])
    plt.savefig("figure_"+str(i)+".png")

create_contour(1,3)

When I run this, I get the following message:

UserWarning: Legend does not support (matplotlib.contour.QuadContourSet object at 0x7fa69df7cac8) instances. A proxy artist may be used instead. See: http://matplotlib.org/users/legend_guide.html#creating-artists-specifically-for-adding-to-the-legend-aka-proxy-artists "aka-proxy-artists".format(orig_handle)

But as far as I can tell, I am following those directions as closely as possible, the only difference being that they do not use contourf in the example.

Any help would be greatly appreciated.


Solution

  • The comments to your question look like they have solved the question (by making custom patches and passing those through to the legend). There is also an example that I added many years ago to the matplotlib documentation to do something similar (about the same time I added contour hatching to matplotlib): https://matplotlib.org/examples/pylab_examples/contourf_hatching.html#pylab-examples-contourf-hatching

    It is such a reasonable request that there is even a method on the contour set to give you legend proxies out of the box: ContourSet.legend_elements.

    So your example might look something like:

    %matplotlib inline
    
    import matplotlib.pyplot as plt
    import cartopy.crs as ccrs
    import numpy as np
    
    
    fig = plt.figure(figsize=(10, 10))
    ax = plt.axes(projection=ccrs.PlateCarree())
    ax.coastlines('10m')
    
    y = np.linspace(40.0, 60.0, 30)
    x = np.linspace(-10.0, 10.0, 40)
    X, Y = np.meshgrid(x, y)
    data = 2*np.cos(2*X**2/Y) - np.sin(Y**X)
    
    cs = ax.contourf(X, Y, data, 3,
                     hatches=['//','+','x','o'],
                     alpha=0.5)
    artists, labels = cs.legend_elements()
    
    plt.legend(handles=artists, labels=labels)
    
    plt.show()
    

    enter image description here