Wie man die Legende aus der Handlung entfernt

987

Ich habe eine Reihe von 20 Plots (keine Unterplots), die in einer einzigen Figur erstellt werden sollen. Ich möchte, dass die Legende außerhalb des Rahmens liegt. Gleichzeitig möchte ich die Achsen nicht ändern, da die Größe der Figur reduziert wird. Bitte helfen Sie mir bei folgenden Fragen:

  1. Ich möchte das Legendenfeld außerhalb des Handlungsbereichs halten. (Ich möchte, dass sich die Legende draußen auf der rechten Seite des Handlungsbereichs befindet.)
  2. Gibt es sowieso, dass ich die Schriftgröße des Textes innerhalb des Legendenfeldes reduziere, so dass die Größe des Legendenfeldes klein wird.
pottigopi
quelle
14
Bei neueren matplotlib-Versionen zeigt diese Antwort , wie matplotlib so eingestellt wird, dass automatisch bestimmt wird, wo die Legende abgelegt werden soll, ohne die Diagramme zu beeinträchtigen .
Dotancohen
2
Hatte die gleiche Frage und fand dieses großartige Beispiel, das für mich "out of the box" funktionierte
robodasha
1
Diese Antwort hat mehr Tiefe https://stackoverflow.com/a/43439132/52074. und das mit zwei Codezeilen! Die +1200 upvoted Antwort ist auch gut, aber ich fand es weniger generisch.
Trevor Boyd Smith
2
@dotancohen "bestimmt automatisch, wo die Legende abgelegt werden soll, ohne die Diagramme zu beeinträchtigen" In bestimmten Fällen, in denen das Diagramm viele Kurven aufweist, ist dies leider nicht möglich. In diesen Fällen möchte der Benutzer die Legende möglicherweise manuell platzieren und tatsächlich außerhalb des Plotbereichs platzieren. Ich habe gerade Schwierigkeiten mit einer solchen Verschwörung.
Ali
Übrigens, die Liste der Auswahlmöglichkeiten von loc: best; oben rechts; Oben links; Unten links; rechts unten; Recht; Mitte links; Mitte rechts; untere Mitte; obere Mitte; Center;
Z-Y00

Antworten:

57

Sie können den Legendentext verkleinern, indem Sie Schrifteigenschaften erstellen:

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
Navi
quelle
50
Was ist plot1in dieser Antwort?
Paul H
41
Was ist legendin dieser Antwort?
Richard
28
Dies beantwortet den sekundären Teil der Frage, aber nicht den primären (den Titel).
Mateen Ulhaq
8
Auch der richtige Weg, dies zu tun, istplt.legend(fontsize='small')
Mateen Ulhaq
41
Diese Antwort ist schrecklich und bietet sehr wenig Kontext!
Tekill
1795

Es gibt verschiedene Möglichkeiten, das zu tun, was Sie wollen. Um das zu ergänzen, was @inalis und @Navi bereits gesagt haben, können Sie das bbox_to_anchorSchlüsselwortargument verwenden, um die Legende teilweise außerhalb der Achsen zu platzieren und / oder die Schriftgröße zu verringern.

Versuchen Sie, die Legende an verschiedenen Stellen zu platzieren, bevor Sie die Schriftgröße verringern (was das Lesen erheblich erschwert).

Beginnen wir also mit einem allgemeinen Beispiel:

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

Alt-Text

Wenn wir dasselbe tun, aber das bbox_to_anchorSchlüsselwortargument verwenden, können wir die Legende leicht außerhalb der Achsengrenzen verschieben:

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

Alt-Text

Ebenso können Sie die Legende horizontaler gestalten und / oder oben in die Figur einfügen (ich drehe auch abgerundete Ecken und einen einfachen Schlagschatten an):

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

Alt-Text

