Cara mengeluarkan legenda dari plot

988

Saya memiliki serangkaian 20 plot (bukan subplot) untuk dibuat dalam satu gambar. Saya ingin legenda berada di luar kotak. Pada saat yang sama, saya tidak ingin mengganti sumbu, karena ukuran gambar menjadi berkurang. Mohon bantu saya untuk pertanyaan berikut:

  1. Saya ingin menyimpan kotak legenda di luar area plot. (Saya ingin legenda berada di luar di sisi kanan area plot).
  2. Apakah ada yang mengurangi ukuran font teks di dalam kotak legenda, sehingga ukuran kotak legenda akan kecil.
pottigopi
sumber
14
Untuk versi matplotlib yang lebih baru, jawaban ini menunjukkan cara mengatur matplotlib untuk secara otomatis menentukan di mana menempatkan legenda tanpa mengganggu plot .
dotancohen
2
Punya pertanyaan yang sama dan menemukan contoh hebat ini yang bekerja untuk saya "out of the box": matplotlib.org/1.3.1/users/legend_guide.html
robodasha
1
Jawaban ini lebih dalam https://stackoverflow.com/a/43439132/52074. dan melakukannya dengan dua baris kode! jawaban tervotifikasi +1200 juga bagus tetapi saya merasa kurang generik.
Trevor Boyd Smith
2
@dotancohen "secara otomatis menentukan di mana menempatkan legenda tanpa mengganggu plot" Dalam kasus tertentu, ketika plot memiliki banyak kurva, sayangnya tidak mungkin. Dalam kasus tersebut, pengguna mungkin ingin menempatkan legenda secara manual, dan memang meletakkannya di luar area plot. Saya mengalami kesulitan dengan plot seperti itu sekarang.
Ali
btw, daftar pilihan loc: best; pojok kanan atas; kiri atas; kiri bawah; kanan bawah; Baik; kiri tengah; kanan tengah; pusat bawah; pusat atas; pusat;
Z-Y00

Jawaban:

57

Anda dapat membuat teks legenda lebih kecil dengan membuat properti font:

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
sumber
50
apa yang ada plot1di jawaban ini?
Paul H
41
apa yang ada legenddi jawaban ini?
Richard
28
Ini menjawab bagian kedua dari pertanyaan, tetapi bukan yang utama (yang berjudul).
Mateen Ulhaq
8
Juga, cara yang tepat untuk melakukan ini adalahplt.legend(fontsize='small')
Mateen Ulhaq
41
Jawaban ini mengerikan dan memberikan konteks yang sangat sedikit!
Tekill
1797

Ada sejumlah cara untuk melakukan apa yang Anda inginkan. Untuk menambah apa yang sudah dikatakan @inalis dan @Navi, Anda bisa menggunakan bbox_to_anchorargumen kata kunci untuk menempatkan legenda sebagian di luar sumbu dan / atau mengurangi ukuran font.

Sebelum Anda mempertimbangkan untuk mengurangi ukuran font (yang dapat membuat hal-hal sangat sulit dibaca), cobalah bermain-main dengan menempatkan legenda di tempat yang berbeda:

Jadi, mari kita mulai dengan contoh umum:

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

teks alternatif

Jika kami melakukan hal yang sama, tetapi menggunakan bbox_to_anchorargumen kata kunci, kami dapat menggeser legenda sedikit di luar batas sumbu:

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

teks alternatif

Demikian pula, Anda dapat membuat legenda lebih horizontal dan / atau meletakkannya di bagian atas gambar (saya juga menyalakan sudut bulat dan drop shadow sederhana):

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

teks alternatif

