Come mettere la leggenda fuori dalla trama


988

Ho una serie di 20 trame (non trame secondarie) da realizzare in un'unica figura. Voglio che la leggenda sia fuori dagli schemi. Allo stesso tempo, non voglio cambiare gli assi, poiché la dimensione della figura viene ridotta. Aiutatemi gentilmente per le seguenti domande:

  1. Voglio mantenere la casella della legenda fuori dall'area della trama. (Voglio che la legenda sia all'esterno sul lato destro dell'area della trama).
  2. C'è comunque che riduco la dimensione del carattere del testo all'interno della casella della legenda, in modo che la dimensione della casella della legenda sia piccola.

14
Per le versioni più recenti di matplotlib, questa risposta mostra come impostare matplotlib per determinare automaticamente dove posizionare la legenda senza interferire con i grafici .
dotancohen,

2
Aveva la stessa domanda e ho trovato questo grande esempio che ha funzionato per me "out of the box": matplotlib.org/1.3.1/users/legend_guide.html
robodasha

1
Questa risposta ha più profondità https://stackoverflow.com/a/43439132/52074. e lo fa con due righe di codice! la risposta migliorata di +1200 è buona, ma l'ho trovata meno generica.
Trevor Boyd Smith,

2
@dotancohen "determina automaticamente dove posizionare la legenda senza interferire con le trame" In alcuni casi, quando la trama ha molte curve, è purtroppo impossibile. In questi casi l'utente potrebbe voler posizionare manualmente la legenda e in effetti posizionarla al di fuori dell'area del grafico. Sto avendo difficoltà con una trama del genere in questo momento.
Ali,

tra l'altro, l'elenco delle scelte di loc: migliore; In alto a destra; superiore sinistro; in basso a sinistra; in basso a destra; destra; centro a sinistra; al centro a destra; centro inferiore; centro superiore; centro;
Z-Y00,

Risposte:


57

Puoi ridurre il testo della legenda creando le proprietà del carattere:

from matplotlib.font_manager import FontProperties

fontP = FontProperties()
fontP.set_size('small')
legend([plot1], "title", prop=fontP) 
# or add prop=fontP to whatever legend() call you already have

50
cosa c'è plot1in questa risposta?
Paul H,

41
cosa c'è legendin questa risposta?
Richard,

28
Questo risponde alla parte secondaria della domanda, ma non a quella primaria (quella che è intitolata).
Mateen Ulhaq,

8
Inoltre, il modo corretto per farlo èplt.legend(fontsize='small')
Mateen Ulhaq,

41
Questa risposta è terribile e fornisce pochissimo contesto!
Tekill,

1797

Esistono diversi modi per fare ciò che vuoi. Per aggiungere ciò che hanno già detto @inalis e @Navi, è possibile utilizzare l' bbox_to_anchorargomento della parola chiave per posizionare la legenda parzialmente all'esterno degli assi e / o ridurre la dimensione del carattere.

Prima di considerare di ridurre la dimensione del carattere (che può rendere le cose terribilmente difficili da leggere), prova a giocare posizionando la legenda in luoghi diversi:

Quindi, iniziamo con un esempio generico:

import matplotlib.pyplot as plt
import numpy as np

x = np.arange(10)

fig = plt.figure()
ax = plt.subplot(111)

for i in xrange(5):
    ax.plot(x, i * x, label='$y = %ix$' % i)

ax.legend()

plt.show()

testo alternativo

Se facciamo la stessa cosa, ma utilizziamo l' bbox_to_anchorargomento della parola chiave, possiamo spostare leggermente la legenda fuori dai confini degli assi:

import matplotlib.pyplot as plt
import numpy as np

x = np.arange(10)

fig = plt.figure()
ax = plt.subplot(111)

for i in xrange(5):
    ax.plot(x, i * x, label='$y = %ix$' % i)

ax.legend(bbox_to_anchor=(1.1, 1.05))

plt.show()

testo alternativo

Allo stesso modo, puoi rendere la legenda più orizzontale e / o metterla nella parte superiore della figura (sto anche ruotando gli angoli arrotondati e una semplice ombra esterna):

import matplotlib.pyplot as plt
import numpy as np

x = np.arange(10)

fig = plt.figure()
ax = plt.subplot(111)

