Jak wykluczyć legendę z fabuły

987

Mam serię 20 wykresów (nie podplotów), które należy wykonać w jednym rysunku. Chcę, żeby legenda była poza pudełkiem. Jednocześnie nie chcę zmieniać osi, ponieważ zmniejsza się rozmiar figury. Prosimy o pomoc w przypadku następujących pytań:

  1. Chcę zachować pole legendy poza obszarem fabuły. (Chcę, aby legenda była na zewnątrz po prawej stronie obszaru fabuły).
  2. Czy w każdym razie zmniejszam rozmiar czcionki tekstu w polu legendy, aby rozmiar pola legendy był niewielki.
pottigopi
źródło
14
W przypadku nowszych wersji matplotlib ta odpowiedź pokazuje, jak ustawić matplotlib, aby automatycznie określał, gdzie umieścić legendę bez ingerencji w wykresy .
dotancohen
2
Miałem to samo pytanie i znalazłem ten świetny przykład, który zadziałał dla mnie „po wyjęciu z pudełka”: matplotlib.org/1.3.1/users/legend_guide.html
robodasha
1
Ta odpowiedź ma większą głębię https://stackoverflow.com/a/43439132/52074. i robi to za pomocą dwóch linii kodu! pozytywna odpowiedź +1200 jest również dobra, ale uważam, że jest mniej ogólna.
Trevor Boyd Smith
2
@dotancohen „automatycznie określa, gdzie umieścić legendę bez ingerencji w fabuły”. W niektórych przypadkach, gdy fabuła ma wiele krzywych, jest to niestety niemożliwe. W takich przypadkach użytkownik może chcieć ręcznie umieścić legendę i rzeczywiście umieścić ją poza obszarem fabuły. Mam teraz trudności z taką fabułą.
Ali
btw, lista wyborów loc: najlepszy; Górny prawy; Górny lewy; lewy dolny; prawy dolny; dobrze; środkowy lewy; środkowa prawa; dolny środek; górny środek; Centrum;
Z-Y00,

Odpowiedzi:

57

Możesz zmniejszyć tekst legendy, tworząc właściwości czcionki:

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
źródło
50
co jest plot1w tej odpowiedzi?
Paul H
41
co jest legendw tej odpowiedzi?
Richard
28
Odpowiada to na drugą część pytania, ale nie na pierwotną (tę zatytułowaną).
Mateen Ulhaq,
8
Właściwy sposób to zrobićplt.legend(fontsize='small')
Mateen Ulhaq,
41
Ta odpowiedź jest okropna i zapewnia bardzo mały kontekst!
Tekill,
1794

Istnieje wiele sposobów robienia tego, co chcesz. Aby dodać do tego, co już powiedzieli @inalis i @Navi, możesz użyć bbox_to_anchorargumentu słowa kluczowego, aby umieścić legendę częściowo poza osiami i / lub zmniejszyć rozmiar czcionki.

Zanim zastanowisz się nad zmniejszeniem rozmiaru czcionki (co może uczynić rzeczy okropnie trudnymi do odczytania), spróbuj pobawić się legendą w różnych miejscach:

Zacznijmy od ogólnego przykładu:

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

alternatywny tekst

Jeśli zrobimy to samo, ale użyjemy bbox_to_anchorargumentu słowa kluczowego, możemy przesunąć legendę nieco poza granice osi:

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

alternatywny tekst

Podobnie możesz ustawić legendę bardziej poziomo i / lub umieścić ją na górze figury (włączam również zaokrąglone rogi i prosty cień):

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

alternatywny tekst

