2015-05-23 16 views
12

Ich versuche, das Schlüsselwort bbox_to_anchor() in einem Matplotlib-Plot in Python zu verwenden.Matplotlib automatische Legende außerhalb Grundstück

Hier ist eine sehr einfache Handlung, die ich produziert habe:

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

Es basiert auf dem Beispiel basiert hier: http://matplotlib.org/users/legend_guide.html#plotting-guide-legend

ich automatisch versuche außerhalb des Diagramms die Legende zu platzieren bbox_to_anchor() verwenden. In diesem Beispiel sind in bbox_to_anchor() 4 Argumente aufgelistet.

In diesem speziellen Beispiel (oben) wird die Legende unter dem Diagramm platziert, so dass die Nummer -0,15 jedes Mal manuell eingegeben werden muss, wenn ein Diagramm geändert wird (Schriftgröße, Achsentitel entfernt usw.). Ist es möglich, diese 4 Zahlen automatisch für die folgenden Szenarien zu berechnen?:

  1. Legende unten Grundstück
  2. Legende oben Grundstück
  3. Legende nach rechts von Grundstück

Wenn nicht, ist es möglich, gute Vermutungen über diese Zahlen, in Python zu machen?

Auch im obigen Beispiel Code habe ich die letzten 2 Zahlen in bbox_to_anchor() auf 1 und 0 gesetzt, da ich nicht verstehe, was sie sind oder wie sie funktionieren. Was bedeuten die letzten 2 Nummern in bbox_to_anchor()?

Antwort

17

EDIT:

ich sehr die Antwort von ImportanceOfBeingErnest empfehlen: How to put the legend out of the plot

Dieser ist einfacher zu verstehen:

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

nun mit der an den Koordinaten (x spielen, y). Für loc können Sie:

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

Danke. Müssten die Koordinaten nicht jedes Mal manuell eingestellt werden? –

+0

Auch die Dataseries Etiketten sind sehr lang für mich. Dadurch werden sie in der Legende abgeschnitten. Gibt es eine Möglichkeit, dies zu vermeiden? –

+1

Wenn Sie "oben links" und z. B. (1,1,25) festlegen, befindet sich die Legende außerhalb des Diagramms. Legenden sollten sowieso kurz sein – Moritz

1

Das Argument bbox_to_anchor in Achsen Koordinaten ist. matplotlib verwendet verschiedene Koordinatensysteme, um die Platzierung von Objekten auf dem Bildschirm zu erleichtern. Wenn mit Positionierungs Legenden Umgang Koordinaten kritische Systeme zu behandeln sind Achsen-Koordinaten, Figur Koordinaten und Anzeigekoordinaten (in Pixeln), wie unten gezeigt:

matplotlib coordinate systems

Wie bereits erwähnt, bbox_to_anchor ist in den Achsen-Koordinaten und benötigt nicht alle 4 Tupelargumente für ein Rechteck. Sie können einfach ein Tupel mit zwei Argumenten geben, das (xpos, ypos) in Achsenkoordinaten enthält. Das Argument loc bestimmt in diesem Fall den Ankerpunkt für die Legende.So die Legende an Pin an der äußeren rechten Seite der Achsen und mit der oberen Kante ausgerichtet ist, würde erteilen Sie Folgendes:

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

Dies ist jedoch Neupositionierung nicht die Achsen in Bezug auf die Figur, und dies wird die wahrscheinliche Position Legende aus dem Zeichenbereich. Um den Zeichenbereich automatisch so anzupassen, dass er mit den Achsen und der Legende ausgerichtet ist, habe ich den folgenden Algorithmus verwendet.

Zuerst auf der Leinwand die Legende zieht es zuweisen reale Pixelkoordinaten:

plt.gcf().canvas.draw() 

dann die Transformation definieren von Pixel zu gehen Koordinaten Koordinaten Abbildung:

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

Als nächstes erhalten die Legendenausdehnung in Pixeln und Konvertieren in Bildkoordinaten. Ziehen Sie die weiteste Ausdehnung in x-Richtung aus, da dies die Leinwand Richtung, die wir brauchen, ist anzupassen:

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

Machen Sie dasselbe für die Achsen:

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

Schließlich stellen Sie die Abbildung Leinwand mit tight_layout für

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

Beachten Sie, dass das rect Argument tight_layout ist in Abbildung koor: der Anteil der Achsen, den Raum bewegt über muss für die Legende zu ermöglichen, innerhalb der Leinwand zu passen Definiert und definiert die unteren linken und oberen rechten Ecken eines Rechtecks, das die Tight_layout-Grenzen der Achsen enthält, die die Legende nicht enthalten. Ein einfacher Tight_layout-Aufruf ist also äquivalent zum Festlegen der richtigen Grenzen von (0, 0, 1, 1).

+0

das ist eine großartige Antwort. Dies ist der einzige, den ich ausprobiert habe, der programmatisch funktioniert. Netter Job, der es auch erklärt; Es wäre schön, eine allgemeinere Antwort zu haben, die sich in jede Richtung verschieben könnte, wenn die Legende zum Beispiel über/unter der Zahl platziert würde. – shapiromatron