for i in xrange(5):
    line, = ax.plot(x, i * x, label='$y = %ix$'%i)

ax.legend(loc='upper center', bbox_to_anchor=(0.5, 1.05),
          ncol=3, fancybox=True, shadow=True)
plt.show()

testo alternativo

In alternativa, puoi ridurre la larghezza della trama corrente e mettere la legenda completamente al di fuori dell'asse della figura (nota: se usi tight_layout () , allora lascia fuori ax.set_position ():

import matplotlib.pyplot as plt
import numpy as np

x = np.arange(10)

fig = plt.figure()
ax = plt.subplot(111)

for i in xrange(5):
    ax.plot(x, i * x, label='$y = %ix$'%i)

# Shrink current axis by 20%
box = ax.get_position()
ax.set_position([box.x0, box.y0, box.width * 0.8, box.height])

# Put a legend to the right of the current axis
ax.legend(loc='center left', bbox_to_anchor=(1, 0.5))

plt.show()

testo alternativo

E in modo simile, puoi ridurre la trama verticalmente e mettere una legenda orizzontale in basso:

import matplotlib.pyplot as plt
import numpy as np

x = np.arange(10)

fig = plt.figure()
ax = plt.subplot(111)

for i in xrange(5):
    line, = ax.plot(x, i * x, label='$y = %ix$'%i)

# Shrink current axis's height by 10% on the bottom
box = ax.get_position()
ax.set_position([box.x0, box.y0 + box.height * 0.1,
                 box.width, box.height * 0.9])

# Put a legend below current axis
ax.legend(loc='upper center', bbox_to_anchor=(0.5, -0.05),
          fancybox=True, shadow=True, ncol=5)

plt.show()

testo alternativo

Dai un'occhiata alla guida della legenda di matplotlib . Potresti anche dare un'occhiata plt.figlegend().


10
Se qualcuno ha problemi con questo, nota che tight_layout () causerà problemi!
Matthew G.

4
Bella risposta! il link corretto al documento è matplotlib.org/users/legend_guide.html#legend-location
meduz,

4
come completezza, si potrebbe dire che in generale (riassunto dal documento) " bbox_to_anchorè una tupla di 4 galleggianti (x, y, larghezza, altezza del bbox) o una tupla di 2 galleggianti (x, y) in assi normalizzati coordinate ".
meduz,

5
Devo ammettere che questa è probabilmente la mia risposta SO più visitata di sempre. Non posso fare a meno di tornarci più volte perché non c'è modo in cui una persona ragionevole possa ricordare questa logica senza guardarla qui.
KT.

9
Si noti che se si desidera salvare la figura in un file, probabilmente è necessario memorizzare l'oggetto restituito, vale a dire legend = ax.legend()e successivamentefig.savefig(bbox_extra_artists=(legend,))
coldfix

793

Posizionamento della legenda ( bbox_to_anchor)

Una legenda viene posizionata all'interno del rettangolo di selezione degli assi usando l' locargomento to plt.legend.
Ad esempio loc="upper right"posiziona la legenda nell'angolo in alto a destra del rettangolo di selezione, che per impostazione predefinita si estende da (0,0)a (1,1)in coordinate degli assi (o nella notazione del rettangolo di selezione (x0,y0, width, height)=(0,0,1,1)).

Per posizionare la legenda all'esterno del rettangolo di selezione degli assi, è possibile specificare una tupla (x0,y0)di coordinate degli assi nell'angolo inferiore sinistro della legenda.

plt.legend(loc=(1.04,0))

Tuttavia, un approccio più versatile sarebbe quello di specificare manualmente il rettangolo di selezione in cui inserire la legenda, usando l' bbox_to_anchorargomento. Ci si può limitare a fornire solo la (x0,y0)parte della bbox. Questo crea una casella di span zero, fuori dalla quale la legenda si espanderà nella direzione data locdall'argomento. Per esempio

plt.legend (bbox_to_anchor = (1.04,1), loc = "in alto a sinistra")

posiziona la legenda fuori dagli assi, in modo tale che l'angolo superiore sinistro della legenda sia in posizione (1.04,1)nelle coordinate degli assi.

Ulteriori esempi sono riportati di seguito, in cui sono mostrate anche l'interazione tra diversi argomenti come modee ncols.

inserisci qui la descrizione dell'immagine