Alternatywnie możesz zmniejszyć szerokość bieżącego wykresu i umieścić legendę całkowicie poza osią figury (uwaga: jeśli używasz tight_layout () , to pomiń 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()

alternatywny tekst

W podobny sposób możesz zmniejszyć fabułę w pionie i umieścić na dole poziomą legendę:

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

alternatywny tekst

Spojrzeć w przewodniku matplotlib legendy . Możesz także rzucić okiem plt.figlegend().

Joe Kington
źródło
10
Jeśli ktoś ma z tym problemy, zwróć uwagę, że tight_layout () spowoduje problemy!
Matthew G.
4
świetna odpowiedź! poprawny link do dokumentu to matplotlib.org/users/legend_guide.html#legend-location
med
4
jako kompletność można powiedzieć, że ogólnie (podsumowane z dokumentu) „ bbox_to_anchorjest krotką 4 pływaków (x, y, szerokość, wysokość skrzynki) lub krotką 2 pływaków (x, y) w znormalizowanych osiach współrzędne. ”
meduz
5
Muszę przyznać, że jest to prawdopodobnie moja najczęściej odwiedzana odpowiedź SO. Po prostu nie mogę przestać do tego wracać, ponieważ rozsądny człowiek nie jest w stanie zapamiętać tej logiki bez szukania jej tutaj.
KT.
9
Zauważ, że jeśli chcesz zapisać figurę w pliku, prawdopodobnie powinieneś przechowywać zwrócony obiekt, tj. legend = ax.legend()I późniejfig.savefig(bbox_extra_artists=(legend,))
coldfix,
788

Umieszczanie legendy ( bbox_to_anchor)

Legenda jest umieszczana wewnątrz obwiedni osi za pomocą locargumentu do plt.legend.
Np. loc="upper right"Umieszcza legendę w prawym górnym rogu ramki ograniczającej, która domyślnie rozciąga się od (0,0)do (1,1)współrzędnych osi (lub w notacji ramki ograniczającej (x0,y0, width, height)=(0,0,1,1)).

Aby umieścić legendę poza obwiednią osi, można określić krotkę (x0,y0)współrzędnych osi lewego dolnego rogu legendy.

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

Jednak bardziej uniwersalnym podejściem byłoby ręczne określenie ramki granicznej, w której legenda powinna zostać umieszczona, za pomocą bbox_to_anchorargumentu. Można ograniczyć się do dostarczania tylko (x0,y0)części skrzynki. Tworzy to pole zerowego zakresu, z którego legenda będzie się rozwijać w kierunku podanym przez locargument. Na przykład

plt.legend (bbox_to_anchor = (1.04,1), loc = "lewy górny róg")

umieszcza legendę poza osiami, tak aby lewy górny róg legendy był ustawiony (1.04,1)we współrzędnych osi.

Dalsze przykłady podano poniżej, gdzie dodatkowo pokazano wzajemne oddziaływanie różnych argumentów, takich jak modei ncols.

wprowadź opis zdjęcia tutaj

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

Szczegółowe informacje na temat interpretacji argumentu 4-krotnego bbox_to_anchor, podobnie jak w l4, można znaleźć w tym pytaniu . mode="expand"Rozszerza legendę poziomo wewnątrz obwiedni określonej przez 4-krotnego. W przypadku legendy rozwiniętej pionowo zobacz to pytanie .

Czasami może być przydatne określenie ramki granicznej we współrzędnych figury zamiast we współrzędnych osi. Jest to pokazane w l5powyższym przykładzie , w którym bbox_transformargument jest używany do umieszczenia legendy w lewym dolnym rogu figury.

Przetwarzanie końcowe

Umieszczenie legendy poza osiami często prowadzi do niepożądanej sytuacji, że jest ona całkowicie lub częściowo poza płótnem postaci.

Rozwiązaniami tego problemu są:

  • Dostosuj parametry podplotu
    Można tak dostosować parametry podplotu, aby osie zajmowały mniej miejsca wewnątrz figury (a tym samym pozostawiły więcej miejsca legendzie) za pomocą plt.subplots_adjust. Na przykład

    plt.subplots_adjust(right=0.7)

    pozostawia 30% miejsca po prawej stronie figury, gdzie można umieścić legendę.

  • Ciasny układ
    Używanie plt.tight_layoutUmożliwia automatyczne dostosowanie parametrów wykresu podrzędnego, tak aby elementy na figurze ściśle przylegały do ​​krawędzi figury. Niestety, legenda nie jest brana pod uwagę w tym automatyzmie, ale możemy dostarczyć prostokątne pudełko, w które zmieści się cały obszar podplotów (w tym etykiety).

    plt.tight_layout(rect=[0,0,0.75,1])
  • Zapisywanie figury za pomocąbbox_inches = "tight"
    Argumentu, bbox_inches = "tight"za plt.savefigpomocą którego można zapisać figurę, tak aby wszyscy artyści na płótnie (w tym legenda) byli dopasowani do zapisanego obszaru. W razie potrzeby wielkość figury jest automatycznie dostosowywana.

    plt.savefig("output.png", bbox_inches="tight")
  • automatyczne dostosowywanie parametrów wykresu podrzędnego
    Sposób na automatyczne dopasowanie położenia wykresu podrzędnego tak, aby legenda mieściła się w obszarze roboczym bez zmiany rozmiaru figury, można znaleźć w tej odpowiedzi: Tworzenie figury z dokładnym rozmiarem i bez dopełnienia (i legenda poza osiami)

Porównanie przypadków omówionych powyżej:

wprowadź opis zdjęcia tutaj

Alternatywy

Postać legenda
One mogą wykorzystywać legendę do figury zamiast z osi matplotlib.figure.Figure.legend. Stało się to szczególnie przydatne w wersji matplotlib> = 2.1, gdzie nie są potrzebne żadne specjalne argumenty

fig.legend(loc=7) 

stworzyć legendę dla wszystkich artystów w różnych osiach figury. Legenda jest umieszczana za pomocą locargumentu, podobnie jak jest umieszczona w osiach, ale w odniesieniu do całej figury - stąd będzie nieco automatycznie poza osiami. Pozostaje tak wyregulować wykresy podrzędne, aby legenda i osie nie zachodziły na siebie. W tym przypadku pomocny będzie punkt „Dostosuj parametry podplotu” z góry. Przykład:

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

wprowadź opis zdjęcia tutaj

Legenda w dedykowanych osiach podplotu
Alternatywą dla użycia bbox_to_anchorbyłoby umieszczenie legendy w dedykowanych osiach podplotu ( lax). Ponieważ podplot legendy powinien być mniejszy niż wykres, możemy go wykorzystać gridspec_kw={"width_ratios":[4,1]}przy tworzeniu osi. Możemy ukryć osie lax.axis("off")ale nadal umieścić legendę w. Uchwyty legenda i etykiety muszą uzyskać od rzeczywistej działce pośrednictwem h,l = ax.get_legend_handles_labels(), a następnie może być dostarczony do legendy w laxpoletko, lax.legend(h,l). Pełny przykład znajduje się poniżej.

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

To tworzy wykres, który jest wizualnie bardzo podobny do wykresu z góry:

wprowadź opis zdjęcia tutaj

Możemy również użyć pierwszych osi do umieszczenia legendy, ale użyj bbox_transformosi legendy,

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

W tym podejściu nie musimy uzyskiwać uchwytów legendy zewnętrznie, ale musimy podać bbox_to_anchorargument.

Dalsza lektura i notatki:

  • Rozważ przewodnik po matplotlib z kilkoma przykładami innych rzeczy, które chcesz robić z legendami.
  • Przykładowy kod do umieszczania legend dla wykresów kołowych można znaleźć bezpośrednio w odpowiedzi na to pytanie: Python - Legenda pokrywa się z wykresem kołowym
  • locArgument może wziąć numery zamiast strun, które sprawiają, że rozmowy krótszy, jednak nie są one bardzo intuicyjnie odwzorowywane na siebie. Oto mapowanie w celach informacyjnych:

wprowadź opis zdjęcia tutaj

WażnośćOfBeingErnest
źródło
Umieszczenie legendy w dedykowanej synergii osi wątku bardzo ładnie fig.tight_layout. Jeśli używasz plt.subplotsdo tworzenia osi, po prostu daj mu coś w rodzaju gridspec_kw={'height_ratios': [100, 1]}(lub width_ratios), aby osie legendy były małe ... Następnie fig.tight_layout()rozszerzy ją, aby pasowała. Przynajmniej dla Matplotlib 3.0.3.
travc
161

Po prostu zadzwoń legend()po takim plot()połączeniu:

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

Wyniki wyglądałyby mniej więcej tak:

wprowadź opis zdjęcia tutaj

Shital Shah
źródło
4
Prace przy przejściu te same parametry, jak również do matplotlib.pyplot.legend
kidmose
8
Czy to odcina słowa z legendy dla kogokolwiek innego?
user1717828,
85

Aby umieścić legendę poza obszarem fabuły, użyj loci bbox_to_anchorsłów kluczowych legend(). Na przykład poniższy kod umieści legendę po prawej stronie obszaru wydruku:

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

Aby uzyskać więcej informacji, zobacz przewodnik legendy

Christian Alis
źródło
10
Okej - podoba mi się implementacja, ale kiedy idę zapisać postać (bez ręcznego zmieniania jej rozmiaru w oknie, czego nie chcę za każdym razem robić), legenda zostaje odcięta. Jakieś pomysły na to, jak to naprawić?
astromax
@astromax Nie jestem pewien, ale może spróbuj zadzwonić plt.tight_layout()?
Christian Alis,
81

Krótka odpowiedź: możesz użyć bbox_to_anchor+ bbox_extra_artists+ bbox_inches='tight'.


Dłuższa odpowiedź: można użyć bbox_to_anchordo ręcznego określenia położenia pola legendy, jak wskazały inne osoby w odpowiedziach.

Jednak zwykłym problemem jest przycięcie pola legendy, np .:

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

wprowadź opis zdjęcia tutaj

Aby zapobiec przycięciu pola legendy, po zapisaniu figury możesz użyć parametrów bbox_extra_artistsi bbox_inchespoprosić savefigo dołączenie przyciętych elementów do zapisanego obrazu:

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

Przykład (zmieniłem tylko ostatni wiersz, aby dodać 2 parametry 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')

wprowadź opis zdjęcia tutaj

Chciałbym, aby matplotlib natywnie umożliwiał zewnętrzną lokalizację skrzynki z legendami, ponieważ Matlab :

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

wprowadź opis zdjęcia tutaj

Franck Dernoncourt
źródło
6
Dziękuję bardzo! Parametry „bbox_to_anchor”, „bbox_extra_artist” i „” bbox_inches = „tight” były dokładnie tym, czego potrzebowałem, aby działało poprawnie. Niesamowite!
Demitrian
6
Dziękuję, ale tak naprawdę bbox_inches='tight'działa dla mnie idealnie, nawet bez bbox_extra_artist
avtomaton
1
@avtomaton Dzięki, dobrze wiedzieć, jakiej wersji matplotlib używasz?
Franck Dernoncourt
1
@FranckDernoncourt python3, matplotlib wersja 1.5.3
avtomaton
68

Oprócz wszystkich doskonałych odpowiedzi tutaj, nowsze wersje matplotlibi pylabmogą automatycznie określać, gdzie umieścić legendę bez ingerencji w fabuły , jeśli to możliwe.

pylab.legend(loc='best')

To automatycznie umieści legendę z dala od danych, jeśli to możliwe! Porównaj użycie loc = „best”

Jeśli jednak nie ma miejsca na umieszczenie legendy bez nakładania się danych, warto wypróbować jedną z pozostałych odpowiedzi; użycie loc="best"nigdy nie wystawi legendy poza fabułę.

dotancohen
źródło
2
Dziękujemy za zwrócenie na to uwagi! Szukałem tego kilka lat temu i nie znalazłem tego, a to naprawdę ułatwia moje życie.
Edgar H
4
ta opcja jest pomocna, ale nie odpowiada na pytanie, więc przegłosowałem. o ile wiem, najlepiej nigdy nie wystawia legendy poza fabułą
Tommy
3
@Tommy: W komentarzach OP (które wydają się już zniknąć) wyraźnie wyjaśniono, że OP chciał, aby legenda nie obejmowała danych wykresu, i pomyślał, że poza fabułą jest to jedyny sposób, aby to zrobić. Możesz to zobaczyć w odpowiedziach mefathy, Mateo Sancheza, Bastiaana i radtka. PO poprosił o X, ale chciał Y .
dotancohen
1
Właściwie to nie. W szczególności poprosił, aby legenda znalazła się poza fabułą. To w imię pytania;) „Jak wyrzucić legendę z fabuły”.
durbachit,
4
Nie gwarantuje to, że legenda nie zasłania danych. Po prostu zrób bardzo gęstą fabułę - nie ma miejsca na umieszczenie legendy. Na przykład spróbuj tego ... z numange import arange, sin, pi import matplotlib.pyplot jako plt t = arange (0,0, 100,0, 0,01) fig = plt.figure (1) ax1 = rys. 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 ( „Fala sinusoidalna lub dwie”) dla etykiety w ax1.get_xticklabels (): label.set_color ('r') plt.legend (loc = 'best') plt.show ()
adam.r
56

Krótka odpowiedź : przywołaj legendę do przeciągania i interaktywnie przenieś ją w dowolne miejsce:

ax.legend().draggable()

Długa odpowiedź : jeśli wolisz umieszczać legendę interaktywnie / ręcznie niż programowo, możesz przełączyć tryb przeciągania legendy, aby można było przeciągnąć ją w dowolne miejsce. Sprawdź poniższy przykład:

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()
mefatia
źródło
Nie jestem pewien, czy w pełni to rozumiem. Jak „przeciągnąć” legendę w dowolne miejsce dzięki temu? Używam Python 3.6 i Jupyter Notebook
sb2020
14

Nie do końca to, o co prosiłeś, ale znalazłem alternatywę dla tego samego problemu. Uczyń legendę półprzezroczystą, tak jak to: fabuła matplotlib z półprzezroczystą legendą i półprzezroczystym polem tekstowym

Zrób to z:

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
źródło
8

Jak już wspomniano, można również umieścić legendę na fabule lub nieco ją odsunąć do krawędzi. Oto przykład użycia interfejsu API programu Plotly Python , wykonanego za pomocą notatnika IPython . Jestem w zespole.

Na początek musisz zainstalować niezbędne pakiety:

import plotly
import math
import random
import numpy as np

Następnie zainstaluj 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)

