86 votes

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

J'ai un graphique où différentes couleurs sont utilisées pour différents paramètres, et où différents styles de lignes 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 lignes 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 de réaliser cela ? Comment ?

Voici à quoi ressemble mon code en réalité :

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()

122voto

Mu Mind Points 5142

Il y a une section dans la documentation de matplotlib sur ce sujet exact .

Voici le code pour 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 son résultat : Plot with 2 legends, per-param and per-algo

24voto

Maxime Beau Points 429

Voici également une façon plus "pratique" de le faire (c'est-à-dire en interagissant explicitement avec les axes des figures) :

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 d'une manière moins obscure. Vous pouvez d'abord créer votre ensemble de légendes, puis les ajouter aux axes que vous voulez avec la méthode "add_artist". Aussi, je commence avec matplotlib, et pour moi au moins il 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/la sauvegarde. Pour résoudre ce problème, utilisez la méthode axes.set_position([left, bottom, width, length]) pour rétrécir le sous-graphe par rapport à la taille de la figure et faire apparaître les légendes.

9voto

Tojur Points 101

Et si vous utilisiez un axe fantôme double ?

import matplotlib.pyplot as plt
import numpy as np

fig, ax = plt.subplots()

colors = ['b', 'r', 'g', ]
styles = ['-', '--', '-.']

for cc, col in enumerate(colors):
    for ss, sty in enumerate(styles):
        print(cc, ss)
        ax.plot([0, 1], [cc, ss], c=colors[cc], ls=styles[ss])

for cc, col in enumerate(colors):
    ax.plot(np.NaN, np.NaN, c=colors[cc], label=col)

ax2 = ax.twinx()
for ss, sty in enumerate(styles):
    ax2.plot(np.NaN, np.NaN, ls=styles[ss],
             label='style ' + str(ss), c='black')
ax2.get_yaxis().set_visible(False)

ax.legend(loc=1)
ax2.legend(loc=3)

plt.show()

enter image description here

1voto

Paul Chen Points 320

Vous pouvez également utiliser line.get_label()

import matplotlib.pyplot as plt

plt.figure()

colors = ['b', 'r', 'g', 'c']
parameters = [1,2,3,4]
for p in parameters:

  color = colors[parameters.index(p)]
  plt.plot([1,10],[1,p], '-', c=color, label='auto label '+str(p))

lines = plt.gca().get_lines()
include = [0,1]
legend1 = plt.legend([lines[i] for i in include],[lines[i].get_label() for i in include], loc=1)
legend2 = plt.legend([lines[i] for i in [2,3]],['manual label 3','manual label 4'], loc=4)
plt.gca().add_artist(legend1)
plt.show()

Auto and manual labels

0voto

Hardiksoni Points 1
import matplotlib.pyplot as plt

plt.figure()

colors = ['b', 'r', 'g', 'c']
parameters = [1,2,3,4]
for p in parameters:

  color = colors[parameters.index(p)]
  plt.plot([1,10],[1,p], '-', c=color, label='auto label '+str(p))

lines = plt.gca().get_lines()
include = [0,1]
legend1 = plt.legend([lines[i] for i in include],[lines[i].get_label() for i in include], loc=1)
legend2 = plt.legend([lines[i] for i in [2,3]],['manual label 3','manual label 4'], loc=4)
plt.gca().add_artist(legend1)
plt.show()

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X