l1 = plt.legend(bbox_to_anchor=(1.04,1), borderaxespad=0)
l2 = plt.legend(bbox_to_anchor=(1.04,0), loc="lower left", borderaxespad=0)
l3 = plt.legend(bbox_to_anchor=(1.04,0.5), loc="center left", borderaxespad=0)
l4 = plt.legend(bbox_to_anchor=(0,1.02,1,0.2), loc="lower left",
                mode="expand", borderaxespad=0, ncol=3)
l5 = plt.legend(bbox_to_anchor=(1,0), loc="lower right", 
                bbox_transform=fig.transFigure, ncol=3)
l6 = plt.legend(bbox_to_anchor=(0.4,0.8), loc="upper right")

I dettagli su come interpretare l'argomento in 4 tuple bbox_to_anchorcome, come in l4, sono disponibili in questa domanda . Il mode="expand"espande la legenda orizzontalmente all'interno del rettangolo di selezione in 4 parametri. Per una legenda espansa verticalmente, vedi questa domanda .

A volte può essere utile specificare il riquadro di delimitazione nelle coordinate della figura anziché nelle coordinate degli assi. Questo è mostrato nell'esempio l5dall'alto, in cui l' bbox_transformargomento viene utilizzato per posizionare la legenda nell'angolo in basso a sinistra della figura.

Post produzione

Avere posto la legenda fuori dagli assi spesso porta alla situazione indesiderata che è completamente o parzialmente al di fuori della tela della figura.

Le soluzioni a questo problema sono:

  • Regola i parametri della sottotrama
    È possibile regolare i parametri della sottotrama in modo tale che gli assi occupino meno spazio all'interno della figura (e quindi lasciano più spazio alla legenda) utilizzando plt.subplots_adjust. Per esempio

    plt.subplots_adjust(right=0.7)

    lascia il 30% di spazio sul lato destro della figura, dove è possibile posizionare la legenda.

  • Layout stretto
    Utilizzo plt.tight_layoutConsente di regolare automaticamente i parametri della sottotrama in modo tale che gli elementi nella figura siano ben aderenti ai bordi della figura. Sfortunatamente, la leggenda non viene presa in considerazione in questo automatismo, ma possiamo fornire una scatola rettangolare in cui si adatterà l'intera area delle sottotrame (comprese le etichette).

    plt.tight_layout(rect=[0,0,0.75,1])
  • Salvare la figura conbbox_inches = "tight"
    L'argomento bbox_inches = "tight"su plt.savefigpuò essere usato per salvare la figura in modo tale che tutti gli artisti sulla tela (inclusa la legenda) siano adatti all'area salvata. Se necessario, la dimensione della figura viene regolata automaticamente.

    plt.savefig("output.png", bbox_inches="tight")
  • regolazione automatica dei parametri della sottotrama
    Un modo per regolare automaticamente la posizione della sottotrama in modo tale che la legenda si adatti all'interno della tela senza cambiare la dimensione della figura si trova in questa risposta: Creazione di una figura con dimensioni esatte e nessuna imbottitura (e legenda fuori dagli assi)

Confronto tra i casi discussi sopra:

inserisci qui la descrizione dell'immagine

alternative

Una figura legenda
Uno può utilizzare una legenda alla figura invece degli assi, matplotlib.figure.Figure.legend. Ciò è diventato particolarmente utile per la versione matplotlib> = 2.1, dove non sono necessari argomenti speciali

fig.legend(loc=7) 

per creare una leggenda per tutti gli artisti nei diversi assi della figura. La legenda viene posizionata usando l' locargomento, in modo simile al modo in cui è posizionata all'interno di un asse, ma in riferimento all'intera figura - quindi sarà fuori dagli assi in qualche modo automaticamente. Ciò che rimane è regolare i grafici secondari in modo tale che non vi siano sovrapposizioni tra la legenda e gli assi. Qui sarà utile il punto "Regola i parametri della sottotrama" dall'alto. Un esempio:

import numpy as np
import matplotlib.pyplot as plt

