web-dev-qa-db-fra.com

matplotlib: 2 légendes différentes sur un même graphique

J'ai un tracé où différentes couleurs sont utilisées pour différents paramètres, et où différents styles de ligne sont utilisés pour différents algorithmes. Le but est de comparer les résultats des différents algorithmes réalisés avec des paramètres similaires. Cela signifie qu'au total, j'utilise 4 couleurs différentes et 3 styles de ligne différents, pour un total de 12 tracés sur le même graphique.

En fait, je construis la légende en fonction des couleurs, en associant chaque couleur au paramètre correspondant. J'aimerais maintenant afficher une deuxième légende sur le même graphique, avec la signification de chaque style de ligne. Est-il possible d'y parvenir? Comment?

Voici à quoi ressemble mon code:

colors = ['b', 'r', 'g', 'c']
cc = cycle(c)
for p in parameters:

    d1 = algo1(p)
    d2 = algo2(p)
    d3 = algo3(p)

    pyplot.hold(True)
    c = next(cc)
    pyplot.plot(d1, '-', color=c, label="d1")
    pyplot.plot(d1, '--', color=c)
    pyplot.plot(d2, '.-', color=c)

pyplot.legend()
56
Charles Brunet

Il y a une section dans la documentation de matplotlib sur ce sujet exact: http://matplotlib.org/users/legend_guide.html#multiple-legends-on-the-same-axes

Voici le code de votre exemple spécifique:

import itertools
from matplotlib import pyplot

colors = ['b', 'r', 'g', 'c']
cc = itertools.cycle(colors)
plot_lines = []
for p in parameters:

    d1 = algo1(p)
    d2 = algo2(p)
    d3 = algo3(p)

    pyplot.hold(True)
    c = next(cc)
    l1, = pyplot.plot(d1, '-', color=c)
    l2, = pyplot.plot(d2, '--', color=c)
    l3, = pyplot.plot(d3, '.-', color=c)

    plot_lines.append([l1, l2, l3])

legend1 = pyplot.legend(plot_lines[0], ["algo1", "algo2", "algo3"], loc=1)
pyplot.legend([l[0] for l in plot_lines], parameters, loc=4)
pyplot.gca().add_artist(legend1)

Voici un exemple de sa sortie: Plot with 2 legends, per-param and per-algo

75
Mu Mind

Voici également une façon plus "pratique" de le faire (c'est-à-dire d'interagir explicitement avec n'importe quel axe de figure):

import itertools
from matplotlib import pyplot

fig, axes = plt.subplot(1,1)

colors = ['b', 'r', 'g', 'c']
cc = itertools.cycle(colors)
plot_lines = []
for p in parameters:

    d1 = algo1(p)
    d2 = algo2(p)
    d3 = algo3(p)

    c = next(cc)
    axes.plot(d1, '-', color=c)
    axes.plot(d2, '--', color=c)
    axes.plot(d3, '.-', color=c)

# In total 3x3 lines have been plotted
lines = axes.get_lines()
legend1 = pyplot.legend([lines[i] for i in [0,1,2]], ["algo1", "algo2", "algo3"], loc=1)
legend2 = pyplot.legend([lines[i] for i in [0,3,6]], parameters, loc=4)
axes.add_artist(legend1)
axes.add_artist(legend2)

J'aime cette façon de l'écrire car elle permet potentiellement de jouer avec différents axes de manière moins obscure. Vous pouvez d'abord créer votre ensemble de légendes, puis les ajouter aux axes de votre choix avec la méthode "add_artist". Aussi, je commence par matplotlib, et pour moi au moins c'est plus facile de comprendre les scripts quand les objets sont explicités.

NB: Attention, vos légendes peuvent être coupées lors de l'affichage/sauvegarde. Pour résoudre ce problème, utilisez la méthode axes.set_position ([gauche, bas, largeur, longueur]) pour réduire le sous-tracé par rapport à la taille de la figure et faire apparaître les légendes.

8
Maxime Beau