web-dev-qa-db-fra.com

Comment l'ordre des articles dans la légende matplotlib est-il déterminé?

Je dois réorganiser des articles dans une légende, quand je ne pense pas que je devrais le faire. J'essaie:

from pylab import *
clf()
ax=gca()
ht=ax.add_patch(Rectangle((1,1),1,1,color='r',label='Top',alpha=.01))
h1=ax.bar(1,2,label='Middle')
hb=ax.add_patch(Rectangle((1,1),1,1,color='k',label='Bottom',alpha=.01))
legend()
show()

et finir avec Bas au-dessus du milieu. Comment puis-je obtenir la bonne commande? N'est-il pas déterminé par l'ordre de création?

Code results in the wrong legend item order

Mise à jour: Les éléments suivants peuvent être utilisés pour forcer la commande. Je pense que c'est peut-être la façon la plus simple de le faire, et cela semble gênant. La question est de savoir ce qui détermine la commande d'origine?

hh=[ht,h1,hb]
legend([ht,h1.patches[0],hb],[H.get_label() for H in hh])
48
CPBL

L'ordre est déterministe, mais une partie des tripes privées peut donc être modifiée à tout moment, voir le code ici (le self.* les éléments sont des listes des artistes qui ont été ajoutés, la liste des descripteurs est donc triée d'abord par type, ensuite par ordre d'ajout).

Si vous souhaitez contrôler explicitement l'ordre des éléments dans votre légende, assemblez une liste de gestionnaires et d'étiquettes comme vous l'avez fait dans votre édition.

11
tacaswell

Voici un extrait rapide pour trier les entrées dans une légende. Il suppose que vous avez déjà ajouté vos éléments de tracé avec une étiquette, par exemple, quelque chose comme

ax.plot(..., label='label1')
ax.plot(..., label='label2')

puis le bit principal:

handles, labels = ax.get_legend_handles_labels()
# sort both labels and handles by labels
labels, handles = Zip(*sorted(Zip(labels, handles), key=lambda t: t[0]))
ax.legend(handles, labels)

Ceci est juste une simple adaptation du code répertorié sur http://matplotlib.org/users/legend_guide.html

62
kevin

Une légère variation sur quelques autres demandes. La liste order doit avoir la même longueur que le nombre d'éléments de légende et spécifie la nouvelle commande manuellement.

handles, labels = plt.gca().get_legend_handles_labels()
order = [0,2,1]
plt.legend([handles[idx] for idx in order],[labels[idx] for idx in order])
23
Ian Hincks

La fonction suivante recherche les poignées et étiquettes de légende, et les trie, ou les trie partiellement, selon une liste donnée (order):

#  Returns Tuple of handles, labels for axis ax, after reordering them to conform to the label order `order`, and if unique is True, after removing entries with duplicate labels.
def reorderLegend(ax=None,order=None,unique=False):
    if ax is None: ax=plt.gca()
    handles, labels = ax.get_legend_handles_labels()
    labels, handles = Zip(*sorted(Zip(labels, handles), key=lambda t: t[0])) # sort both labels and handles by labels
    if order is not None: # Sort according to a given list (not necessarily complete)
        keys=dict(Zip(order,range(len(order))))
        labels, handles = Zip(*sorted(Zip(labels, handles), key=lambda t,keys=keys: keys.get(t[0],np.inf)))
    if unique:  labels, handles= Zip(*unique_everseen(Zip(labels,handles), key = labels)) # Keep only the first of each handle
    ax.legend(handles, labels)
    return(handles, labels)


def unique_everseen(seq, key=None):
    seen = set()
    seen_add = seen.add
    return [x for x,k in Zip(seq,key) if not (k in seen or seen_add(k))]

La fonction sous forme mise à jour est en cpblUtilities.mathgraph sur https://gitlab.com/cpbl/cpblUtilities/blob/master/mathgraph.py

Citations: Kevin (cette page) et Markus Jarderot ( Comment supprimer les doublons d'une liste tout en préservant l'ordre? ).

1
CPBL