x = np.linspace(0,2*np.pi)
colors=["#7aa0c4","#ca82e1" ,"#8bcd50","#e18882"]
fig, axes = plt.subplots(ncols=2)
for i in range(4):
    axes[i//2].plot(x,np.sin(x+i), color=colors[i],label="y=sin(x+{})".format(i))

fig.legend(loc=7)
fig.tight_layout()
fig.subplots_adjust(right=0.75)   
plt.show()

inserisci qui la descrizione dell'immagine

Legenda all'interno degli assi della sottotrama dedicata
Un'alternativa all'utilizzo bbox_to_anchorsarebbe quella di posizionare la legenda nei suoi assi della trama secondaria dedicata ( lax). Poiché la sottotrama della legenda dovrebbe essere più piccola della trama, possiamo usarla gridspec_kw={"width_ratios":[4,1]}durante la creazione degli assi. Siamo in grado di nascondere gli assi lax.axis("off"), ma ancora messo una leggenda. Le maniglie leggenda e le etichette devono ottenuto dalla trama vera via h,l = ax.get_legend_handles_labels(), e può quindi essere fornito alla leggenda nella laxsottotrama, lax.legend(h,l). Un esempio completo è di seguito.

import matplotlib.pyplot as plt
plt.rcParams["figure.figsize"] = 6,2

fig, (ax,lax) = plt.subplots(ncols=2, gridspec_kw={"width_ratios":[4,1]})
ax.plot(x,y, label="y=sin(x)")
....

h,l = ax.get_legend_handles_labels()
lax.legend(h,l, borderaxespad=0)
lax.axis("off")

plt.tight_layout()
plt.show()

Questo produce una trama che è visivamente abbastanza simile alla trama dall'alto:

inserisci qui la descrizione dell'immagine

Potremmo anche usare i primi assi per posizionare la legenda, ma usare il bbox_transformdegli assi della legenda,

ax.legend(bbox_to_anchor=(0,0,1,1), bbox_transform=lax.transAxes)
lax.axis("off")

In questo approccio, non è necessario ottenere esternamente gli handle di legenda, ma è necessario specificare l' bbox_to_anchorargomento.

Ulteriori letture e note:

  • Considera la guida della legenda matplotlib con alcuni esempi di altre cose che vuoi fare con le leggende.
  • Alcuni codici di esempio per il posizionamento di legende per grafici a torta possono essere trovati direttamente in risposta a questa domanda: Python - La legenda si sovrappone al grafico a torta
  • L' locargomento può accettare numeri anziché stringhe, il che rende le chiamate più brevi, tuttavia non sono mappate in modo molto intuitivo tra loro. Ecco la mappatura per riferimento:

inserisci qui la descrizione dell'immagine


Mettere la legenda in un sottotrama dedicato sinergie molto bene con fig.tight_layout. Se stai usando plt.subplotsper creare gli assi, dagli qualcosa di simile gridspec_kw={'height_ratios': [100, 1]}(o width_ratios) in modo che gli assi della legenda siano minuscoli ... Quindi fig.tight_layout()espanderli per adattarli. Almeno per matplotlib 3.0.3.
travc

161

Chiama la legend()chiamata dopo la plot()chiamata in questo modo:

# matplotlib
plt.plot(...)
plt.legend(loc='center left', bbox_to_anchor=(1, 0.5))

# Pandas
df.myCol.plot().legend(loc='center left', bbox_to_anchor=(1, 0.5))

I risultati sarebbero simili al seguente:

inserisci qui la descrizione dell'immagine


4
funziona quando si passano gli stessi parametri anche a matplotlib.pyplot.legend
kidmose,

8
Questo interrompe le parole della leggenda per chiunque altro?
user1717828

85

Per posizionare la legenda fuori dall'area della trama, utilizzare loce bbox_to_anchorparole chiave di legend(). Ad esempio, il codice seguente posizionerà la legenda a destra dell'area della trama:

legend(loc="upper left", bbox_to_anchor=(1,1))

Per ulteriori informazioni, consultare la guida della legenda


10
Okay - Mi piace l'implementazione, ma quando vado a salvare la figura (senza ridimensionarla manualmente nella finestra, cosa che non voglio fare ogni volta), la legenda viene tagliata. Qualche idea su come potrei risolverlo?
astromax

@astromax non sono sicuro, ma forse prova a chiamare plt.tight_layout()?
Christian Alis

81

Risposta breve: puoi usare bbox_to_anchor+ bbox_extra_artists+ bbox_inches='tight'.


Risposta più lunga: è possibile utilizzare bbox_to_anchorper specificare manualmente la posizione della casella della legenda, come alcune persone hanno indicato nelle risposte.

Tuttavia, il solito problema è che la casella della legenda è ritagliata, ad esempio:

import matplotlib.pyplot as plt

# data 
all_x = [10,20,30]
all_y = [[1,3], [1.5,2.9],[3,2]]

# Plot
fig = plt.figure(1)
ax = fig.add_subplot(111)
ax.plot(all_x, all_y)

# Add legend, title and axis labels
lgd = ax.legend( [ 'Lag ' + str(lag) for lag in all_x], loc='center right', bbox_to_anchor=(1.3, 0.5))
ax.set_title('Title')
ax.set_xlabel('x label')
ax.set_ylabel('y label')

fig.savefig('image_output.png', dpi=300, format='png')

inserisci qui la descrizione dell'immagine

Per evitare che la casella della legenda venga ritagliata, quando si salva la figura è possibile utilizzare i parametri bbox_extra_artistse bbox_incheschiedere savefigdi includere elementi ritagliati nell'immagine salvata:

fig.savefig('image_output.png', bbox_extra_artists=(lgd,), bbox_inches='tight')

Esempio (ho modificato solo l'ultima riga per aggiungere 2 parametri a fig.savefig() ):

import matplotlib.pyplot as plt

# data 
all_x = [10,20,30]
all_y = [[1,3], [1.5,2.9],[3,2]]

# Plot
fig = plt.figure(1)
ax = fig.add_subplot(111)
ax.plot(all_x, all_y)

# Add legend, title and axis labels
lgd = ax.legend( [ 'Lag ' + str(lag) for lag in all_x], loc='center right', bbox_to_anchor=(1.3, 0.5))
ax.set_title('Title')
ax.set_xlabel('x label')
ax.set_ylabel('y label')    

fig.savefig('image_output.png', dpi=300, format='png', bbox_extra_artists=(lgd,), bbox_inches='tight')

inserisci qui la descrizione dell'immagine

Vorrei che matplotlib consentisse nativamente la posizione esterna per la casella della legenda come Matlab fa :

figure
x = 0:.2:12;
plot(x,besselj(1,x),x,besselj(2,x),x,besselj(3,x));
hleg = legend('First','Second','Third',...
              'Location','NorthEastOutside')
% Make the text of the legend italic and color it brown
set(hleg,'FontAngle','italic','TextColor',[.3,.2,.1])

inserisci qui la descrizione dell'immagine


6
Grazie mille! I parametri "bbox_to_anchor", "bbox_extra_artist" e "" bbox_inches = 'tight "erano esattamente ciò di cui avevo bisogno per farlo funzionare correttamente. Fantastico!
Demitrian

6
Grazie, ma in realtà bbox_inches='tight'funziona perfettamente per me anche senza bbox_extra_artist
avtomaton

1
@avtomaton Grazie, buono a sapersi, quale versione di matplotlib usi?
Franck Dernoncourt l'

1
@FranckDernoncourt python3, matplotlib versione 1.5.3
avtomaton

68

Oltre a tutte le eccellenti risposte qui, le versioni più recenti di matplotlibe pylabpossono determinare automaticamente dove posizionare la legenda senza interferire con i grafici , se possibile.

pylab.legend(loc='best')

Questo posizionerà automaticamente la legenda lontano dai dati, se possibile! Confronta l'uso di loc = 'best'

Tuttavia, se non c'è posto per mettere la legenda senza sovrapporre i dati, allora ti consigliamo di provare una delle altre risposte; l'utilizzo loc="best"non metterà mai la legenda fuori dalla trama.


2
Grazie per averlo sottolineato! L'ho cercato qualche anno fa e non l'ho trovato, ed è qualcosa che mi rende davvero più semplice la vita.
Edgar H,

4
questa opzione è utile ma non risponde alla domanda, quindi ho effettuato il downgrade. per quanto ne so, la cosa migliore non mette mai la leggenda fuori dalla trama
Tommy,

3
@ Tommy: Nei commenti dell'OP (che sembra essere sparito ora) è stato esplicitamente chiarito che l'OP voleva che la legenda non coprisse i dati del grafico, e pensava che al di fuori della trama fosse l'unico modo per farlo. Puoi vederlo nelle risposte di mefathy, Mateo Sanchez, Bastiaan e Radtek. Il PO ha chiesto per X, ma voleva Y .
dotancohen,

1
In realtà no. Chiede espressamente che la leggenda sia fuori dalla trama. È nel nome della domanda;) "Come mettere la leggenda fuori dalla trama".
durbachit,

4
Ciò non garantisce che la legenda non oscuri i dati. Crea una trama molto fitta: non c'è posto dove mettere la leggenda. Ad esempio, prova questo ... da numpy import arange, sin, pi import matplotlib.pyplot as plt t = arange (0.0, 100.0, 0.01) fig = plt.figure (1) ax1 = fig.add_subplot (211) ax1. scatter (t, sin (2 * pi * t), label = 'test') ax1.grid (True) # ax1.set_ylim ((- 2, 2)) ax1.set_ylabel ('1 Hz') ax1.set_title ( 'Un'onda sinusoidale o due') per l'etichetta in ax1.get_xticklabels (): label.set_color ('r') plt.legend (loc = 'best') plt.show ()
adam.r