Sebagai alternatif, Anda dapat mengecilkan lebar plot saat ini, dan meletakkan legenda sepenuhnya di luar sumbu gambar (catatan: jika Anda menggunakan tight_layout () , lalu tinggalkan 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()

teks alternatif

Dan dengan cara yang sama, Anda dapat mengecilkan plot secara vertikal, dan meletakkan legenda horizontal di bagian bawah:

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

teks alternatif

Lihatlah panduan legenda matplotlib . Anda mungkin juga melihatnya plt.figlegend().

Joe Kington
sumber
10
Jika ada yang mengalami masalah dengan ini, perhatikan bahwa tight_layout () akan menyebabkan masalah!
Matius G.
4
jawaban bagus! tautan yang benar ke dokumen ini adalah matplotlib.org/users/legend_guide.html#legend-location
meduz
4
sebagai kelengkapan, Anda dapat mengatakan bahwa secara umum (disimpulkan dari dokumen) " bbox_to_anchoradalah tuple dari 4 float (x, y, lebar, tinggi bbox), atau tuple dari 2 float (x, y) dalam sumbu dinormalisasi koordinat. "
meduz
5
Saya harus mengakui bahwa ini mungkin jawaban SO saya yang paling banyak dikunjungi. Saya tidak bisa tidak kembali ke sana lagi karena tidak ada cara orang yang masuk akal dapat mengingat logika ini tanpa melihatnya di sini.
KT.
9
Perhatikan bahwa jika Anda ingin menyimpan gambar ke file, Anda mungkin harus menyimpan objek yang dikembalikan, yaitu legend = ax.legend()dan kemudianfig.savefig(bbox_extra_artists=(legend,))
coldfix
792

Menempatkan legenda ( bbox_to_anchor)

Legenda diposisikan di dalam kotak pembatas dari sumbu menggunakan locargumen untuk plt.legend.
Misalnya loc="upper right"menempatkan legenda di sudut kanan atas kotak pembatas, yang secara default meluas dari (0,0)ke (1,1)dalam koordinat sumbu (atau dalam notasi pembatas kotak (x0,y0, width, height)=(0,0,1,1)).

Untuk menempatkan legenda di luar kotak pembatas sumbu, seseorang dapat menentukan tupel (x0,y0)koordinat sumbu dari sudut kiri bawah legenda.

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

Namun, pendekatan yang lebih fleksibel adalah dengan menentukan secara manual kotak pembatas di mana legenda harus ditempatkan, menggunakan bbox_to_anchorargumen. Seseorang dapat membatasi diri hanya untuk memasok (x0,y0)bagian dari bbox. Ini menciptakan kotak rentang nol, di mana legenda akan berkembang ke arah yang diberikan oleh locargumen. Misalnya

plt.legend (bbox_to_anchor = (1.04,1), loc = "kiri atas")

menempatkan legenda di luar sumbu, sehingga sudut kiri atas legenda berada pada posisi (1.04,1)dalam koordinat sumbu.

Contoh lebih lanjut diberikan di bawah ini, di mana tambahan interaksi antara argumen yang berbeda seperti modedan ncolsditampilkan.

masukkan deskripsi gambar di sini

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

Rincian tentang bagaimana menafsirkan argumen 4-tuple bbox_to_anchor, seperti pada l4, dapat ditemukan dalam pertanyaan ini . The mode="expand"memperluas legenda horizontal dalam kotak berlari diberikan oleh 4-tupel. Untuk legenda yang diperluas secara vertikal, lihat pertanyaan ini .

Kadang-kadang mungkin berguna untuk menentukan kotak pembatas dalam koordinat angka, bukan koordinat sumbu. Ini ditunjukkan dalam contoh l5dari atas, di mana bbox_transformargumen digunakan untuk meletakkan legenda di sudut kiri bawah gambar.

Pengolahan pasca

Setelah menempatkan legenda di luar sumbu sering mengarah pada situasi yang tidak diinginkan bahwa itu sepenuhnya atau sebagian di luar kanvas gambar.

Solusi untuk masalah ini adalah:

  • Menyesuaikan parameter subplot
    Seseorang dapat menyesuaikan parameter subplot sedemikian rupa, sehingga sumbu mengambil lebih sedikit ruang di dalam gambar (dan dengan demikian meninggalkan lebih banyak ruang untuk legenda) dengan menggunakan plt.subplots_adjust. Misalnya

    plt.subplots_adjust(right=0.7)

    menyisakan 30% ruang di sisi kanan gambar, di mana orang bisa menempatkan legenda.

  • Tata letak yang ketat
    Menggunakan plt.tight_layoutMemungkinkan untuk secara otomatis menyesuaikan parameter subplot sedemikian rupa sehingga elemen-elemen pada gambar berada pada tepi gambar. Sayangnya, legenda tersebut tidak diperhitungkan dalam otomatisme ini, tetapi kami dapat menyediakan kotak persegi panjang yang dapat digunakan oleh seluruh area subplot (termasuk label).

    plt.tight_layout(rect=[0,0,0.75,1])
  • Menyimpan gambar denganbbox_inches = "tight"
    Argumen bbox_inches = "tight"untuk plt.savefigdapat digunakan untuk menyimpan gambar sedemikian rupa sehingga semua artis di kanvas (termasuk legenda) masuk ke dalam area yang disimpan. Jika perlu, ukuran gambar disesuaikan secara otomatis.

    plt.savefig("output.png", bbox_inches="tight")
  • secara otomatis menyesuaikan parplot subplot
    Cara untuk menyesuaikan posisi subplot secara otomatis sehingga legenda pas di dalam kanvas tanpa mengubah ukuran gambar dapat ditemukan dalam jawaban ini: Membuat gambar dengan ukuran tepat dan tanpa bantalan (dan legenda di luar sumbu)

Perbandingan antara kasus-kasus yang dibahas di atas:

masukkan deskripsi gambar di sini

Alternatif

Legenda figur
Seseorang dapat menggunakan legenda untuk figur alih-alih sumbu matplotlib.figure.Figure.legend,. Ini menjadi sangat berguna untuk versi matplotlib> = 2.1, di mana tidak ada argumen khusus yang diperlukan

fig.legend(loc=7) 

untuk menciptakan legenda bagi semua seniman di sumbu yang berbeda dari gambar. Legenda ditempatkan menggunakan locargumen, mirip dengan bagaimana ia ditempatkan di dalam sumbu, tetapi mengacu pada keseluruhan gambar - maka itu akan berada di luar sumbu agak otomatis. Yang tersisa adalah menyesuaikan subplot sehingga tidak ada tumpang tindih antara legenda dan sumbu. Di sini titik "Sesuaikan parameter subplot" dari atas akan sangat membantu. Sebuah contoh:

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

masukkan deskripsi gambar di sini

Legenda di dalam kapak subplot khusus
Alternatif untuk menggunakan bbox_to_anchoradalah menempatkan legenda dalam kapak subplot khusus ( lax). Karena subplot legenda harus lebih kecil dari plot, kita dapat menggunakan gridspec_kw={"width_ratios":[4,1]}pada pembuatan sumbu. Kita dapat menyembunyikan sumbu lax.axis("off")tetapi masih memasukkan legenda. Legenda menangani dan label perlu diperoleh dari plot nyata melalui h,l = ax.get_legend_handles_labels(), dan kemudian dapat dipasok ke legenda di laxsubplot lax.legend(h,l),. Contoh lengkapnya ada di bawah ini.

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

Ini menghasilkan plot yang secara visual sangat mirip dengan plot dari atas:

masukkan deskripsi gambar di sini

Kita juga bisa menggunakan kapak pertama untuk menempatkan legenda, tetapi gunakan bbox_transformkapak legenda,

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

Dalam pendekatan ini, kita tidak perlu mendapatkan gagang legenda secara eksternal, tetapi kita perlu menentukan bbox_to_anchorargumennya.

Bacaan dan catatan lebih lanjut:

  • Pertimbangkan panduan legenda matplotlib dengan beberapa contoh hal lain yang ingin Anda lakukan dengan legenda.
  • Beberapa contoh kode untuk menempatkan legenda untuk diagram lingkaran dapat langsung ditemukan sebagai jawaban atas pertanyaan ini: Python - Legenda tumpang tindih dengan diagram lingkaran
  • The locArgumen dapat mengambil angka bukan string, yang membuat panggilan pendek, namun, mereka tidak sangat intuitif dipetakan ke satu sama lain. Berikut adalah pemetaan untuk referensi:

masukkan deskripsi gambar di sini

ImportanceOfBeingErnest
sumber
Menempatkan legenda dalam sumbu subplot berdedikasi dengan sangat baik fig.tight_layout. Jika Anda menggunakan plt.subplotsuntuk membuat sumbu, cukup berikan sesuatu seperti gridspec_kw={'height_ratios': [100, 1]}(atau width_ratios) sehingga sumbu legenda itu kecil ... Kemudian fig.tight_layout()akan diperluas agar sesuai. Setidaknya untuk matplotlib 3.0.3.
travc
161

Panggil saja panggilan legend()setelah plot()panggilan seperti ini:

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

Hasilnya akan terlihat seperti ini:

masukkan deskripsi gambar di sini

Shital Shah
sumber
4
berfungsi ketika meneruskan parameter yang sama ke matplotlib.pyplot.legend juga
kidmose
8
Apakah ini memotong kata-kata dalam legenda untuk orang lain?
user1717828
85

Untuk menempatkan legenda di luar area plot, gunakan locdan bbox_to_anchorkata kunci dari legend(). Misalnya, kode berikut akan menempatkan legenda di sebelah kanan area plot:

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

Untuk info lebih lanjut, lihat panduan legenda

Christian Alis
sumber
10
Oke - Saya suka implementasinya, tetapi ketika saya pergi untuk menyimpan gambar (tanpa mengubah ukurannya secara manual di jendela, yang tidak ingin saya lakukan setiap waktu), legenda semakin terpotong. Ada ide tentang bagaimana saya bisa memperbaikinya?
astromax
@astromax Saya tidak yakin tetapi mungkin mencoba menelepon plt.tight_layout()?
Christian Alis
81

Jawaban singkat: Anda dapat menggunakan bbox_to_anchor+ bbox_extra_artists+ bbox_inches='tight'.


Jawaban yang lebih panjang: Anda dapat menggunakan bbox_to_anchoruntuk secara manual menentukan lokasi kotak legenda, seperti yang ditunjukkan beberapa orang lainnya dalam jawaban.

Namun, masalah yang biasa terjadi adalah kotak legenda dipangkas, misalnya:

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

masukkan deskripsi gambar di sini

Untuk mencegah kotak legenda dipotong, ketika Anda menyimpan gambar, Anda dapat menggunakan parameter bbox_extra_artistsdan bbox_inchesmeminta savefiguntuk memasukkan elemen yang dipotong dalam gambar yang disimpan:

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

Contoh (Saya hanya mengubah baris terakhir untuk menambahkan 2 parameter 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')

masukkan deskripsi gambar di sini

Saya berharap matplotlib akan mengizinkan lokasi di luar untuk kotak legenda seperti yang dilakukan 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])

