Nota
Fare clic qui per scaricare il codice di esempio completo
Guida alla leggenda #
Generare legende in modo flessibile in Matplotlib.
Questa guida alla legenda è un'estensione della documentazione disponibile all'indirizzo
legend()
: assicurati di conoscere i contenuti di tale documentazione prima di procedere con questa guida.
Questa guida fa uso di alcuni termini comuni, qui documentati per maggiore chiarezza:
- voce legenda #
Una legenda è composta da una o più voci della legenda. Una voce è composta esattamente da una chiave e da un'etichetta.
- chiave legenda #
L'indicatore colorato/motivo a sinistra di ogni etichetta della legenda.
- etichetta legenda #
Il testo che descrive l'handle rappresentato dalla chiave.
- maniglia della legenda #
L'oggetto originale utilizzato per generare una voce appropriata nella legenda.
Controllo delle voci della legenda #
La chiamata legend()
senza argomenti recupera automaticamente gli handle della legenda e le etichette associate. Questa funzionalità equivale a:
handles, labels = ax.get_legend_handles_labels()
ax.legend(handles, labels)
La get_legend_handles_labels()
funzione restituisce un elenco di handle/artisti esistenti sugli assi che possono essere utilizzati per generare voci per la legenda risultante - vale la pena notare tuttavia che non tutti gli artisti possono essere aggiunti a una legenda, a quel punto un "proxy" verrà devono essere creati (vedi Creazione di artisti appositamente per l'aggiunta alla legenda (ovvero artisti proxy) per ulteriori dettagli).
Nota
Gli artisti con una stringa vuota come etichetta o con un'etichetta che inizia con un carattere di sottolineatura, "_", verranno ignorati.
Per il controllo completo di ciò che viene aggiunto alla legenda, è comune passare gli handle appropriati direttamente a 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])
In alcuni casi non è possibile impostare l'etichetta dell'handle, quindi è possibile passare dall'elenco delle etichette a 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'])
Creazione di artisti appositamente per l'aggiunta alla legenda (ovvero artisti proxy) #
Non tutte le maniglie possono essere trasformate automaticamente in voci di legenda, quindi è spesso necessario creare un artista che possa . Le maniglie della legenda non devono esistere sulla figura o sugli assi per essere utilizzate.
Supponiamo di voler creare una legenda che abbia una voce per alcuni dati che è rappresentata da un colore rosso:
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()
Esistono molti handle di legenda supportati. Invece di creare una macchia di colore avremmo potuto creare una linea con un pennarello:
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()
Posizione della legenda n.
La posizione della legenda può essere specificata dall'argomento della parola chiave
loc . Consultare la documentazione all'indirizzo legend()
per ulteriori dettagli.
La bbox_to_anchor
parola chiave offre un elevato grado di controllo per il posizionamento manuale della legenda. Ad esempio, se desideri che la legenda degli assi si trovi nell'angolo in alto a destra della figura anziché nell'angolo degli assi, specifica semplicemente la posizione dell'angolo e il sistema di coordinate di quella posizione:
Altri esempi di posizionamento personalizzato della legenda:
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()
Più legende sugli stessi assi #
A volte è più chiaro suddividere le voci della legenda in più legende. Mentre l'approccio istintivo per farlo potrebbe essere quello di chiamare la legend()
funzione più volte, scoprirai che esiste solo una leggenda sugli assi. Ciò è stato fatto in modo che sia possibile richiamare legend()
ripetutamente per aggiornare la legenda agli ultimi handle sugli assi. Per mantenere le vecchie istanze della legenda, dobbiamo aggiungerle manualmente agli assi:
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()
Gestori della leggenda n.
Per creare voci di legenda, gli handle vengono forniti come argomento a una HandlerBase
sottoclasse appropriata. La scelta della sottoclasse del gestore è determinata dalle seguenti regole:
Aggiorna
get_legend_handler_map()
con il valore nellahandler_map
parola chiave.Controlla se
handle
è nel filehandler_map
.Controlla se il tipo di
handle
è nel filehandler_map
.Controlla se qualcuno dei tipi in
handle
's mro è nel file appena creatohandler_map
.
Per completezza, questa logica è per lo più implementata in
get_legend_handler()
.
Tutta questa flessibilità significa che abbiamo gli hook necessari per implementare gestori personalizzati per il nostro tipo di chiave legenda.
L'esempio più semplice di utilizzo di gestori personalizzati consiste nell'istanziare una delle legend_handler.HandlerBase
sottoclassi esistenti. Per semplicità, scegliamo legend_handler.HandlerLine2D
quale accetta un argomento numpoints (numpoints è anche una parola chiave della legend()
funzione per comodità). Possiamo quindi passare la mappatura dell'istanza a Handler come parola chiave a legend.
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)})
<matplotlib.legend.Legend object at 0x7f2cf9a16ef0>
Come puoi vedere, "Linea 1" ora ha 4 punti marcatore, mentre "Linea 2" ne ha 2 (impostazione predefinita). Prova il codice sopra, cambia solo la chiave della mappa da line1
a
type(line1)
. Nota come ora entrambe le Line2D
istanze ottengono 4 marcatori.
Insieme ai gestori per tipi di grafici complessi come barre di errore, grafici stem e istogrammi, l'impostazione predefinita handler_map
ha un tuple
gestore speciale ( legend_handler.HandlerTuple
) che traccia semplicemente le maniglie una sopra l'altra per ogni elemento nella tupla data. L'esempio seguente mostra la combinazione di due tasti legenda uno sopra l'altro:
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"])
<matplotlib.legend.Legend object at 0x7f2cfb693760>
La legend_handler.HandlerTuple
classe può anche essere utilizzata per assegnare più chiavi di legenda alla stessa voce:
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)})
Implementazione di un gestore di legende personalizzato #
È possibile implementare un gestore personalizzato per trasformare qualsiasi handle in una chiave di legenda (gli handle non devono necessariamente essere artisti matplotlib). Il gestore deve implementare un legend_artist
metodo che restituisca un singolo artista per la legenda da utilizzare. La firma richiesta per legend_artist
è documentata in
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()})
<matplotlib.legend.Legend object at 0x7f2cddb26a10>
In alternativa, se avessimo voluto accettare globalmente le AnyObject
istanze senza dover impostare manualmente la parola chiave handler_map per tutto il tempo, avremmo potuto registrare il nuovo gestore con:
from matplotlib.legend import Legend
Legend.update_default_handler_map({AnyObject: AnyObjectHandler()})
Sebbene il potere qui sia chiaro, ricorda che ci sono già molti gestori implementati e ciò che vuoi ottenere potrebbe già essere facilmente possibile con le classi esistenti. Ad esempio, per produrre chiavi di legenda ellittiche, anziché rettangolari:
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()})
<matplotlib.legend.Legend object at 0x7f2d00dde710>
Tempo di esecuzione totale dello script: (0 minuti 3,053 secondi)