56

Risposta breve : invoca trascinabile sulla legenda e spostala in modo interattivo dove vuoi:

ax.legend().draggable()

Risposta lunga : Se preferisci posizionare la legenda in modo interattivo / manuale piuttosto che a livello di programmazione, puoi attivare la modalità trascinabile della legenda in modo da poterla trascinare dove vuoi. Controlla l'esempio seguente:

import matplotlib.pylab as plt
import numpy as np
#define the figure and get an axes instance
fig = plt.figure()
ax = fig.add_subplot(111)
#plot the data
x = np.arange(-5, 6)
ax.plot(x, x*x, label='y = x^2')
ax.plot(x, x*x*x, label='y = x^3')
ax.legend().draggable()
plt.show()

Non sono sicuro di averlo capito appieno. Come posso "trascinare" la legenda dove voglio con questo? Sto usando Python 3.6 e Jupyter Notebook
sb2020 il

14

Non esattamente quello che hai chiesto, ma ho scoperto che è un'alternativa allo stesso problema. Rendi la legenda semitrasparente, in questo modo: trama matplotlib con legenda semitrasparente e casella di testo semitrasparente

Fallo con:

fig = pylab.figure()
ax = fig.add_subplot(111)
ax.plot(x,y,label=label,color=color)
# Make the legend transparent:
ax.legend(loc=2,fontsize=10,fancybox=True).get_frame().set_alpha(0.5)
# Make a transparent text box
ax.text(0.02,0.02,yourstring, verticalalignment='bottom',
                     horizontalalignment='left',
                     fontsize=10,
                     bbox={'facecolor':'white', 'alpha':0.6, 'pad':10},
                     transform=self.ax.transAxes)