Alternativ können Sie die Breite des aktuellen Diagramms verkleinern und die Legende vollständig außerhalb der Achse der Figur platzieren (Hinweis: Wenn Sie tight_layout () verwenden , lassen Sie ax.set_position () weg:

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

Alt-Text

Auf ähnliche Weise können Sie das Diagramm vertikal verkleinern und die horizontale Legende unten einfügen:

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

Alt-Text

Schauen Sie sich den Matplotlib-Legendenführer an . Sie könnten auch einen Blick darauf werfen plt.figlegend().

Joe Kington
quelle
10
Wenn jemand Probleme damit hat, beachten Sie, dass tight_layout () Probleme verursachen wird!
Matthew G.
4
gute Antwort! Der richtige Link zum Dokument ist matplotlib.org/users/legend_guide.html#legend-location
meduz
4
Der Vollständigkeit halber könnte man sagen, dass im Allgemeinen (zusammengefasst aus dem Dokument) " bbox_to_anchorein Tupel von 4 Gleitkommazahlen (x, y, Breite, Höhe der bbox) oder ein Tupel von 2 Gleitkommazahlen (x, y) in normalisierten Achsen ist Koordinaten. "
Meduz
5
Ich muss zugeben, dass dies wahrscheinlich meine meistbesuchte SO-Antwort ist. Ich kann einfach nicht anders, als immer wieder darauf zurückzukommen, denn eine vernünftige Person kann sich auf keinen Fall an diese Logik erinnern, ohne sie hier nachzuschlagen.
KT.
9
Beachten Sie, dass Sie, wenn Sie die Figur in einer Datei speichern möchten, wahrscheinlich das zurückgegebene Objekt speichern sollten, dh legend = ax.legend()und späterfig.savefig(bbox_extra_artists=(legend,))
Coldfix
791

Legende platzieren ( bbox_to_anchor)

Eine Legende wird innerhalb des Begrenzungsrahmens der Achsen mit dem locArgument to positioniert plt.legend.
Beispiel loc="upper right"stellt die Legende in der oberen rechten Ecke des Begrenzungsrahmens, der standardmäßig Ausdehnungen von (0,0)bis (1,1)in Achsen - Koordinaten (oder Box - Notation in Bounding (x0,y0, width, height)=(0,0,1,1)).

Um die Legende außerhalb des Achsenbegrenzungsrahmens zu platzieren, kann ein Tupel (x0,y0)von Achsenkoordinaten in der unteren linken Ecke der Legende angegeben werden.

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

Ein vielseitigerer Ansatz wäre jedoch, den Begrenzungsrahmen, in den die Legende eingefügt werden soll, mithilfe des bbox_to_anchorArguments manuell anzugeben . Man kann sich darauf beschränken, nur den (x0,y0)Teil der bbox zu liefern. Dadurch wird ein Feld mit einer Spannweite von Null erstellt, aus dem die Legende in die durch das locArgument angegebene Richtung erweitert wird . Z.B

plt.legend (bbox_to_anchor = (1.04,1), loc = "oben links")

Platziert die Legende außerhalb der Achsen, sodass sich die obere linke Ecke der Legende (1.04,1)in Achsenkoordinaten befindet.

Weitere Beispiele sind unten angegeben, wo zusätzlich das Zusammenspiel zwischen verschiedenen Argumenten wie modeund ncolsgezeigt wird.

Geben Sie hier die Bildbeschreibung ein

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

Details zur Interpretation des 4-Tupel-Arguments bbox_to_anchorwie in l4finden Sie in dieser Frage . Das mode="expand"erweitert die Legende horizontal innerhalb des Begrenzungsrahmens des 4-Tupels. Eine vertikal erweiterte Legende finden Sie in dieser Frage .

Manchmal kann es nützlich sein, den Begrenzungsrahmen in Zahlenkoordinaten anstelle von Achsenkoordinaten anzugeben. Dies wird im l5obigen Beispiel gezeigt, in dem das bbox_transformArgument verwendet wird, um die Legende in der unteren linken Ecke der Abbildung zu platzieren.

Nachbearbeitung

Wenn die Legende außerhalb der Achsen platziert wird, führt dies häufig zu der unerwünschten Situation, dass sie sich ganz oder teilweise außerhalb der Leinwand befindet.

Lösungen für dieses Problem sind:

  • Anpassen der Subplot-Parameter Mit
    können Sie die Subplot-Parameter so einstellen, dass die Achsen weniger Platz in der Figur beanspruchen (und dadurch mehr Platz für die Legende lassen) plt.subplots_adjust. Z.B

    plt.subplots_adjust(right=0.7)

    Lässt 30% Platz auf der rechten Seite der Figur, wo man die Legende platzieren könnte.

  • Enges Layout
    Verwenden von plt.tight_layoutErmöglicht das automatische Anpassen der Unterzeichnungsparameter, sodass die Elemente in der Figur eng an den Kanten der Figur anliegen. Leider wird die Legende in diesem Automatismus nicht berücksichtigt, aber wir können ein Rechteckfeld bereitstellen, in das der gesamte Teilplotbereich (einschließlich Beschriftungen) passt.

    plt.tight_layout(rect=[0,0,0.75,1])
  • Speichern der Figur mitbbox_inches = "tight"
    Das Argument bbox_inches = "tight"to plt.savefigkann verwendet werden, um die Figur so zu speichern, dass alle Künstler auf der Leinwand (einschließlich der Legende) in den gespeicherten Bereich passen. Bei Bedarf wird die Figurengröße automatisch angepasst.

    plt.savefig("output.png", bbox_inches="tight")
  • Automatisches Anpassen der Subplot-Parameter
    Eine Möglichkeit, die Subplot-Position automatisch so anzupassen, dass die Legende in die Leinwand passt, ohne die Figurengröße zu ändern , finden Sie in dieser Antwort: Erstellen einer Figur mit exakter Größe und ohne Polsterung (und Legende außerhalb der Achsen)

Vergleich zwischen den oben diskutierten Fällen:

Geben Sie hier die Bildbeschreibung ein

Alternativen

Eine Figurenlegende
Man kann anstelle der Achsen eine Legende für die Figur verwenden matplotlib.figure.Figure.legend. Dies ist besonders nützlich für die matplotlib-Version> = 2.1, bei der keine speziellen Argumente erforderlich sind

fig.legend(loc=7) 

eine Legende für alle Künstler in den verschiedenen Achsen der Figur zu erstellen. Die Legende wird mit dem locArgument platziert, ähnlich wie sie innerhalb einer Achse platziert wird, jedoch in Bezug auf die gesamte Figur - daher befindet sie sich etwas automatisch außerhalb der Achsen. Was bleibt, ist, die Unterzeichnungen so anzupassen, dass es keine Überlappung zwischen der Legende und den Achsen gibt. Hier ist der Punkt "Anpassen der Subplot-Parameter" von oben hilfreich. Ein Beispiel:

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

Geben Sie hier die Bildbeschreibung ein

Legende in dedizierten Nebenplotachsen
Eine Alternative zur Verwendung besteht bbox_to_anchordarin, die Legende in ihren dedizierten Unterplotachsen zu platzieren ( lax). Da das Legendenunterdiagramm kleiner als das Diagramm sein sollte, können wir es gridspec_kw={"width_ratios":[4,1]}bei der Achsenerstellung verwenden. Wir können die Achsen ausblenden, lax.axis("off")aber dennoch eine Legende einfügen. Die Legendengriffe und Beschriftungen müssen aus dem realen Plot über abgerufen werden h,l = ax.get_legend_handles_labels()und können dann der Legende im laxUnterplot übergeben werden lax.legend(h,l). Ein vollständiges Beispiel finden Sie unten.

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

Dies erzeugt eine Handlung, die der Handlung von oben optisch ziemlich ähnlich ist:

Geben Sie hier die Bildbeschreibung ein

Wir könnten auch die ersten Achsen verwenden, um die Legende zu platzieren, aber die bbox_transformder Legendenachsen verwenden,

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

Bei diesem Ansatz müssen wir die Legendenhandles nicht extern abrufen, sondern das bbox_to_anchorArgument angeben .

Weiterführende Literatur und Hinweise:

  • Betrachten Sie den Matplotlib- Legendenführer mit einigen Beispielen für andere Dinge , die Sie mit Legenden tun möchten.
  • Ein Beispielcode zum Platzieren von Legenden für Kreisdiagramme kann direkt als Antwort auf diese Frage gefunden werden: Python - Legende überschneidet sich mit dem Kreisdiagramm
  • Das locArgument kann Zahlen anstelle von Zeichenfolgen annehmen, wodurch Aufrufe kürzer werden. Sie sind jedoch nicht sehr intuitiv aufeinander abgestimmt. Hier ist das Mapping als Referenz:

Geben Sie hier die Bildbeschreibung ein

Bedeutung von BeErnest
quelle
Das Einfügen der Legende in eine dedizierte Nebenplotachse bietet sehr gute Synergien fig.tight_layout. Wenn Sie plt.subplotszum Erstellen der Achsen verwenden, geben Sie einfach so etwas wie gridspec_kw={'height_ratios': [100, 1]}(oder width_ratios) ein, damit die Achsen der Legende winzig sind ... Dann fig.tight_layout()wird es entsprechend erweitert. Zumindest für matplotlib 3.0.3.
Travc
161

Rufen Sie einfach legend()nach dem plot()Anruf wie folgt an:

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

Die Ergebnisse würden ungefähr so ​​aussehen:

Geben Sie hier die Bildbeschreibung ein

Shital Shah
quelle
4
funktioniert, wenn die gleichen Parameter auch an matplotlib.pyplot.legend übergeben werden
kidmose
8
Schneidet dies die Wörter in der Legende für andere ab?
user1717828
85

Verwenden Sie locund bbox_to_anchorSchlüsselwörter von , um die Legende außerhalb des Plotbereichs zu platzieren legend(). Mit dem folgenden Code wird die Legende beispielsweise rechts vom Plotbereich platziert:

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

Weitere Informationen finden Sie im Legendenhandbuch

Christian Alis
quelle
10
Okay - ich mag die Implementierung, aber wenn ich die Figur speichere (ohne die Größe im Fenster manuell zu ändern, was ich nicht jedes Mal tun möchte), wird die Legende abgeschnitten. Irgendwelche Ideen, wie ich das beheben könnte?
Astromax
@astromax Ich bin mir nicht sicher, aber vielleicht versuchen Sie anzurufen plt.tight_layout()?
Christian Alis
81

Kurze Antwort: Sie können bbox_to_anchor+ bbox_extra_artists+ verwenden bbox_inches='tight'.


Längere Antwort: Sie können bbox_to_anchordie Position des Legendenfelds manuell angeben, wie einige andere Personen in den Antworten ausgeführt haben.

Das übliche Problem ist jedoch, dass das Legendenfeld beschnitten ist, z.

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

Geben Sie hier die Bildbeschreibung ein

Um zu verhindern, dass das Legendenfeld beschnitten wird, können Sie beim Speichern der Figur die Parameter verwenden bbox_extra_artistsund bbox_inchesfragen savefig, ob beschnittene Elemente in das gespeicherte Bild aufgenommen werden sollen:

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

Beispiel (Ich habe nur die letzte Zeile geändert, um 2 Parameter hinzuzufügen 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')

Geben Sie hier die Bildbeschreibung ein

Ich wünschte, Matplotlib würde nativ einen externen Standort für die Legendenbox zulassen, wie es Matlab tut :

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

Geben Sie hier die Bildbeschreibung ein

Franck Dernoncourt
quelle
6
Ich danke dir sehr! Die Parameter "bbox_to_anchor", "bbox_extra_artist" und "" bbox_inches = 'tight "waren genau das, was ich brauchte, damit es richtig funktioniert.
Super
6
Danke, bbox_inches='tight'funktioniert aber auch ohne bbox_extra_artist
avtomaton
1
@avtomaton Danke, gut zu wissen, welche Version von matplotlib verwenden Sie?
Franck Dernoncourt
1
@FranckDernoncourt python3, matplotlib Version 1.5.3
avtomaton
68

Zusätzlich zu all den hervorragenden Antworten hier, neuere Versionen matplotlibund pylabkann automatisch bestimmen , wo die Legende zu setzen , ohne mit den Stellplätzen zu stören , wenn möglich.

pylab.legend(loc='best')

Dadurch wird die Legende nach Möglichkeit automatisch von den Daten entfernt! Vergleichen Sie die Verwendung von loc = 'best'

Wenn es jedoch keinen Platz gibt, an dem die Legende platziert werden kann, ohne die Daten zu überlappen, sollten Sie eine der anderen Antworten ausprobieren. Mit using loc="best"wird die Legende niemals außerhalb der Handlung platziert.

dotancohen
quelle
2
Vielen Dank für den Hinweis! Ich habe vor ein paar Jahren danach gesucht und es nicht gefunden, und es ist etwas, das mir das Leben wirklich erleichtert.
Edgar H
4
Diese Option ist hilfreich, beantwortet aber die Frage nicht und ich habe sie abgelehnt. Soweit ich das beurteilen kann, wird die Legende am besten nie außerhalb der Handlung platziert
Tommy
3
@Tommy: In den Kommentaren des OP (die jetzt weg zu sein scheinen) wurde ausdrücklich klargestellt, dass das OP wollte, dass die Legende die Diagrammdaten nicht abdeckt, und er dachte, dass dies außerhalb des Plots der einzige Weg sei. Sie können dies in den Antworten von Mefathy, Mateo Sanchez, Bastiaan und Radtek sehen. Die OP fragte nach X, aber er wollte Y .
Dotancohen
1
Eigentlich nicht. Er / sie bat ausdrücklich darum, dass sich die Legende außerhalb der Handlung befindet. Es ist im Namen der Frage;) "Wie man die Legende aus der Handlung entfernt".
Durbachit
4
Dies garantiert nicht, dass die Legende die Daten nicht verdeckt. Machen Sie einfach eine sehr dichte Handlung - es gibt keinen Platz, um die Legende zu setzen. Versuchen Sie dies beispielsweise ... aus numpy import arange, sin, pi import matplotlib.pyplot als plt t = arange (0.0, 100.0, 0.01) fig = plt.figure (1) ax1 = fig.add_subplot (211) ax1. Streuung (t, sin (2 * pi * t), label = 'test') ax1.grid (True) # ax1.set_ylim ((- 2, 2)) ax1.set_ylabel ('1 Hz') ax1.set_title ( 'Ein oder zwei Sinuswellen') für label in ax1.get_xticklabels (): label.set_color ('r') plt.legend (loc = 'best') plt.show ()
adam.r
56

Kurze Antwort : Rufen Sie Draggable für die Legende auf und verschieben Sie sie interaktiv, wo immer Sie möchten:

ax.legend().draggable()

Lange Antwort : Wenn Sie die Legende lieber interaktiv / manuell als programmgesteuert platzieren möchten, können Sie den ziehbaren Modus der Legende so umschalten, dass Sie sie an eine beliebige Stelle ziehen können. Überprüfen Sie das folgende Beispiel:

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()
Mefathy
quelle
Ich bin mir nicht sicher, ob ich das vollständig verstehe. Wie "ziehe" ich die Legende damit, wohin ich will? Ich benutze Python 3.6 und Jupyter Notebook
sb2020
14

Nicht genau das, wonach Sie gefragt haben, aber ich fand, dass es eine Alternative für das gleiche Problem ist. Machen Sie die Legende halbtransparent wie folgt: matplotlib-Plot mit halbtransparenter Legende und halbtransparentem Textfeld

Tun Sie dies mit:

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)
Bastiaan
quelle
8

