अपडेट: उपयोगकर्ता cphyc ने इस उत्तर में कोड के लिए कृपया एक Github रिपॉजिटरी बनाई है ( यहां देखें ), और कोड को एक पैकेज में बंडल किया, जिसका उपयोग करके इंस्टॉल किया जा सकता है pip install matplotlib-label-lines
।
सुन्दर तस्वीर:
में matplotlib
इसे करने के लिए बहुत आसान है लेबल समोच्च भूखंडों (स्वत: या मैन्युअल माउस क्लिक के साथ लेबल रखकर या तो)। इस शैली में डेटा श्रृंखला को लेबल करने की कोई समतुल्य क्षमता नहीं है (अभी तक)! इस सुविधा को शामिल न करने के कुछ अर्थिक कारण हो सकते हैं जो मुझे याद आ रहे हैं।
बावजूद, मैंने निम्नलिखित मॉड्यूल को लिखा है जो अर्ध-स्वचालित प्लॉट लेबलिंग के लिए कोई भी अनुमति देता है। इसके numpy
लिए मानक math
पुस्तकालय से केवल और कुछ कार्यों की आवश्यकता है ।
विवरण
labelLines
फ़ंक्शन का डिफ़ॉल्ट व्यवहार समान रूप से x
अक्ष के साथ लेबल को स्पेस करना है (स्वचालित रूप से सही y
-वेल्यू पर रखकर )। यदि आप चाहें तो आप प्रत्येक लेबल के x सह-निर्देशांक की एक सरणी को पारित कर सकते हैं। आप एक लेबल के स्थान को भी ट्विक कर सकते हैं (जैसा कि नीचे दाएं प्लॉट में दिखाया गया है) और बाकी को समान रूप से स्पेस दें यदि आप चाहें तो।
इसके अलावा, label_lines
फ़ंक्शन उन लाइनों के लिए खाता नहीं है जिनके पास plot
कमांड में लेबल लेबल नहीं है (या यदि लेबल में अधिक सटीक है '_line'
)।
कीवर्ड तर्कों को पारित कर दिया labelLines
या labelLine
को भेजी जाती हैं text
समारोह कॉल (कुछ कीवर्ड तर्क अगर बुला कोड चुनता निर्दिष्ट करने के लिए नहीं स्थापित कर रहे हैं)।
मुद्दे
- एनोटेशन बाउंडिंग बॉक्स कभी-कभी अन्य घटता के साथ अवांछनीय रूप से हस्तक्षेप करते हैं। जैसा कि शीर्ष बाएँ प्लॉट में
1
और 10
एनोटेशन द्वारा दिखाया गया है । मुझे यकीन नहीं है कि इससे बचा जा सकता है।
y
कभी-कभी इसके बजाय एक स्थिति निर्दिष्ट करना अच्छा होगा ।
- सही स्थान पर एनोटेशन प्राप्त करना अभी भी एक पुनरावृति प्रक्रिया है
- यह केवल तभी काम करता है जब
x
-axis मान float
एस
gotchas
- डिफ़ॉल्ट रूप से,
labelLines
फ़ंक्शन मानता है कि सभी डेटा श्रृंखला अक्ष सीमा द्वारा निर्दिष्ट सीमा का विस्तार करते हैं। सुंदर चित्र के शीर्ष बाएँ प्लॉट में नीले रंग की वक्र पर एक नज़र डालें। यदि x
रेंज के लिए केवल डेटा उपलब्ध थे 0.5
- 1
तो हम संभवतः वांछित स्थान पर एक लेबल नहीं लगा सकते हैं (जो थोड़ा कम है 0.2
)। इस प्रश्न को विशेष रूप से बुरा उदाहरण के लिए देखें । अभी, कोड बुद्धिमानी से इस परिदृश्य की पहचान नहीं करता है और लेबल को फिर से व्यवस्थित करता है, हालांकि एक उचित समाधान है। लेबललाइन फ़ंक्शन xvals
तर्क लेता है; x
चौड़ाई में डिफ़ॉल्ट रेखीय वितरण के बजाय उपयोगकर्ता द्वारा निर्दिष्ट- सूची की सूची । तो उपयोगकर्ता जो तय कर सकता हैx
प्रत्येक डेटा श्रृंखला के लेबल प्लेसमेंट के लिए उपयोग करने के तरीके।
इसके अलावा, मेरा मानना है कि लेबल को वक्र के साथ संरेखित करने के बोनस उद्देश्य को पूरा करने के लिए यह पहला उत्तर है । :)
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)
ऊपर सुंदर चित्र बनाने के लिए टेस्ट कोड:
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();
यह ऊपरी बाएँ कोने में लेबल में से एक डालता है। कोई राय कि इसे कैसे ठीक किया जाए? समस्या की तरह लगता है कि लाइनें एक साथ बहुत करीब हैं।