26
votes

I am creating a stacked line/area plot using plt.fill_between() method of the pyplot, and after trying so many things I am still not able to figure why it is not displaying any legend or labels (even when I provide them in the code). Here is the code:

import matplotlib.pyplot as plt
import numpy

a1_label = 'record a1'
a2_label = 'record a2'

a1 = numpy.linspace(0,100,40)
a2 = numpy.linspace(30,100,40)

x = numpy.arange(0, len(a1), 1)

plt.fill_between(x, 0, a1, facecolor='green')
plt.fill_between(x, a1, a2, facecolor='red')
plt.title('some title')
plt.grid('on')
plt.legend([a1_label, a2_label])
plt.show()

Here is the image generated (note that the legend shows empty box instead of labels): empty legend box at the top

Help!

4
I'm not there? Quite odd. Try also assigning plots into the parameter for the legend. As well as locations. - user1181445
no luck! :-/ I tried this thing. - khan

4 Answers

40
votes

The fill_between() command creates a PolyCollection that is not supported by the legend() command.

Therefore you will have to use another matplotlib artist (compatible with legend()) as a proxy, without adding it to the axes (so the proxy artist will not be drawn in the main axes) and feed it to the legend function. (see the matplotlib legend guide for more details)

In your case, the code below should fix your problem:

from matplotlib.patches import Rectangle

p1 = Rectangle((0, 0), 1, 1, fc="green")
p2 = Rectangle((0, 0), 1, 1, fc="red")
legend([p1, p2], [a1_label, a2_label])

image

19
votes

gcalmettes's answer was a helpful start, but I wanted my legend to pick up the colors that the stackplot had automatically assigned. Here's how I did it:

polys = pyplot.stackplot(x, y)
legendProxies = []
for poly in polys:
    legendProxies.append(pyplot.Rectangle((0, 0), 1, 1, fc=poly.get_facecolor()[0]))
18
votes

Another, arguably easier, technique is to plot an empty data set, and use it's legend entry:

plt.plot([], [], color='green', linewidth=10)
plt.plot([], [], color='red', linewidth=10)

This works well if you have other data labels for the legend, too:

enter image description here

4
votes

Only to give an update about this matter as I as looking for it. At 2016, PolyCollection already provide support to the label attribute as you can see:

https://github.com/matplotlib/matplotlib/pull/3303#event-182205203