Guide de légende #

Générer des légendes de manière flexible dans Matplotlib.

Ce guide de légende est une extension de la documentation disponible sur legend()- veuillez vous assurer que vous êtes familiarisé avec le contenu de cette documentation avant de continuer avec ce guide.

Ce guide utilise certains termes courants, qui sont documentés ici pour plus de clarté :

entrée de légende #

Une légende est composée d'une ou plusieurs entrées de légende. Une entrée est composée exactement d'une clé et d'un libellé.

clé de légende #

Marqueur coloré/motif à gauche de chaque étiquette de légende.

étiquette de légende #

Le texte qui décrit le handle représenté par la clé.

poignée de légende #

L'objet d'origine qui est utilisé pour générer une entrée appropriée dans la légende.

Contrôle des entrées de légende #

L'appel legend()sans argument récupère automatiquement les poignées de légende et leurs étiquettes associées. Cette fonctionnalité équivaut à :

handles, labels = ax.get_legend_handles_labels()
ax.legend(handles, labels)

La get_legend_handles_labels()fonction renvoie une liste de poignées/artistes qui existent sur les axes qui peuvent être utilisés pour générer des entrées pour la légende résultante - il convient de noter cependant que tous les artistes ne peuvent pas être ajoutés à une légende, auquel cas un "proxy" sera doivent être créés (voir Création d'artistes spécifiquement pour l'ajout à la légende (aka. Artistes mandataires) pour plus de détails).

Noter

Les artistes avec une chaîne vide comme étiquette ou avec une étiquette commençant par un trait de soulignement, "_", seront ignorés.

Pour un contrôle total de ce qui est ajouté à la légende, il est courant de passer les poignées appropriées directement à legend():

fig, ax = plt.subplots()
line_up, = ax.plot([1, 2, 3], label='Line 2')
line_down, = ax.plot([3, 2, 1], label='Line 1')
ax.legend(handles=[line_up, line_down])

Dans certains cas, il n'est pas possible de définir le libellé de la poignée, il est donc possible de passer par la liste des libellés pour legend():

fig, ax = plt.subplots()
line_up, = ax.plot([1, 2, 3], label='Line 2')
line_down, = ax.plot([3, 2, 1], label='Line 1')
ax.legend([line_up, line_down], ['Line Up', 'Line Down'])

Créer des artistes spécifiquement pour ajouter à la légende (aka. Artistes proxy) #

Toutes les poignées ne peuvent pas être automatiquement transformées en entrées de légende, il est donc souvent nécessaire de créer un artiste qui peut . Les poignées de légende ne doivent pas nécessairement exister sur la figure ou les axes pour être utilisées.

Supposons que nous voulions créer une légende contenant une entrée pour certaines données représentées par une couleur rouge :

import matplotlib.patches as mpatches
import matplotlib.pyplot as plt

fig, ax = plt.subplots()
red_patch = mpatches.Patch(color='red', label='The red data')
ax.legend(handles=[red_patch])

plt.show()
guide de légende

Il existe de nombreuses poignées de légende prises en charge. Au lieu de créer un patch de couleur, nous aurions pu créer une ligne avec un marqueur :

import matplotlib.lines as mlines

fig, ax = plt.subplots()
blue_line = mlines.Line2D([], [], color='blue', marker='*',
                          markersize=15, label='Blue stars')
ax.legend(handles=[blue_line])

plt.show()
guide de légende

Emplacement de la légende #

L'emplacement de la légende peut être spécifié par l'argument mot-clé loc . Veuillez consulter la documentation sur legend()pour plus de détails.

Le bbox_to_anchormot-clé donne un grand degré de contrôle pour le placement manuel de la légende. Par exemple, si vous souhaitez que la légende de vos axes soit située dans le coin supérieur droit de la figure au lieu du coin des axes, spécifiez simplement l'emplacement du coin et le système de coordonnées de cet emplacement :

ax.legend(bbox_to_anchor=(1, 1),
          bbox_transform=fig.transFigure)

Autres exemples de placement de légende personnalisé :