masukkan deskripsi gambar di sini

Franck Dernoncourt
sumber
6
Terima kasih banyak! Parameter "bbox_to_anchor", "bbox_extra_artist" dan "" bbox_inches = 'tight "adalah persis apa yang saya butuhkan untuk membuatnya berfungsi dengan benar. Keren!
Demitrian
6
Terima kasih, tetapi sebenarnya bbox_inches='tight'berfungsi dengan baik untuk saya bahkan tanpa bbox_extra_artist
avtomaton
1
@avtomaton Terima kasih, baik untuk mengetahui, versi matplotlib apa yang Anda gunakan?
Franck Dernoncourt
1
@FranckDernoncourt python3, matplotlib versi 1.5.3
avtomaton
68

Selain semua jawaban yang sangat baik di sini, versi yang lebih baru matplotlibdan secara otomatispylab dapat menentukan di mana menempatkan legenda tanpa mengganggu plot , jika memungkinkan.

pylab.legend(loc='best')

Ini akan secara otomatis membuat legenda menjauh dari data jika memungkinkan! Bandingkan penggunaan loc = 'terbaik'

Namun, jika tidak ada tempat untuk meletakkan legenda tanpa tumpang tindih data, maka Anda akan ingin mencoba salah satu jawaban lainnya; menggunakan loc="best"tidak akan pernah menempatkan legenda di luar plot.