Wie bereits erwähnt, können Sie die Legende auch im Plot oder leicht vom Rand entfernt platzieren. Hier ist ein Beispiel für die Verwendung der Plotly Python-API , die mit einem IPython-Notizbuch erstellt wurde . Ich bin im Team.

Zunächst möchten Sie die erforderlichen Pakete installieren:

import plotly
import math
import random
import numpy as np

Installieren Sie dann 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)

Dadurch wird Ihr Diagramm erstellt und Sie können die Legende im Diagramm selbst behalten. Wenn die Legende nicht festgelegt ist, wird sie standardmäßig im Diagramm platziert, wie hier gezeigt.

Geben Sie hier die Bildbeschreibung ein

Für eine alternative Platzierung können Sie den Rand des Diagramms und den Rand der Legende eng ausrichten und Randlinien für eine engere Anpassung entfernen.

Geben Sie hier die Bildbeschreibung ein

Sie können die Legende und das Diagramm mit Code oder über die GUI verschieben und neu formatieren. Um die Legende zu verschieben, haben Sie die folgenden Optionen, um die Legende innerhalb des Diagramms zu positionieren, indem Sie x- und y-Werte von <= 1 zuweisen. Beispiel:

  • {"x" : 0,"y" : 0} -- Unten links
  • {"x" : 1, "y" : 0} -- Unten rechts
  • {"x" : 1, "y" : 1} -- Oben rechts
  • {"x" : 0, "y" : 1} -- Oben links
  • {"x" :.5, "y" : 0} -- Unten in der Mitte
  • {"x": .5, "y" : 1} -- Oben in der Mitte