8

Come notato, puoi anche posizionare la legenda nella trama, o leggermente al margine. Ecco un esempio usando l' API Plotly Python , realizzata con un Notebook IPython . Sono nella squadra.

Per iniziare, ti consigliamo di installare i pacchetti necessari:

import plotly
import math
import random
import numpy as np

Quindi, installa Plotly:

un='IPython.Demo'
k='1fw3zw2o13'
py = plotly.plotly(username=un, key=k)


def sin(x,n):
sine = 0
for i in range(n):
    sign = (-1)**i
    sine = sine + ((x**(2.0*i+1))/math.factorial(2*i+1))*sign
return sine

x = np.arange(-12,12,0.1)

anno = {
'text': '$\\sum_{k=0}^{\\infty} \\frac {(-1)^k x^{1+2k}}{(1 + 2k)!}$',
'x': 0.3, 'y': 0.6,'xref': "paper", 'yref': "paper",'showarrow': False,
'font':{'size':24}
}

l = {
'annotations': [anno], 
'title': 'Taylor series of sine',
'xaxis':{'ticks':'','linecolor':'white','showgrid':False,'zeroline':False},
'yaxis':{'ticks':'','linecolor':'white','showgrid':False,'zeroline':False},
'legend':{'font':{'size':16},'bordercolor':'white','bgcolor':'#fcfcfc'}
}