fig, ax_dict = plt.subplot_mosaic([['top', 'top'], ['bottom', 'BLANK']],
                                  empty_sentinel="BLANK")
ax_dict['top'].plot([1, 2, 3], label="test1")
ax_dict['top'].plot([3, 2, 1], label="test2")
# Place a legend above this subplot, expanding itself to
# fully use the given bounding box.
ax_dict['top'].legend(bbox_to_anchor=(0., 1.02, 1., .102), loc='lower left',
                      ncol=2, mode="expand", borderaxespad=0.)

ax_dict['bottom'].plot([1, 2, 3], label="test1")
ax_dict['bottom'].plot([3, 2, 1], label="test2")
# Place a legend to the right of this smaller subplot.
ax_dict['bottom'].legend(bbox_to_anchor=(1.05, 1),
                         loc='upper left', borderaxespad=0.)

plt.show()
guide de légende

Légendes multiples sur les mêmes Axes #

Parfois, il est plus clair de répartir les entrées de légende sur plusieurs légendes. Bien que l'approche instinctive pour ce faire puisse être d'appeler la legend()fonction plusieurs fois, vous constaterez qu'une seule légende existe sur les Axes. Cela a été fait pour qu'il soit possible d'appeler à legend()plusieurs reprises pour mettre à jour la légende avec les dernières poignées sur les axes. Pour conserver les anciennes instances de légende, nous devons les ajouter manuellement aux Axes :

fig, ax = plt.subplots()
line1, = ax.plot([1, 2, 3], label="Line 1", linestyle='--')
line2, = ax.plot([3, 2, 1], label="Line 2", linewidth=4)

# Create a legend for the first line.
first_legend = ax.legend(handles=[line1], loc='upper right')

# Add the legend manually to the Axes.
ax.add_artist(first_legend)

# Create another legend for the second line.
ax.legend(handles=[line2], loc='lower right')

plt.show()
guide de légende

Gestionnaires de légende #

Afin de créer des entrées de légende, des poignées sont données comme argument à une HandlerBasesous-classe appropriée. Le choix de la sous-classe de gestionnaire est déterminé par les règles suivantes :

  1. Mettez à jour get_legend_handler_map() avec la valeur du mot- handler_mapclé.

  2. Vérifiez si le handleest dans le nouveau fichier handler_map.

  3. Vérifiez si le type de handlese trouve dans le nouveau fichier handler_map.

  4. Vérifiez si l'un des types du handlemro du est dans le nouveau fichier handler_map.

Pour être complet, cette logique est principalement implémentée dans get_legend_handler().

Toute cette flexibilité signifie que nous avons les crochets nécessaires pour implémenter des gestionnaires personnalisés pour notre propre type de clé de légende.

legend_handler.HandlerBaseL'exemple le plus simple d'utilisation de gestionnaires personnalisés consiste à instancier l'une des sous-classes existantes . Par souci de simplicité, choisissons legend_handler.HandlerLine2D celui qui accepte un argument numpoints (numpoints est également un mot clé sur la legend()fonction pour plus de commodité). Nous pouvons ensuite transmettre le mappage d'instance à Handler en tant que mot-clé de légende.

from matplotlib.legend_handler import HandlerLine2D

fig, ax = plt.subplots()
line1, = ax.plot([3, 2, 1], marker='o', label='Line 1')
line2, = ax.plot([1, 2, 3], marker='o', label='Line 2')

ax.legend(handler_map={line1: HandlerLine2D(numpoints=4)})
guide de légende
<matplotlib.legend.Legend object at 0x7f2cf9a16ef0>

Comme vous pouvez le voir, "Ligne 1" a maintenant 4 points de repère, où "Ligne 2" en a 2 (la valeur par défaut). Essayez le code ci-dessus, changez uniquement la clé de la carte de line1à type(line1). Remarquez comment les deux Line2Dinstances obtiennent maintenant 4 marqueurs.