In diesem Fall wählen wir oben rechts legendstyle = {"x" : 1, "y" : 1}, ebenfalls in der Dokumentation beschrieben :

Geben Sie hier die Bildbeschreibung ein

Mateo Sanchez
quelle
3

Etwas in dieser Richtung hat bei mir funktioniert. Ausgehend von einem Code von Joe ändert diese Methode die Fensterbreite, um automatisch eine Legende rechts von der Abbildung anzupassen.

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()
Martin
quelle
Ich fand das sehr nützlich und es hat bei mir funktioniert. Beachten Sie, dass Sie im wx-Backend (z. B. unter Windows) mgr.window.wm_geometry ("% ix% i"% (winWidthNew, mgr.window.winfo_height ())) durch mgr.window.SetClientSizeWH (winWidthNew) ersetzen , winHeightNew) oder dergleichen
Ezekiel Kruglick
Wenn Sie das Qt4Agg-Backend verwenden (das bei meiner Linux-Installation von matplotlib standardmäßig verwendet wird), ersetzen Sie die Zeile mgr.window.wm_geometry(...)durch mgr.window.setFixedWidth(winWidthNew).
Filip S.
Und, wie ich gerade herausgefunden habe, überspringen Sie einfach die Fenstergröße, wenn Sie ein Backend verwenden, das keine Fenster anzeigt, die zum direkten Speichern in einer Datei gedacht sind (wie das SVG- und das AGG-Backend). fig.set_size_inches(...)kümmert sich um die Größenänderung, die Sie benötigen.
Filip S.
3

