Legenden-Anleitung#

Diese Legenden-Anleitung erweitert die legend-Dokumentation – bitte lesen Sie diese, bevor Sie mit dieser Anleitung fortfahren.

Diese Anleitung verwendet einige gängige Begriffe, die hier zur Klarheit dokumentiert sind

Legendereintrag#

Eine Legende besteht aus einem oder mehreren Legenden-Einträgen. Ein Eintrag besteht aus genau einem Schlüssel und einer Beschriftung.

Legenden-Schlüssel#

Der farbige/gemusterte Marker links neben jeder Legenden-Beschriftung.

Legenden-Beschriftung#

Der Text, der das vom Schlüssel dargestellte Handle beschreibt.

Legenden-Handle#

Das ursprüngliche Objekt, das zur Erzeugung eines geeigneten Eintrags in der Legende verwendet wird.

Steuerung der Legenden-Einträge#

Das Aufrufen von legend() ohne Argumente ruft automatisch die Legenden-Handles und ihre zugehörigen Beschriftungen ab. Diese Funktionalität ist äquivalent zu

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

Die Funktion get_legend_handles_labels() gibt eine Liste von Handles/Künstlern zurück, die sich auf den Achsen befinden und zur Erzeugung von Einträgen für die resultierende Legende verwendet werden können – es ist jedoch zu beachten, dass nicht alle Künstler zu einer Legende hinzugefügt werden können, woraufhin ein "Proxy" erstellt werden muss (siehe Erstellung von Künstlern speziell für die Hinzufügung zur Legende (auch Proxy-Künstler genannt) für weitere Details).

Hinweis

Künstler mit einer leeren Zeichenkette als Beschriftung oder mit einer Beschriftung, die mit einem Unterstrich beginnt ("_"), werden ignoriert.

Für die vollständige Kontrolle darüber, was zur Legende hinzugefügt wird, ist es üblich, die entsprechenden Handles direkt an legend() zu übergeben.

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

Umbenennen von Legenden-Einträgen#

Wenn die Beschriftungen nicht direkt auf den Handles gesetzt werden können, können sie direkt an Axes.legend übergeben werden.

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'])

Wenn die Handles nicht direkt zugänglich sind, z. B. bei Verwendung einiger Drittanbieter-Pakete, können sie über Axes.get_legend_handles_labels abgerufen werden. Hier verwenden wir ein Wörterbuch, um bestehende Beschriftungen umzubenennen.

my_map = {'Line Up':'Up', 'Line Down':'Down'}

handles, labels = ax.get_legend_handles_labels()
ax.legend(handles, [my_map[l] for l in labels])

Erstellung von Künstlern speziell für die Hinzufügung zur Legende (auch Proxy-Künstler genannt)#

Nicht alle Handles können automatisch in Legenden-Einträge umgewandelt werden, daher ist es oft notwendig, einen Künstler zu erstellen, der dies *kann*. Legenden-Handles müssen nicht auf der Figur oder den Achsen vorhanden sein, um verwendet zu werden.

Angenommen, wir möchten eine Legende erstellen, die einen Eintrag für einige Daten hat, die durch eine rote Farbe dargestellt werden.

import matplotlib.pyplot as plt

import matplotlib.patches as mpatches

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

plt.show()
legend guide

Es gibt viele unterstützte Legenden-Handles. Anstatt eine Farbfläche zu erstellen, hätten wir auch eine Linie mit einem Marker erstellen können.

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

Legenden-Position#

Die Position der Legende kann durch das Schlüsselwortargument loc angegeben werden. Weitere Details finden Sie in der Dokumentation unter legend().

Das Schlüsselwort bbox_to_anchor bietet ein hohes Maß an Kontrolle für die manuelle Platzierung von Legenden. Wenn Sie beispielsweise möchten, dass Ihre Achsen-Legende in der oberen rechten Ecke der Figur und nicht in der Ecke der Achsen platziert wird, geben Sie einfach die Position der Ecke und das Koordinatensystem dieser Position an.

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

Weitere Beispiele für benutzerdefinierte Legendenplatzierung

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',
                      ncols=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.)
legend guide

Figuren-Legenden#

Manchmal ist es sinnvoller, eine Legende relativ zur (Teil-)Figur statt zu einzelnen Achsen zu platzieren. Durch die Verwendung von constrained layout und die Angabe von "outside" am Anfang des loc-Schlüsselwortarguments wird die Legende außerhalb der Achsen auf der (Teil-)Figur gezeichnet.

fig, axs = plt.subplot_mosaic([['left', 'right']], layout='constrained')

axs['left'].plot([1, 2, 3], label="test1")
axs['left'].plot([3, 2, 1], label="test2")

axs['right'].plot([1, 2, 3], 'C2', label="test3")
axs['right'].plot([3, 2, 1], 'C3', label="test4")
# Place a legend to the right of this smaller subplot.
fig.legend(loc='outside upper right')
legend guide

Dies akzeptiert eine leicht andere Grammatik als das normale loc-Schlüsselwort, wobei "outside right upper" sich von "outside upper right" unterscheidet.

