2015-05-23 16 views
12

Sto provando a utilizzare la parola chiave bbox_to_anchor() in un grafico matplotlib in Python.Legenda automatica Matlotlib all'esterno del grafico

Ecco una trama molto semplice che ho prodotto:

import matplotlib.pyplot as plt 
x = [1,2,3] 
plt.subplot(211) 
plt.plot(x, label="test1") 
plt.plot([3,2,1], label="test2") 
plt.legend(bbox_to_anchor=(0, -0.15, 1, 0), loc=2, ncol=2, mode="expand", borderaxespad=0) 
plt.show() 

Si basa sull'esempio qui: http://matplotlib.org/users/legend_guide.html#plotting-guide-legend

sto cercando di posizionare automaticamente la leggenda di fuori la trama usando bbox_to_anchor(). In questo esempio, bbox_to_anchor() ha 4 argomenti elencati.

In questo particolare esempio (sopra), la legenda viene posizionata sotto il grafico in modo che il numero -0,15 debba essere immesso manualmente ogni volta che viene modificato un grafico (dimensione carattere, titolo asse rimosso, ecc.). È possibile calcolare automaticamente questi 4 numeri per i seguenti scenari?:

  1. leggenda sotto trama
  2. leggenda sopra trama
  3. leggenda a destra della trama

In caso contrario, è possibile fare buoni congetture su questi numeri, in Python?

Inoltre, nel codice di esempio sopra ho impostato gli ultimi 2 numeri in bbox_to_anchor() su 1 e 0 poiché non capisco cosa siano o come funzionino. Che cosa significano gli ultimi 2 numeri in bbox_to_anchor()?

risposta

17

EDIT:

Mi consiglia di utilizzare la risposta da ImportanceOfBeingErnest: How to put the legend out of the plot

Questo è più facile da capire:

import matplotlib.pyplot as plt 
x = [1,2,3] 
plt.subplot(211) 
plt.plot(x, label="test1") 
plt.plot([3,2,1], label="test2") 
plt.legend(bbox_to_anchor=(0, 1), loc='upper left', ncol=1) 
plt.show() 

ora giocare con l'a coordinate (x, y). Per loc è possibile utilizzare:

valid locations are: 
right 
center left 
upper right 
lower right 
best 
center 
lower left 
center right 
upper left 
upper center 
lower center 
+1

Grazie. Le coordinate non dovrebbero essere impostate manualmente ogni volta? –

+0

Inoltre, le etichette dei dataseries sono molto lunghe per me. Questo sta causando loro di essere tagliati, nella leggenda. c'è un modo per evitarlo? –

+1

Se si imposta 'in alto a sinistra' e ad esempio (1,15) la legenda è esterna alla trama. Le leggende dovrebbero essere corte in ogni caso – Moritz

1

L'argomento di bbox_to_anchor è in Assi coordinate. matplotlib utilizza diversi sistemi di coordinate per facilitare il posizionamento degli oggetti sullo schermo. Quando si tratta di legende posizionamento, il critico sistemi per affrontare sono coordinate assi, coordina figura, e le coordinate di visualizzazione (in pixel) coordinata come illustrato di seguito:

matplotlib coordinate systems

Come precedentemente menzionato, bbox_to_anchor è in coordinate assi e non richiede tutti e 4 gli argomenti di tupla per un rettangolo. Puoi semplicemente dargli una tupla a due argomenti contenente (xpos, ypos) nelle coordinate degli assi. L'argomento loc in questo caso definirà il punto di ancoraggio per la legenda.Così al pin la legenda a destra esterna degli assi e allineato con il bordo superiore, si rilascia la seguente:

lgd = plt.legend(bbox_to_anchor=(1.01, 1), loc='upper left') 

Questo tuttavia non riposizionare gli assi rispetto alla figura e questo probabilmente posizionarla legenda fuori dalla tela di figura. Per riposizionare automaticamente la tela Figura per allinearla con gli assi e la legenda, ho utilizzato il seguente algoritmo.

primo coordinate, disegnare la legenda sulla tela di assegnare reale pixel:

plt.gcf().canvas.draw() 

indicare la trasformazione di passare da coordinate pixel alla Figura coordinate:

invFigure = plt.gcf().transFigure.inverted() 

Avanti, ottenere il legenda le estensioni in pixel e converti in coordinate di figura. Estrarre la misura più lontano nella direzione x quanto questa è la direzione tela è necessario adeguare:

lgd_pos = lgd.get_window_extent() 
lgd_coord = invFigure.transform(lgd_pos) 
lgd_xmax = lgd_coord[1, 0] 

fare lo stesso per gli assi:

ax_pos = plt.gca().get_window_extent() 
ax_coord = invFigure.transform(ax_pos) 
ax_xmax = ax_coord[1, 0] 

Infine, regolare la Figura tela utilizzando tight_layout per la proporzione degli assi che deve passare sopra per lasciare spazio per la legenda per adattarsi all'interno della tela:

shift = 1 - (lgd_xmax - ax_xmax) 
plt.gcf().tight_layout(rect=(0, 0, shift, 1)) 

nota che l'argomento rettangolo di tight_layout è in Figura coor dinates e definisce gli angoli in basso a sinistra e in alto a destra di un rettangolo contenente i limiti tight_layout degli Axes, che non include la legenda. Quindi una semplice chiamata tight_layout equivale all'impostazione dei limiti retti di (0, 0, 1, 1).

+0

questa è un'ottima risposta. Questo è l'unico che ho provato che funziona a livello di programmazione. Bel lavoro anche a spiegarlo; sarebbe bello avere una risposta più generale che potrebbe spostarsi in qualsiasi direzione se la legenda fosse posizionata sopra/sotto la figura, ad esempio. – shapiromatron