Es lohnt sich, diese Frage zu aktualisieren, da neuere Versionen von Matplotlib es viel einfacher gemacht haben, die Legende außerhalb der Handlung zu positionieren. Ich habe dieses Beispiel mit der Matplotlib-Version erstellt 3.1.1.

Benutzer können dem locParameter ein 2-Tupel von Koordinaten übergeben, um die Legende an einer beliebigen Stelle im Begrenzungsrahmen zu positionieren. Das einzige Problem ist, dass Sie ausführen müssen plt.tight_layout(), damit matplotlib die Plotdimensionen neu berechnet, sodass die Legende sichtbar ist:

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

Dies führt zu folgendem Plot:

Handlung mit Legende draußen

Verweise:

luc
quelle
2

Sie können es auch versuchen figlegend. Es ist möglich, eine Legende unabhängig von einem beliebigen Axes-Objekt zu erstellen. Möglicherweise müssen Sie jedoch einige "Dummy" -Pfade erstellen, um sicherzustellen, dass die Formatierung für die Objekte korrekt weitergegeben wird.

Uri Laserson
quelle
1

Hier ist ein Beispiel aus dem matplotlib tutorial hier . Dies ist eines der einfacheren Beispiele, aber ich habe der Legende Transparenz hinzugefügt und plt.show () hinzugefügt, damit Sie dies in die interaktive Shell einfügen und ein Ergebnis erhalten können:

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()
radtek
quelle
1