En plus des gestionnaires pour les types de tracés complexes tels que les barres d'erreur, les tracés de tiges et les histogrammes, la valeur par défaut handler_mapa un tuplegestionnaire spécial ( legend_handler.HandlerTuple) qui trace simplement les poignées les unes sur les autres pour chaque élément du tuple donné. L'exemple suivant illustre la combinaison de deux clés de légende l'une sur l'autre :

from numpy.random import randn

z = randn(10)

fig, ax = plt.subplots()
red_dot, = ax.plot(z, "ro", markersize=15)
# Put a white cross over some of the data.
white_cross, = ax.plot(z[:5], "w+", markeredgewidth=3, markersize=15)

ax.legend([red_dot, (red_dot, white_cross)], ["Attr A", "Attr A+B"])
guide de légende
<matplotlib.legend.Legend object at 0x7f2cfb693760>

La legend_handler.HandlerTupleclasse peut également être utilisée pour affecter plusieurs clés de légende à une même entrée :

from matplotlib.legend_handler import HandlerLine2D, HandlerTuple

fig, ax = plt.subplots()
p1, = ax.plot([1, 2.5, 3], 'r-d')
p2, = ax.plot([3, 2, 1], 'k-o')

l = ax.legend([(p1, p2)], ['Two keys'], numpoints=1,
              handler_map={tuple: HandlerTuple(ndivide=None)})
guide de légende

Implémentation d'un gestionnaire de légende personnalisé #

Un gestionnaire personnalisé peut être implémenté pour transformer n'importe quelle poignée en clé de légende (les poignées n'ont pas nécessairement besoin d'être des artistes matplotlib). Le gestionnaire doit implémenter une legend_artistméthode qui renvoie un seul artiste pour la légende à utiliser. La signature requise pour legend_artistest documentée à legend_artist.

import matplotlib.patches as mpatches


class AnyObject:
    pass


class AnyObjectHandler:
    def legend_artist(self, legend, orig_handle, fontsize, handlebox):
        x0, y0 = handlebox.xdescent, handlebox.ydescent
        width, height = handlebox.width, handlebox.height
        patch = mpatches.Rectangle([x0, y0], width, height, facecolor='red',
                                   edgecolor='black', hatch='xx', lw=3,
                                   transform=handlebox.get_transform())
        handlebox.add_artist(patch)
        return patch

fig, ax = plt.subplots()

ax.legend([AnyObject()], ['My first handler'],
          handler_map={AnyObject: AnyObjectHandler()})
guide de légende
<matplotlib.legend.Legend object at 0x7f2cddb26a10>

Alternativement, si nous avions voulu accepter globalement les AnyObjectinstances sans avoir à définir manuellement le mot-clé handler_map tout le temps, nous aurions pu enregistrer le nouveau gestionnaire avec :

from matplotlib.legend import Legend
Legend.update_default_handler_map({AnyObject: AnyObjectHandler()})

Bien que la puissance ici soit claire, rappelez-vous qu'il existe déjà de nombreux gestionnaires implémentés et que ce que vous voulez réaliser peut déjà être facilement réalisable avec les classes existantes. Par exemple, pour produire des clés de légende elliptiques plutôt que rectangulaires :

from matplotlib.legend_handler import HandlerPatch


class HandlerEllipse(HandlerPatch):
    def create_artists(self, legend, orig_handle,
                       xdescent, ydescent, width, height, fontsize, trans):
        center = 0.5 * width - 0.5 * xdescent, 0.5 * height - 0.5 * ydescent
        p = mpatches.Ellipse(xy=center, width=width + xdescent,
                             height=height + ydescent)
        self.update_prop(p, orig_handle, legend)
        p.set_transform(trans)
        return [p]


c = mpatches.Circle((0.5, 0.5), 0.25, facecolor="green",
                    edgecolor="red", linewidth=3)

fig, ax = plt.subplots()

ax.add_patch(c)
ax.legend([c], ["An ellipse, not a rectangle"],
          handler_map={mpatches.Circle: HandlerEllipse()})
guide de légende
<matplotlib.legend.Legend object at 0x7f2d00dde710>

Durée totale d'exécution du script : (0 minutes 3,053 secondes)

Galerie générée par Sphinx-Gallery