ucl = ['upper', 'center', 'lower']
lcr = ['left', 'center', 'right']
fig, ax = plt.subplots(figsize=(6, 4), layout='constrained', facecolor='0.7')

ax.plot([1, 2], [1, 2], label='TEST')
# Place a legend to the right of this smaller subplot.
for loc in [
        'outside upper left',
        'outside upper center',
        'outside upper right',
        'outside lower left',
        'outside lower center',
        'outside lower right']:
    fig.legend(loc=loc, title=loc)

fig, ax = plt.subplots(figsize=(6, 4), layout='constrained', facecolor='0.7')
ax.plot([1, 2], [1, 2], label='test')

for loc in [
        'outside left upper',
        'outside right upper',
        'outside left lower',
        'outside right lower']:
    fig.legend(loc=loc, title=loc)
  • legend guide
  • legend guide

Mehrere Legenden auf denselben Achsen#

Manchmal ist es klarer, Legenden-Einträge auf mehrere Legenden aufzuteilen. Während der instinktive Ansatz dafür darin bestehen mag, die Funktion legend() mehrmals aufzurufen, werden Sie feststellen, dass nur eine Legende auf den Achsen existiert. Dies wurde getan, damit es möglich ist, legend() wiederholt aufzurufen, um die Legende mit den neuesten Handles auf den Achsen zu aktualisieren. Um alte Legendeninstanzen zu behalten, müssen wir sie manuell zu den Achsen hinzufügen.

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

Legenden-Handler#

Um Legenden-Einträge zu erstellen, werden Handles als Argument an eine geeignete Unterklasse von HandlerBase übergeben. Die Wahl der Handler-Unterklasse wird durch die folgenden Regeln bestimmt.

  1. Aktualisieren Sie get_legend_handler_map() mit dem Wert im Schlüsselwort handler_map.

  2. Prüfen Sie, ob das handle im neu erstellten handler_map vorhanden ist.

  3. Prüfen Sie, ob der Typ des handle im neu erstellten handler_map vorhanden ist.

  4. Prüfen Sie, ob einer der Typen im MRO des handle im neu erstellten handler_map vorhanden ist.

Der Vollständigkeit halber ist diese Logik größtenteils in get_legend_handler() implementiert.

All diese Flexibilität bedeutet, dass wir die notwendigen Haken haben, um benutzerdefinierte Handler für unsere eigene Art von Legenden-Schlüssel zu implementieren.

Das einfachste Beispiel für die Verwendung benutzerdefinierter Handler ist die Instanziierung einer der vorhandenen Unterklassen von legend_handler.HandlerBase. Der Einfachheit halber wählen wir legend_handler.HandlerLine2D, das ein numpoints-Argument akzeptiert (numpoints ist auch ein Schlüsselwort in der Funktion legend() zur Bequemlichkeit). Wir können dann die Zuordnung von Instanz zu Handler als Schlüsselwort an legend übergeben.

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)}, handlelength=4)
legend guide

Wie Sie sehen können, hat "Line 1" nun 4 Marker-Punkte, während "Line 2" 2 hat (Standard). Wir haben auch die Länge der Handles mit dem Schlüsselwort handlelength erhöht, um zum größeren Legenden-Eintrag zu passen. Versuchen Sie den obigen Code, ändern Sie nur den Schlüssel des Maps von line1 zu type(line1). Beachten Sie, wie nun beide Line2D-Instanzen 4 Marker erhalten.

Zusammen mit Handlern für komplexe Plottypen wie Fehlerbalken, Stem-Plots und Histogramme hat die Standard- handler_map einen speziellen tuple-Handler (legend_handler.HandlerTuple), der einfach die Handles übereinander für jedes Element im gegebenen Tupel zeichnet. Das folgende Beispiel zeigt die Kombination von zwei Legenden-Schlüsseln übereinander.

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"])
legend guide

Die Klasse legend_handler.HandlerTuple kann auch verwendet werden, um mehrere Legenden-Schlüssel demselben Eintrag zuzuweisen.

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)})
legend guide

Implementierung eines benutzerdefinierten Legenden-Handlers#

Ein benutzerdefinierter Handler kann implementiert werden, um jeden Handle in einen Legenden-Schlüssel zu verwandeln (Handles müssen nicht unbedingt Matplotlib-Künstler sein). Der Handler muss eine Methode legend_artist implementieren, die einen einzelnen Künstler für die Legende zurückgibt. Die erforderliche Signatur für legend_artist ist unter legend_artist dokumentiert.

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()})
legend guide

Alternativ hätten wir, wenn wir AnyObject-Instanzen global akzeptieren wollen, ohne ständig das Schlüsselwort handler_map manuell setzen zu müssen, den neuen Handler registrieren können mit.

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

Obwohl die Macht hier klar ist, denken Sie daran, dass bereits viele Handler implementiert sind und das, was Sie erreichen möchten, möglicherweise bereits mit vorhandenen Klassen leicht möglich ist. Zum Beispiel, um elliptische Legenden-Schlüssel anstelle von rechteckigen zu erzeugen.

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()})
legend guide

Gesamtlaufzeit des Skripts: (0 Minuten 6,610 Sekunden)

Galerie generiert von Sphinx-Gallery