Die Lösung, die für mich funktionierte, als ich eine große Legende hatte, bestand darin, ein extra leeres Bildlayout zu verwenden. Im folgenden Beispiel habe ich 4 Zeilen erstellt und unten zeichne ich ein Bild mit einem Versatz für die Legende (bbox_to_anchor) oben, es wird nicht geschnitten.

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')
Kristall
quelle
1

Hier ist eine andere Lösung, ähnlich wie beim Hinzufügen von bbox_extra_artistsund bbox_inches, bei der Sie keine zusätzlichen Künstler im Rahmen Ihrer haben müssensavefig Anrufs haben müssen. Ich habe mir das ausgedacht, da ich den größten Teil meiner Handlung innerhalb von Funktionen generiere.

Anstatt alle Ihre Ergänzungen zum Begrenzungsrahmen hinzuzufügen, wenn Sie sie ausschreiben möchten, können Sie sie den FigureKünstlern des Künstlers vorab hinzufügen . Verwenden Sie etwas Ähnliches wie die Antwort von Franck Dernoncourt oben :

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

Hier ist das generierte Diagramm.

ivirshup
quelle
-1

Ich weiß nicht, ob Sie Ihr Problem bereits gelöst haben ... wahrscheinlich ja, aber ... Ich habe einfach die Zeichenfolge 'außerhalb' für den Speicherort verwendet, wie in matlab. Ich habe Pylab aus Matplotlib importiert. Sehen Sie den Code wie folgt:

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)

Klicken Sie hier, um das Diagramm anzuzeigen

Ziuccia
quelle