Search code examples
pythonmatplotliblegendlegend-properties

Legend using PathCollections


I'm plotting groups of circles using collections and I am not able to generate the legend of the three categories. I want:

  • Cat 1: red circles
  • Cat 2: blue circles
  • Cat 3: yellow circles
import matplotlib
import matplotlib.pyplot as plt
from matplotlib.collections import PatchCollection
from matplotlib.patches import Circle
import numpy as np

# (modified from one of the matplotlib gallery examples)
resolution = 50 # the number of vertices
N = 50
Na = 25
Nb = 10
x        = np.random.random(N)
y       = np.random.random(N)
radii   = 0.1*np.random.random(30)

xa       = np.random.random(Na)
ya       = np.random.random(Na)
radiia   = 0.1*np.random.random(50)


xb       = np.random.random(Nb)
yb       = np.random.random(Nb)
radiib   = 0.1*np.random.random(60)

patches = []
patchesa = []
patchesb = []
for x1,y1,r in zip(x, y, radii):
     circle = Circle((x1,y1), r)
     patches.append(circle)

for x1,y1,r in zip(xa, ya, radiia):
    circle = Circle((x1,y1), r)
    patchesa.append(circle)

for x1,y1,r in zip(xb, yb, radiib):
    circle = Circle((x1,y1), r)
    patchesb.append(circle)


fig = plt.figure()
ax = fig.add_subplot(111)

colors = 100*np.random.random(N)
p = PatchCollection(patches, cmap=matplotlib.cm.jet, alpha=0.4, label= "Cat 1", facecolor="red")
pa = PatchCollection(patchesa, cmap=matplotlib.cm.jet, alpha=0.3, label= "Cat 2", facecolor="blue")
pb = PatchCollection(patchesb, cmap=matplotlib.cm.jet, alpha=0.4, label= "Cat 3", facecolor="yellow")
#p.set_array(colors)
ax.add_collection(p)
ax.add_collection(pa)
ax.add_collection(pb)
ax.legend(loc = 2)
plt.colorbar(p)

print p.get_label()

plt.show()

PathCollections are not iterable objects, so trying to generate the legend the following way;

legend([p, pa, pb], ["cat 1", "2 cat", "cat 3"])

does not work.

How can the caption to appear?

My system run on Python 2.7 and Matplotlib 1.2.0_1

Note that the command print p.get_label() shows that the object has an associated label, but matplotlib is unable to mount the legend.


Solution

  • One possible solution is to add Line2D objects to use in the legend, also known as using proxy artists. To achieve this you have to add from matplotlib.lines import Line2D to your script, and then you can replace this code:

    ax.legend(loc = 2)
    plt.colorbar(p)
    
    print p.get_label()
    

    with this:

    circ1 = Line2D([0], [0], linestyle="none", marker="o", alpha=0.4, markersize=10, markerfacecolor="red")
    circ2 = Line2D([0], [0], linestyle="none", marker="o", alpha=0.3, markersize=10, markerfacecolor="blue")
    circ3 = Line2D([0], [0], linestyle="none", marker="o", alpha=0.4, markersize=10, markerfacecolor="yellow")
    
    plt.legend((circ1, circ2, circ3), ("Cat 1", "Cat 2", "Cat 3"), numpoints=1, loc="best")
    

    enter image description here