py.iplot([{'x':x, 'y':sin(x,1), 'line':{'color':'#e377c2'}, 'name':'$x\\\\$'},\
      {'x':x, 'y':sin(x,2), 'line':{'color':'#7f7f7f'},'name':'$ x-\\frac{x^3}{6}$'},\
      {'x':x, 'y':sin(x,3), 'line':{'color':'#bcbd22'},'name':'$ x-\\frac{x^3}{6}+\\frac{x^5}{120}$'},\
      {'x':x, 'y':sin(x,4), 'line':{'color':'#17becf'},'name':'$ x-\\frac{x^5}{120}$'}], layout=l)

Questo crea il tuo grafico e ti dà la possibilità di mantenere la legenda all'interno della trama stessa. L'impostazione predefinita per la legenda, se non è impostata, è posizionarla nella trama, come mostrato qui.

inserisci qui la descrizione dell'immagine

Per un posizionamento alternativo, è possibile allineare da vicino il bordo del grafico e il bordo della legenda e rimuovere le linee del bordo per un adattamento più stretto.

inserisci qui la descrizione dell'immagine

È possibile spostare e ridisegnare la legenda e il grafico con il codice o con la GUI. Per spostare la legenda, sono disponibili le seguenti opzioni per posizionare la legenda all'interno del grafico assegnando valori xey di <= 1. Ad esempio:

  • {"x" : 0,"y" : 0} -- In basso a sinistra
  • {"x" : 1, "y" : 0} -- In basso a destra
  • {"x" : 1, "y" : 1} -- In alto a destra
  • {"x" : 0, "y" : 1} -- In alto a sinistra
  • {"x" :.5, "y" : 0} - Centro inferiore
  • {"x": .5, "y" : 1} - In alto al centro

In questo caso, scegliamo in alto a destra, legendstyle = {"x" : 1, "y" : 1}descritto anche nella documentazione :

inserisci qui la descrizione dell'immagine


3

Qualcosa del genere ha funzionato per me. A partire da un po 'di codice preso da Joe, questo metodo modifica la larghezza della finestra in modo da adattare automaticamente una legenda a destra della figura.

import matplotlib.pyplot as plt
import numpy as np

plt.ion()

x = np.arange(10)

fig = plt.figure()
ax = plt.subplot(111)

for i in xrange(5):
    ax.plot(x, i * x, label='$y = %ix$'%i)

# Put a legend to the right of the current axis
leg = ax.legend(loc='center left', bbox_to_anchor=(1, 0.5))

plt.draw()

# Get the ax dimensions.
box = ax.get_position()
xlocs = (box.x0,box.x1)
ylocs = (box.y0,box.y1)

# Get the figure size in inches and the dpi.
w, h = fig.get_size_inches()
dpi = fig.get_dpi()

# Get the legend size, calculate new window width and change the figure size.
legWidth = leg.get_window_extent().width
winWidthNew = w*dpi+legWidth
fig.set_size_inches(winWidthNew/dpi,h)

# Adjust the window size to fit the figure.
mgr = plt.get_current_fig_manager()
mgr.window.wm_geometry("%ix%i"%(winWidthNew,mgr.window.winfo_height()))

# Rescale the ax to keep its original size.
factor = w*dpi/winWidthNew
x0 = xlocs[0]*factor
x1 = xlocs[1]*factor
width = box.width*factor
ax.set_position([x0,ylocs[0],x1-x0,ylocs[1]-ylocs[0]])

plt.draw()

L'ho trovato abbastanza utile e ha funzionato per me. Nota che se sei nel backend di wx (ad es. Usando windows), sostituisci mgr.window.wm_geometry ("% ix% i"% (winWidthNew, mgr.window.winfo_height ())) con mgr.window.SetClientSizeWH (winWidthNew , winHeightNew) o simili
Ezekiel Kruglick,

Se stai usando il backend Qt4Agg (che è predefinito sulla mia installazione Linux di matplotlib), sostituisci la linea mgr.window.wm_geometry(...)con mgr.window.setFixedWidth(winWidthNew).
Filip S.

E, come ho appena scoperto, se stai usando un backend che non mostra alcuna finestra, che è pensato per il salvataggio diretto in un file (come i backend SVG e AGG), salta del tutto il ridimensionamento della finestra. fig.set_size_inches(...)si occupa del ridimensionamento di cui hai bisogno.
Filip S.

3

Vale la pena aggiornare questa domanda, poiché le versioni più recenti di Matplotlib hanno reso molto più semplice posizionare la legenda fuori dalla trama. Ho prodotto questo esempio con la versione Matplotlib3.1.1 .