dotancohen
sumber
2
Terima kasih telah menunjukkan ini! Saya mencari ini beberapa tahun yang lalu dan tidak menemukannya, dan itu sesuatu yang benar-benar membuat hidup saya lebih mudah.
Edgar H
4
opsi ini bermanfaat tetapi tidak menjawab pertanyaan jadi saya downvoted. sejauh yang saya tahu, yang terbaik tidak pernah menempatkan legenda di luar plot
Tommy
3
@Tommy: Dalam komentar OP (yang tampaknya sudah hilang sekarang) secara eksplisit diklarifikasi bahwa OP ingin legenda tidak mencakup data grafik, dan dia berpikir bahwa di luar plot adalah satu-satunya cara untuk melakukan itu. Anda dapat melihat ini di jawaban dari mefathy, Mateo Sanchez, Bastiaan, dan radtek. OP meminta X, tapi ia ingin Y .
dotancohen
1
Sebenarnya tidak. Dia secara khusus meminta legenda berada di luar plot. Ada dalam nama pertanyaan;) "Bagaimana cara mengeluarkan legenda dari plot".
durbachit
4
Ini tidak menjamin bahwa legenda tidak mengaburkan data. Buat plot yang sangat padat - tidak ada tempat untuk menempatkan legenda. Sebagai contoh, coba ini ... dari numpy import arange, sin, pi import matplotlib.pyplot sebagai plt t = arange (0.0, 100.0, 0.01) fig = plt.figure (1) ax1 = fig.add_subplot (211) ax1. pencar (t, sin (2 * pi * t), label = 'test') ax1.grid (Benar) # ax1.set_ylim ((- 2, 2)) ax1.set_ylabel ('1 Hz') ax1.set_title ( 'Satu atau dua gelombang sinus') untuk label di ax1.get_xticklabels (): label.set_color ('r') plt.legend (loc = 'terbaik') plt.show ()
adam.r
56

