Güncelleme: Kullanıcı cphyc bu yanıttaki kod için nazikçe bir Github deposu oluşturdu ( buraya bakın ) ve kodu kullanılarak kurulabilecek bir pakete paketledi pip install matplotlib-label-lines
.
Güzel bir resim:
Gelen matplotlib
bu oldukça kolaydır etiket kontur araziler (otomatik veya manuel fare tıklaması ile etiket koyarak ya). Bu şekilde veri serilerini etiketlemek için eşdeğer bir yetenek (henüz) görünmemektedir! Eksik olduğum bu özelliği dahil etmemek için bazı anlamsal nedenler olabilir.
Her şeye rağmen, yarı otomatik grafik etiketlemeye izin veren aşağıdaki modülü yazdım. numpy
Standart math
kitaplıktan sadece ve birkaç işlev gerektirir .
Açıklama
labelLines
Fonksiyonun varsayılan davranışı , etiketleri x
eksen boyunca eşit aralıklarla yerleştirmektir y
(elbette otomatik olarak doğru değere yerleştirilir ). İsterseniz, her bir etiketin x koordinat dizisini iletebilirsiniz. Hatta bir etiketin konumunu (sağ alttaki grafikte gösterildiği gibi) değiştirebilir ve isterseniz geri kalanını eşit aralıklarla yerleştirebilirsiniz.
Ek olarak, label_lines
işlev, plot
komutta bir etiket atanmamış satırları hesaba katmaz (veya etiket içeriyorsa daha doğrusu '_line'
).
Kelime argümanlar geçirilen labelLines
veya labelLine
aktarılmaktadır text
işlev çağrısında (çağırarak kod seçer belirtmek değilse bazı anahtar kelime argümanlar ayarlanır).
Sorunlar
- Ek açıklama sınırlayıcı kutuları bazen diğer eğrilere istenmeyen şekilde müdahale eder. Sol üstteki grafikte
1
ve 10
ek açıklamalarla gösterildiği gibi . Bunun önlenebileceğinden bile emin değilim.
y
Bazen bunun yerine bir pozisyon belirlemek güzel olurdu .
- Ek açıklamaları doğru konuma almak için hala yinelemeli bir süreçtir
- Yalnızca
x
-axis değerleri float
s olduğunda çalışır
Gotchas
- Varsayılan olarak
labelLines
işlev, tüm veri serilerinin eksen sınırlarıyla belirtilen aralığı kapsadığını varsayar. Güzel resmin sol üst köşesindeki mavi eğriye bir bakın. x
Aralık için yalnızca veriler mevcut olsaydı 0.5
- 1
o zaman muhtemelen istenen konuma bir etiket yerleştiremezdik (bundan biraz daha küçüktür 0.2
). Özellikle kötü bir örnek için bu soruya bakın . Şu anda, kod bu senaryoyu akıllıca tanımlamıyor ve etiketleri yeniden düzenlemiyor, ancak makul bir geçici çözüm var. LabelLines işlevi xvals
argümanı alır ; x
genişlik boyunca varsayılan doğrusal dağılım yerine kullanıcı tarafından belirtilen değerler listesi . Böylece kullanıcı hangisininx
- Her veri serisinin etiket yerleşimi için kullanılacak değerler.
Ayrıca, etiketleri üzerinde bulundukları eğriye göre hizalama bonus hedefini tamamlamak için ilk cevabın bu olduğuna inanıyorum . :)
label_lines.py: 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)
Yukarıdaki güzel resmi oluşturmak için kodu test edin:
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()
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();
örneğim var : Bu, etiketlerden birini sol üst köşeye koyuyor. Bunu nasıl düzelteceğine dair bir fikrin var mı? Görünüşe göre sorun, çizgilerin birbirine çok yakın olması olabilir.