Spowoduje to utworzenie wykresu i pozwoli zachować legendę w samym wykresie. Domyślną legendą, jeśli nie jest ustawiona, jest umieszczenie jej na wykresie, jak pokazano tutaj.

wprowadź opis zdjęcia tutaj

W celu alternatywnego umieszczenia możesz ściśle wyrównać krawędź wykresu i obramowanie legendy oraz usunąć linie obramowania w celu ściślejszego dopasowania.

wprowadź opis zdjęcia tutaj

Możesz przenieść i zmienić styl legendy i wykresu za pomocą kodu lub GUI. Aby przesunąć legendę, masz następujące opcje, aby umieścić legendę na wykresie, przypisując wartości xiy <= 1. Np .:

  • {"x" : 0,"y" : 0} -- Na dole po lewej
  • {"x" : 1, "y" : 0} -- Prawy dolny
  • {"x" : 1, "y" : 1} -- W prawym górnym rogu
  • {"x" : 0, "y" : 1} -- U góry z lewej
  • {"x" :.5, "y" : 0} - Dolny środek
  • {"x": .5, "y" : 1} - Top Center

W takim przypadku wybieramy prawy górny róg legendstyle = {"x" : 1, "y" : 1}, również opisany w dokumentacji :

wprowadź opis zdjęcia tutaj

