J'ai remarqué qu'aucune réponse n'affiche une image avec une seule légende référençant de nombreuses courbes dans différentes sous-parcelles, donc je dois vous en montrer une ... pour vous rendre curieux ...
Maintenant, vous voulez regarder le code, n'est-ce pas?
from numpy import linspace
import matplotlib.pyplot as plt
# Calling the axes.prop_cycle returns an itertoools.cycle
color_cycle = plt.rcParams['axes.prop_cycle']()
# I need some curves to plot
x = linspace(0, 1, 51)
f1 = x*(1-x) ; lab1 = 'x - x x'
f2 = 0.25-f1 ; lab2 = '1/4 - x + x x'
f3 = x*x*(1-x) ; lab3 = 'x x - x x x'
f4 = 0.25-f3 ; lab4 = '1/4 - x x + x x x'
# let's plot our curves (note the use of color cycle, otherwise the curves colors in
# the two subplots will be repeated and a single legend becomes difficult to read)
fig, (a13, a24) = plt.subplots(2)
a13.plot(x, f1, label=lab1, **next(color_cycle))
a13.plot(x, f3, label=lab3, **next(color_cycle))
a24.plot(x, f2, label=lab2, **next(color_cycle))
a24.plot(x, f4, label=lab4, **next(color_cycle))
# so far so good, now the trick
lines_labels = [ax.get_legend_handles_labels() for ax in fig.axes]
lines, labels = [sum(lol, []) for lol in zip(*lines_labels)]
# finally we invoke the legend (that you probably would like to customize...)
fig.legend(lines, labels)
plt.show()
Les deux lignes
lines_labels = [ax.get_legend_handles_labels() for ax in fig.axes]
lines, labels = [sum(lol, []) for lol in zip(*lines_labels)]
mérite une explication - dans ce but, j'ai encapsulé la partie délicate dans une fonction, juste 4 lignes de code mais fortement commenté
def fig_legend(fig, **kwdargs):
# generate a sequence of tuples, each contains
# - a list of handles (lohand) and
# - a list of labels (lolbl)
tuples_lohand_lolbl = (ax.get_legend_handles_labels() for ax in fig.axes)
# e.g. a figure with two axes, ax0 with two curves, ax1 with one curve
# yields: ([ax0h0, ax0h1], [ax0l0, ax0l1]) and ([ax1h0], [ax1l0])
# legend needs a list of handles and a list of labels,
# so our first step is to transpose our data,
# generating two tuples of lists of homogeneous stuff(tolohs), i.e
# we yield ([ax0h0, ax0h1], [ax1h0]) and ([ax0l0, ax0l1], [ax1l0])
tolohs = zip(*tuples_lohand_lolbl)
# finally we need to concatenate the individual lists in the two
# lists of lists: [ax0h0, ax0h1, ax1h0] and [ax0l0, ax0l1, ax1l0]
# a possible solution is to sum the sublists - we use unpacking
handles, labels = (sum(list_of_lists, []) for list_of_lists in tolohs)
# call fig.legend with the keyword arguments, return the legend object
return fig.legend(handles, labels, **kwdargs)
PS Je reconnais que sum(list_of_lists, [])
c'est une méthode vraiment inefficace pour aplatir une liste de listes mais ① j'aime sa compacité, ② est généralement quelques courbes dans quelques sous-graphiques et ③ Matplotlib et l'efficacité? ;-)