Jawaban Singkat : Aktifkan draggable pada legenda dan pindahkan secara interaktif ke mana pun Anda inginkan:

ax.legend().draggable()

Jawaban Panjang : Jika Anda lebih suka menempatkan legenda secara interaktif / manual daripada secara terprogram, Anda dapat mengaktifkan mode legenda yang dapat diseret sehingga Anda dapat menyeretnya ke mana pun Anda inginkan. Lihat contoh di bawah ini:

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()
bodoh
sumber
Tidak yakin saya mengerti ini sepenuhnya. Bagaimana cara "menyeret" legenda ke mana pun saya mau dengan ini? Saya menggunakan Python 3.6 dan Jupyter Notebook
sb2020
14

Tidak persis apa yang Anda minta, tetapi saya menemukan itu alternatif untuk masalah yang sama. Jadikan legenda semi transparan, seperti: plot matplotlib dengan legenda semi transparan dan kotak teks semi transparan

Lakukan ini dengan:

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
sumber
8

Seperti yang disebutkan, Anda juga bisa menempatkan legenda di plot, atau sedikit melenceng ke tepi juga. Berikut adalah contoh menggunakan Plotly Python API , dibuat dengan IPython Notebook . Saya di tim.

Untuk memulai, Anda ingin menginstal paket yang diperlukan:

import plotly
import math
import random
import numpy as np

Kemudian, instal 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)

Ini membuat grafik Anda, dan memberi Anda kesempatan untuk menyimpan legenda di dalam plot itu sendiri. Default untuk legenda jika tidak disetel adalah menempatkannya dalam plot, seperti yang ditunjukkan di sini.

masukkan deskripsi gambar di sini

Untuk penempatan alternatif, Anda dapat menyelaraskan tepi grafik dan tepi legenda dengan dekat, dan menghapus garis batas untuk kesesuaian yang lebih dekat.

masukkan deskripsi gambar di sini

Anda dapat memindahkan dan menata ulang legenda dan grafik dengan kode, atau dengan GUI. Untuk menggeser legenda, Anda memiliki opsi berikut untuk memposisikan legenda di dalam grafik dengan menetapkan nilai x dan y dari <= 1. Misalnya:

  • {"x" : 0,"y" : 0} -- Kiri bawah
  • {"x" : 1, "y" : 0} -- Kanan bawah
  • {"x" : 1, "y" : 1} -- Kanan atas
  • {"x" : 0, "y" : 1} - Kiri Atas
  • {"x" :.5, "y" : 0} -- Tengah bawah
  • {"x": .5, "y" : 1} - Pusat Atas