Mateo Sanchez
źródło
3

Coś w tym stylu działało dla mnie. Począwszy od odrobiny kodu pobranego od Joe, ta metoda modyfikuje szerokość okna, aby automatycznie dopasować legendę po prawej stronie figury.

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()
Jaskółka oknówka
źródło
Uznałem to za bardzo przydatne i działało dla mnie. Zauważ, że jeśli korzystasz z backendu wx (np. Używasz systemu Windows), zamień mgr.window.wm_geometry („% ix% i”% (winWidthNew, mgr.window.winfo_height ())) na mgr.window.SetClientSizeWH (winWidthNew , winHeightNew) lub podobnym
Ezekiel Kruglick
Jeśli używasz backend Qt4Agg (który jest domyślnie w mojej instalacji Linuksa matplotlib), a następnie zamienić linię mgr.window.wm_geometry(...)z mgr.window.setFixedWidth(winWidthNew).
Filip S.
I, jak właśnie odkryłem, jeśli używasz backendu, który nie pokazuje żadnych okien, które są przeznaczone do zapisywania bezpośrednio do pliku (takiego jak backendy SVG i AGG), po prostu pomiń zmianę rozmiaru okna. fig.set_size_inches(...)dba o potrzebny rozmiar.
Filip S.
3

Warto odświeżyć to pytanie, ponieważ nowsze wersje Matplotlib znacznie ułatwiły umieszczenie legendy poza fabułą. Ten przykład stworzyłem w wersji Matplotlib 3.1.1.

