Di Matplotlib, tidak terlalu sulit untuk membuat legenda ( example_legend()
, di bawah), tapi menurut saya gaya yang lebih baik adalah meletakkan label tepat pada kurva yang sedang diplot (seperti di example_inline()
, di bawah). Ini bisa sangat rumit, karena saya harus menentukan koordinat dengan tangan, dan, jika saya memformat ulang plot, saya mungkin harus mengubah posisi label. Apakah ada cara untuk secara otomatis menghasilkan label pada kurva di Matplotlib? Poin bonus untuk dapat mengarahkan teks pada sudut yang sesuai dengan sudut kurva.
import numpy as np
import matplotlib.pyplot as plt
def example_legend():
plt.clf()
x = np.linspace(0, 1, 101)
y1 = np.sin(x * np.pi / 2)
y2 = np.cos(x * np.pi / 2)
plt.plot(x, y1, label='sin')
plt.plot(x, y2, label='cos')
plt.legend()
def example_inline():
plt.clf()
x = np.linspace(0, 1, 101)
y1 = np.sin(x * np.pi / 2)
y2 = np.cos(x * np.pi / 2)
plt.plot(x, y1, label='sin')
plt.plot(x, y2, label='cos')
plt.text(0.08, 0.2, 'sin')
plt.text(0.9, 0.2, 'cos')
sumber
plt.plot(x2, 3*x2**2, label="3x*x"); plt.plot(x2, 2*x2**2, label="2x*x"); plt.plot(x2, 0.5*x2**2, label="0.5x*x"); plt.plot(x2, -1*x2**2, label="-x*x"); plt.plot(x2, -2.5*x2**2, label="-2.5*x*x"); my_legend();
Ini menempatkan salah satu label di sudut kiri atas. Ada ide tentang cara memperbaikinya? Sepertinya masalahnya mungkin garis-garisnya terlalu berdekatan.x2 = np.linspace(0,0.5,100)
.print
perintah, itu berjalan dan membuat 4 plot, 3 di antaranya tampak seperti omong kosong pixelated (mungkin ada hubungannya dengan 32x32), dan yang keempat dengan label di tempat-tempat aneh.Pembaruan: Pengguna cphyc telah dengan ramah membuat repositori Github untuk kode dalam jawaban ini (lihat di sini ), dan memaketkan kode ke dalam paket yang dapat diinstal menggunakan
pip install matplotlib-label-lines
.Gambar yang indah:
Di
matplotlib
dalamnya cukup mudah untuk memberi label pada plot kontur (baik secara otomatis atau dengan menempatkan label secara manual dengan klik mouse). Tampaknya belum ada kemampuan yang setara untuk melabeli seri data dengan cara ini! Mungkin ada beberapa alasan semantik untuk tidak menyertakan fitur ini yang saya lewatkan.Terlepas dari itu, saya telah menulis modul berikut yang memungkinkan pelabelan plot semi-otomatis. Ini hanya membutuhkan
numpy
dan beberapa fungsi darimath
perpustakaan standar .Deskripsi
Perilaku default dari
labelLines
fungsi ini adalah memberi jarak label secara merata di sepanjangx
sumbu (tentu saja secara otomatis menempatkan pada nilai yang benary
). Jika mau, Anda bisa meneruskan larik koordinat x dari masing-masing label. Anda bahkan dapat mengubah lokasi satu label (seperti yang ditunjukkan di plot kanan bawah) dan memberi jarak pada label lainnya secara merata jika Anda mau.Selain itu,
label_lines
fungsi tersebut tidak memperhitungkan baris yang belum diberi label padaplot
perintah (atau lebih akurat jika label berisi'_line'
).Argumen kata kunci diteruskan ke
labelLines
ataulabelLine
diteruskan ketext
pemanggilan fungsi (beberapa argumen kata kunci disetel jika kode pemanggil memilih untuk tidak menentukan).Masalah
1
dan10
di plot kiri atas. Saya bahkan tidak yakin ini bisa dihindari.y
posisi kadang-kadang.x
-axis adalahfloat
sGotchas
labelLines
fungsi mengasumsikan bahwa semua rangkaian data menjangkau rentang yang ditentukan oleh batas sumbu. Perhatikan kurva biru di kiri atas gambar cantik. Jika hanya ada data yang tersedia untukx
rentang tersebut0.5
-1
maka kami tidak mungkin menempatkan label di lokasi yang diinginkan (yang sedikit kurang dari0.2
). Lihat pertanyaan ini untuk contoh yang sangat buruk. Saat ini, kode tidak dengan cerdas mengidentifikasi skenario ini dan mengatur ulang label, namun ada solusi yang masuk akal. Fungsi labelLines mengambilxvals
argumen; daftar-x
nilai yang ditentukan oleh pengguna, bukan distribusi linier default di seluruh lebar. Sehingga pengguna bisa memutuskan yang manax
-nilai yang akan digunakan untuk penempatan label dari setiap seri data.Juga, saya yakin ini adalah jawaban pertama untuk menyelesaikan tujuan bonus dalam menyelaraskan label dengan kurva tempat mereka berada. :)
label_lines.py:
from math import atan2,degrees import numpy as np #Label line with line2D label data def labelLine(line,x,label=None,align=True,**kwargs): ax = line.axes xdata = line.get_xdata() ydata = line.get_ydata() if (x < xdata[0]) or (x > xdata[-1]): print('x label location is outside data range!') return #Find corresponding y co-ordinate and angle of the line ip = 1 for i in range(len(xdata)): if x < xdata[i]: ip = i break y = ydata[ip-1] + (ydata[ip]-ydata[ip-1])*(x-xdata[ip-1])/(xdata[ip]-xdata[ip-1]) if not label: label = line.get_label() if align: #Compute the slope dx = xdata[ip] - xdata[ip-1] dy = ydata[ip] - ydata[ip-1] ang = degrees(atan2(dy,dx)) #Transform to screen co-ordinates pt = np.array([x,y]).reshape((1,2)) trans_angle = ax.transData.transform_angles(np.array((ang,)),pt)[0] else: trans_angle = 0 #Set a bunch of keyword arguments if 'color' not in kwargs: kwargs['color'] = line.get_color() if ('horizontalalignment' not in kwargs) and ('ha' not in kwargs): kwargs['ha'] = 'center' if ('verticalalignment' not in kwargs) and ('va' not in kwargs): kwargs['va'] = 'center' if 'backgroundcolor' not in kwargs: kwargs['backgroundcolor'] = ax.get_facecolor() if 'clip_on' not in kwargs: kwargs['clip_on'] = True if 'zorder' not in kwargs: kwargs['zorder'] = 2.5 ax.text(x,y,label,rotation=trans_angle,**kwargs) def labelLines(lines,align=True,xvals=None,**kwargs): ax = lines[0].axes labLines = [] labels = [] #Take only the lines which have labels other than the default ones for line in lines: label = line.get_label() if "_line" not in label: labLines.append(line) labels.append(label) if xvals is None: xmin,xmax = ax.get_xlim() xvals = np.linspace(xmin,xmax,len(labLines)+2)[1:-1] for line,x,label in zip(labLines,xvals,labels): labelLine(line,x,label,align,**kwargs)
Uji kode untuk menghasilkan gambar cantik di atas:
from matplotlib import pyplot as plt from scipy.stats import loglaplace,chi2 from labellines import * X = np.linspace(0,1,500) A = [1,2,5,10,20] funcs = [np.arctan,np.sin,loglaplace(4).pdf,chi2(5).pdf] plt.subplot(221) for a in A: plt.plot(X,np.arctan(a*X),label=str(a)) labelLines(plt.gca().get_lines(),zorder=2.5) plt.subplot(222) for a in A: plt.plot(X,np.sin(a*X),label=str(a)) labelLines(plt.gca().get_lines(),align=False,fontsize=14) plt.subplot(223) for a in A: plt.plot(X,loglaplace(4).pdf(a*X),label=str(a)) xvals = [0.8,0.55,0.22,0.104,0.045] labelLines(plt.gca().get_lines(),align=False,xvals=xvals,color='k') plt.subplot(224) for a in A: plt.plot(X,chi2(5).pdf(a*X),label=str(a)) lines = plt.gca().get_lines() l1=lines[-1] labelLine(l1,0.6,label=r'$Re=${}'.format(l1.get_label()),ha='left',va='bottom',align = False) labelLines(lines[:-1],align=False) plt.show()
sumber
xvals
, Anda mungkin ingin sedikit memodifikasilabelLines
kode: ubah kode di bawahif xvals is None:
cakupan untuk membuat daftar berdasarkan kriteria lain. Anda bisa mulai denganxvals = [(np.min(l.get_xdata())+np.max(l.get_xdata()))/2 for l in lines]
.get_axes()
dan.get_axis_bgcolor()
sudah tidak digunakan lagi. Harap ganti dengan.axes
dan.get_facecolor()
, resp.labellines
adalah properti yang terkaitplt.text
atauax.text
berlaku untuk itu. Artinya Anda dapat mengaturfontsize
danbbox
parameter dalamlabelLines()
fungsi tersebut.Jawaban @Jan Kuiken tentu saja dipikirkan dengan matang dan menyeluruh, tetapi ada beberapa peringatan:
Pendekatan yang jauh lebih sederhana adalah memberi anotasi pada poin terakhir dari setiap plot. Intinya juga bisa dilingkari, untuk penekanan. Ini dapat dilakukan dengan satu baris tambahan:
from matplotlib import pyplot as plt for i, (x, y) in enumerate(samples): plt.plot(x, y) plt.text(x[-1], y[-1], 'sample {i}'.format(i=i))
Varian akan digunakan
ax.annotate
.sumber
-1
, 2) menetapkan batas sumbu yang sesuai untuk memberi ruang bagi label.Pendekatan yang lebih sederhana seperti yang dilakukan Ioannis Filippidis:
import matplotlib.pyplot as plt import numpy as np # evenly sampled time at 200ms intervals tMin=-1 ;tMax=10 t = np.arange(tMin, tMax, 0.1) # red dashes, blue points default plt.plot(t, 22*t, 'r--', t, t**2, 'b') factor=3/4 ;offset=20 # text position in view textPosition=[(tMax+tMin)*factor,22*(tMax+tMin)*factor] plt.text(textPosition[0],textPosition[1]+offset,'22 t',color='red',fontsize=20) textPosition=[(tMax+tMin)*factor,((tMax+tMin)*factor)**2+20] plt.text(textPosition[0],textPosition[1]+offset, 't^2', bbox=dict(facecolor='blue', alpha=0.5),fontsize=20) plt.show()
kode python 3 di sageCell
sumber