Dalam hal ini, kami memilih kanan atas legendstyle = {"x" : 1, "y" : 1},, juga dijelaskan dalam dokumentasi :

masukkan deskripsi gambar di sini

Mateo Sanchez
sumber
3

Sesuatu di sepanjang garis ini bekerja untuk saya. Dimulai dengan sedikit kode yang diambil dari Joe, metode ini memodifikasi lebar jendela untuk secara otomatis sesuai dengan legenda di sebelah kanan gambar.

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
sumber
Saya menemukan ini sangat berguna dan berhasil untuk saya. Perhatikan bahwa jika Anda berada di backend wx (misalnya menggunakan windows), ganti mgr.window.wm_geometry ("% ix% i"% (winWidthNew, mgr.window.winfo_height ())) dengan mgr.window.SetClientSizeWH (winWidthNew , winHeightNew) atau sejenisnya
Yehezkiel Kruglick
Jika Anda menggunakan backend Qt4Agg (yang default pada instalasi Linux saya dari matplotlib), maka ganti mgr.window.wm_geometry(...)dengan mgr.window.setFixedWidth(winWidthNew).
Filip S.
Dan, seperti yang baru saja saya temukan, jika Anda menggunakan backend yang tidak menampilkan jendela apa pun, yang dimaksudkan untuk menyimpan langsung ke file (seperti backend SVG dan AGG), lewati saja ukuran jendela sama sekali. fig.set_size_inches(...)mengurus ukuran yang Anda butuhkan.
Filip S.
3

Sebaiknya segarkan pertanyaan ini, karena versi Matplotlib yang lebih baru telah membuatnya lebih mudah untuk memposisikan legenda di luar plot. Saya menghasilkan contoh ini dengan versi Matplotlib 3.1.1.

Pengguna dapat memberikan koordinat 2-tupel ke locparameter untuk memposisikan legenda di mana saja di kotak pembatas. Satu-satunya gotcha adalah Anda harus menjalankan plt.tight_layout()untuk mendapatkan matplotlib untuk menghitung ulang dimensi plot sehingga legenda terlihat:

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

Ini mengarah ke plot berikut:

plot dengan legenda di luar

Referensi:

luc
sumber
2

Anda juga bisa mencoba figlegend. Dimungkinkan untuk membuat legenda yang independen dari objek Axes apa pun. Namun, Anda mungkin perlu membuat beberapa Path "dummy" untuk memastikan pemformatan objek diteruskan dengan benar.

Uri Laserson
sumber
1

Berikut adalah contoh dari tutorial matplotlib yang ditemukan di sini . Ini adalah salah satu contoh yang lebih sederhana tetapi saya menambahkan transparansi ke legenda dan menambahkan plt.show () sehingga Anda dapat menempelkan ini ke shell interaktif dan mendapatkan hasilnya:

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
sumber
1

Solusi yang bekerja untuk saya ketika saya memiliki legenda besar adalah menggunakan tata letak gambar ekstra kosong. Dalam contoh berikut ini saya membuat 4 baris dan di bagian bawah saya memplot gambar dengan offset untuk legenda (bbox_to_anchor) di bagian atas tidak memotong.

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')
Kristal
sumber
1

Inilah solusi lain, mirip dengan menambahkan bbox_extra_artistsdan bbox_inches, di mana Anda tidak harus memiliki artis tambahan dalam lingkup Andasavefig panggilan . Saya datang dengan ini karena saya menghasilkan sebagian besar fungsi plot saya.

Alih-alih menambahkan semua tambahan Anda ke kotak pembatas ketika Anda ingin menuliskannya, Anda dapat menambahkannya sebelumnya ke Figureartis. Menggunakan sesuatu yang mirip dengan jawaban Franck Dernoncourt di atas :

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

Inilah plot yang dihasilkan.

ivirshup
sumber
-1

tidak tahu apakah Anda sudah menyelesaikan masalah Anda ... mungkin ya, tapi ... Saya hanya menggunakan string 'luar' untuk lokasi, seperti di matlab. Saya mengimpor pylab dari matplotlib. lihat kode sebagai berikut:

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)

Klik untuk melihat alurnya

Ziuccia
sumber