matplotlib Multiple Legends on the Same Axes


Example

If you call plt.legend() or ax.legend() more than once, the first legend is removed and a new one is drawn. According the official documentation:

This has been done so that it is possible to call legend() repeatedly to update the legend to the latest handles on the Axes

Fear not, though: It is still quite simple to add a second legend (or third, or fourth...) to an axes. In the example here, we plot two lines, then plot markers on their respective maxima and minima. One legend is for the lines, and the other is for the markers.

import matplotlib.pyplot as plt
import numpy as np

# Generate data for plotting:  
x = np.linspace(0,2*np.pi,100)
y0 = np.sin(x)
y1 = .9*np.sin(.9*x)
# Find their maxima and minima and store
maxes = np.empty((2,2))
mins = np.empty((2,2))
for k,y in enumerate([y0,y1]):
    maxloc = y.argmax()
    maxes[k] = x[maxloc], y[maxloc]
    minloc = y.argmin()
    mins[k] = x[minloc], y[minloc]

# Instantiate figure and plot
fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot(x,y0, label='y0')
ax.plot(x,y1, label='y1')
# Plot maxima and minima, and keep references to the lines
maxline, = ax.plot(maxes[:,0], maxes[:,1], 'r^')
minline, = ax.plot(mins[:,0], mins[:,1], 'ko')

# Add first legend:  only labeled data is included
leg1 = ax.legend(loc='lower left')
# Add second legend for the maxes and mins.
# leg1 will be removed from figure
leg2 = ax.legend([maxline,minline],['max','min'], loc='upper right')
# Manually add the first legend back
ax.add_artist(leg1)

enter image description here

The key is to make sure you have references to the legend objects. The first one you instantiate (leg1) is removed from the figure when you add the second one, but the leg1 object still exists and can be added back with ax.add_artist.

The really great thing is that you can can still manipulate both legends. For example, add the following to the bottom of the above code:

leg1.get_lines()[0].set_lw(8)
leg2.get_texts()[1].set_color('b')

enter image description here

Finally, it's worth mentioning that in the example only the lines were given labels when plotted, meaning that ax.legend() adds only those lines to the leg1. The legend for the markers (leg2) therefore required the lines and labels as arguments when it was instantiated. We could have, alternatively, given labels to the markers when they were plotted too. But then both calls to ax.legend would have required some extra arguments so that each legend contained only the items we wanted.