web-dev-qa-db-fra.com

Arrêtez matplotlib de répéter les étiquettes dans la légende

Voici un exemple très simplifié:

xvalues = [2,3,4,6]

for x in xvalues:
    plt.axvline(x,color='b',label='xvalues')

plt.legend()

La légende affichera maintenant 'xvalues' sous la forme d'une ligne bleue 4 fois dans la légende . Existe-t-il une manière plus élégante de corriger cela que la suivante?

for i,x in enumerate(xvalues):
    if not i:
        plt.axvline(x,color='b',label='xvalues')
    else:
        plt.axvline(x,color='b')
44
Anake

legend prend comme argument une liste de descripteurs d'axe et d'étiquettes, par défaut à plt.gca().get_legend_handles_labels(). Vous pouvez supprimer les étiquettes en double lorsque vous appelez legend, par exemple:

from collections import OrderedDict
import matplotlib.pyplot as plt

handles, labels = plt.gca().get_legend_handles_labels()
by_label = OrderedDict(Zip(labels, handles))
plt.legend(by_label.values(), by_label.keys())
73
ecatmur
handles, labels = ax.get_legend_handles_labels()
handle_list, label_list = [], []
for handle, label in Zip(handles, labels):
    if label not in label_list:
        handle_list.append(handle)
        label_list.append(label)
plt.legend(handle_list, label_list)
6
Matthew Bourque

Ces extraits de code ne fonctionnaient pas pour moi personnellement. Je dessinais deux groupes différents dans deux couleurs différentes. La légende indiquait deux marqueurs rouges et deux marqueurs bleus, alors que je voulais seulement en voir un par couleur. Je vais coller une version simplifiée de ce qui a fonctionné pour moi:

Déclarations d'importation

import matplotlib.pyplot as plt

from matplotlib.legend_handler import HandlerLine2D

Données de parcelle

points_grp, = plt.plot(x[grp_idx], y[grp_idx], color=c.c[1], marker=m, ms=4, lw=0, label=leglab[1])        
points_ctrl, = plt.plot(x[ctrl_idx], y[ctrl_idx], color=c.c[0], marker=m, ms=4, lw=0, label=leglab[0])

Ajouter une légende

points_dict = {points_grp: HandlerLine2D(numpoints=1),points_ctrl: HandlerLine2D(numpoints=1)}
leg = ax.legend(fontsize=12, loc='upper left', bbox_to_anchor=(1, 1.03),handler_map=points_dict)
1
Kirstin Aschbacher

Je ne sais pas si cela peut être considéré comme "élégant", mais vous pouvez attribuer à votre étiquette une variable dont la valeur est définie sur "_nolegend_" après la première utilisation:

my_label = "xvalues"
xvalues = [2,3,4,6]

for x in xvalues:
    plt.axvline(x, color='b', label=my_label)
    my_label = "_nolegend_"

plt.legend()

Ceci peut être généralisé à l'aide d'un dictionnaire d'étiquettes si vous devez en mettre plusieurs:

my_labels = {"x1" : "x1values", "x2" : "x2values"}
x1values = [1, 3, 5]
x2values = [2, 4, 6]

for x in x1values:
    plt.axvline(x, color='b', label=my_labels["x1"])
    my_labels["x1"] = "_nolegend_"
for x in x2values:
    plt.axvline(x, color='r', label=my_labels["x2"])
    my_labels["x2"] = "_nolegend_"

plt.legend()

 Figure with 2 different labels

(Réponse inspirée par https://stackoverflow.com/a/19386045/1878788 )

1
bli

Sur la base de answer https://stackoverflow.com/a/13589144/9132798 et https://stackoverflow.com/a/19386045/9132798plt.gca().get_legend_handles_labels()[1] donne une liste de noms, c'est possible de vérifier si l'étiquette est déjà dans la liste pendant le traçage en boucle (label= name[i] if name[i] not in plt.gca().get_legend_handles_labels()[1] else ''). Pour l'exemple donné, cette solution ressemblerait à ceci:

import matplotlib.pyplot as plt

xvalues = [2,3,4,6]

for x in xvalues:
    plt.axvline(x,color='b',\
    label= 'xvalues' if 'xvalues' \
            not in plt.gca().get_legend_handles_labels()[1] else '')

plt.legend()

Ce qui est beaucoup plus court que https://stackoverflow.com/a/13589144/9132798 et plus flexible que https://stackoverflow.com/a/19386045/9132798 car il pourrait être utilisé pour n'importe quel type de boucle toute fonction de tracé dans la boucle individuellement . Cependant, pour de nombreux cycles, elle est probablement plus lente que https://stackoverflow.com/a/13589144/9132798 .

0
Tobias Wegener