Użytkownicy mogą przekazać 2-krotną współrzędną do locparametru, aby umieścić legendę w dowolnym miejscu w obwiedni. Jedyne, co musisz zrobić, to uruchomić program plt.tight_layout()Matplotlib, aby ponownie obliczyć wymiary działki, aby legenda była widoczna:

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

Prowadzi to do następującego wątku:

fabuła z legendą na zewnątrz

Bibliografia:

luc
źródło
2

Możesz także spróbować figlegend. Możliwe jest utworzenie legendy niezależnej od dowolnego obiektu Axes. Konieczne może być jednak utworzenie ścieżek „fikcyjnych”, aby upewnić się, że formatowanie obiektów zostanie poprawnie przekazane.

Uri Laserson
źródło
1

Oto przykład z samouczka matplotlib znalezionego tutaj . Jest to jeden z prostszych przykładów, ale dodałem przezroczystość do legendy i dodałem plt.show (), abyś mógł wkleić to do interaktywnej powłoki i uzyskać wynik:

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
źródło
1

Rozwiązaniem, które działało dla mnie, gdy miałem wielką legendę, było użycie dodatkowego pustego układu obrazu. W poniższym przykładzie wykonałem 4 rzędy, a na dole kreślę obraz z przesunięciem dla legendy (bbox_to_anchor) u góry, który nie jest wycinany.

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')
Kryształ
źródło
1

Oto inne rozwiązanie, podobne do dodawania bbox_extra_artistsi bbox_inches, w którym nie musisz mieć dodatkowych artystów w zasięgu savefigrozmowy. Wymyśliłem to, ponieważ generuję większość moich wykresów w funkcjach.

Zamiast dodawać wszystkie swoje dodatki do obwiedni, gdy chcesz je wypisać, możesz dodać je z wyprzedzeniem do Figureartystów. Używając czegoś podobnego do powyższej odpowiedzi Francka Dernoncourta :

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

Oto wygenerowany wykres.

ivirshup
źródło
-1

nie wiem, czy już rozwiązałeś problem ... prawdopodobnie tak, ale ... po prostu użyłem ciągu „na zewnątrz” dla lokalizacji, jak w Matlabie. Zaimportowałem pylab z Matplotlib. zobacz kod w następujący sposób:

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)

Kliknij, aby zobaczyć fabułę

Ziuccia
źródło