Gli utenti possono passare una 2 tupla di coordinate al locparametro per posizionare la legenda in qualsiasi punto del riquadro di delimitazione. L'unico gotcha è che devi correre plt.tight_layout()per ottenere matplotlib per ricalcolare le dimensioni della trama in modo che la legenda sia visibile:

import matplotlib.pyplot as plt

plt.plot([0, 1], [0, 1], label="Label 1")
plt.plot([0, 1], [0, 2], label='Label 2')

plt.legend(loc=(1.05, 0.5))
plt.tight_layout()

Questo porta al seguente diagramma:

trama con leggenda fuori

Riferimenti:


2

Puoi anche provare figlegend. È possibile creare una legenda indipendente da qualsiasi oggetto Axes. Tuttavia, potrebbe essere necessario creare alcuni percorsi "fittizi" per assicurarsi che la formattazione degli oggetti venga trasmessa correttamente.


1

Ecco un esempio dal tutorial matplotlib trovato qui . Questo è uno degli esempi più semplici ma ho aggiunto trasparenza alla legenda e aggiunto plt.show () in modo da poterlo incollare nella shell interattiva e ottenere un risultato:

import matplotlib.pyplot as plt
p1, = plt.plot([1, 2, 3])
p2, = plt.plot([3, 2, 1])
p3, = plt.plot([2, 3, 1])
plt.legend([p2, p1, p3], ["line 1", "line 2", "line 3"]).get_frame().set_alpha(0.5)
plt.show()

1

La soluzione che ha funzionato per me quando avevo un'enorme leggenda era quella di utilizzare un layout di immagine extra vuoto. Nel seguente esempio ho creato 4 righe e nella parte inferiore ho tracciato un'immagine con offset per la legenda (bbox_to_anchor) nella parte superiore che non viene tagliata.

f = plt.figure()
ax = f.add_subplot(414)
lgd = ax.legend(loc='upper left', bbox_to_anchor=(0, 4), mode="expand", borderaxespad=0.3)
ax.autoscale_view()
plt.savefig(fig_name, format='svg', dpi=1200, bbox_extra_artists=(lgd,), bbox_inches='tight')

1

Ecco un'altra soluzione, simile all'aggiunta bbox_extra_artistse bbox_inches, in cui non devi avere i tuoi artisti extra nell'ambito del tuosavefig chiamata. Ho pensato a questo perché ho generato la maggior parte della mia trama all'interno delle funzioni.

Invece di aggiungere tutte le tue aggiunte al rettangolo di selezione quando vuoi scriverlo, puoi aggiungerle in anticipo agli Figureartisti degli artisti. Utilizzando qualcosa di simile alla risposta di Franck Dernoncourt sopra :

import matplotlib.pyplot as plt

# data 
all_x = [10,20,30]
all_y = [[1,3], [1.5,2.9],[3,2]]

# plotting function
def gen_plot(x, y):
    fig = plt.figure(1)
    ax = fig.add_subplot(111)
    ax.plot(all_x, all_y)
    lgd = ax.legend( [ "Lag " + str(lag) for lag in all_x], loc="center right", bbox_to_anchor=(1.3, 0.5))
    fig.artists.append(lgd) # Here's the change
    ax.set_title("Title")
    ax.set_xlabel("x label")
    ax.set_ylabel("y label")
    return fig

# plotting
fig = gen_plot(all_x, all_y)

# No need for `bbox_extra_artists`
fig.savefig("image_output.png", dpi=300, format="png", bbox_inches="tight")

Ecco la trama generata.


-1

non so se hai già risolto il problema ... probabilmente sì, ma ... ho semplicemente usato la stringa "outside" per la posizione, come in matlab. Ho importato pylab da matplotlib. vedere il codice come segue:

from matplotlib as plt
from matplotlib.font_manager import FontProperties
...
...
t = A[:,0]
sensors = A[:,index_lst]

for i in range(sensors.shape[1]):
    plt.plot(t,sensors[:,i])

plt.xlabel('s')
plt.ylabel('°C')
lgd = plt.legend(b,loc='center left', bbox_to_anchor=(1, 0.5),fancybox = True, shadow = True)

Clicca per vedere la trama

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.