Matplotlib में एक बिंदु पर मँडरा करने पर लेबल दिखाई देना संभव है?


147

मैं तितर बितर भूखंड बनाने के लिए matplotlib का उपयोग कर रहा हूं। तितर बितर भूखंड पर प्रत्येक बिंदु एक नामित वस्तु के साथ जुड़ा हुआ है। जब मैं उस ऑब्जेक्ट से जुड़े स्कैटर प्लॉट पर बिंदु पर अपने कर्सर को घुमाता हूं, तो मैं किसी ऑब्जेक्ट का नाम देख पाऊंगा। विशेष रूप से, यह अच्छा होगा कि वे उन बिंदुओं के नामों को जल्दी से देख सकें जो आउटलेर हैं। यहाँ खोज करते समय मैं जो निकटतम चीज़ पा रहा हूँ वह एनोटेट कमांड है, लेकिन यह प्लॉट पर एक निश्चित लेबल बनाने के लिए प्रतीत होता है। दुर्भाग्य से, मेरे पास जितने बिंदु हैं, यदि मैं प्रत्येक बिंदु पर लेबल लगाता हूं तो स्कैटर प्लॉट अपठनीय होगा। क्या किसी को लेबल बनाने का एक तरीका पता है जो केवल तब दिखाई देता है जब कर्सर उस बिंदु के आसपास के क्षेत्र में घूमता है?


2
खोज के माध्यम से यहां समाप्त होने वाले लोग इस उत्तर को भी जांचना चाहते हैं , जो जटिल है, लेकिन आवश्यकताओं के आधार पर उपयुक्त हो सकता है।
इम्पोर्टेंसऑफबिंगएर्नेस्ट

जवाबों:


133

ऐसा लगता है कि यहां कोई भी अन्य उत्तर वास्तव में प्रश्न का उत्तर नहीं देता है। तो यहाँ एक कोड है जो स्कैटर का उपयोग करता है और स्कैटर पॉइंट्स पर मँडराता हुआ एक एनोटेशन दिखाता है ।

import matplotlib.pyplot as plt
import numpy as np; np.random.seed(1)

x = np.random.rand(15)
y = np.random.rand(15)
names = np.array(list("ABCDEFGHIJKLMNO"))
c = np.random.randint(1,5,size=15)

norm = plt.Normalize(1,4)
cmap = plt.cm.RdYlGn

fig,ax = plt.subplots()
sc = plt.scatter(x,y,c=c, s=100, cmap=cmap, norm=norm)

annot = ax.annotate("", xy=(0,0), xytext=(20,20),textcoords="offset points",
                    bbox=dict(boxstyle="round", fc="w"),
                    arrowprops=dict(arrowstyle="->"))
annot.set_visible(False)

def update_annot(ind):

    pos = sc.get_offsets()[ind["ind"][0]]
    annot.xy = pos
    text = "{}, {}".format(" ".join(list(map(str,ind["ind"]))), 
                           " ".join([names[n] for n in ind["ind"]]))
    annot.set_text(text)
    annot.get_bbox_patch().set_facecolor(cmap(norm(c[ind["ind"][0]])))
    annot.get_bbox_patch().set_alpha(0.4)


def hover(event):
    vis = annot.get_visible()
    if event.inaxes == ax:
        cont, ind = sc.contains(event)
        if cont:
            update_annot(ind)
            annot.set_visible(True)
            fig.canvas.draw_idle()
        else:
            if vis:
                annot.set_visible(False)
                fig.canvas.draw_idle()

fig.canvas.mpl_connect("motion_notify_event", hover)

plt.show()

यहां छवि विवरण दर्ज करें

क्योंकि लोग plotबिखराव के बजाय एक पंक्ति के लिए इस समाधान का उपयोग करना चाहते हैं , निम्नलिखित के लिए एक ही समाधान होगा plot(जो थोड़ा अलग तरीके से काम करता है)।

यदि कोई जुड़वाँ कुल्हाड़ियों में लाइनों के लिए एक समाधान की तलाश में है, तो कई अक्ष में एक बिंदु पर मँडराते समय लेबल कैसे प्रकट करें?

यदि कोई बार भूखंडों के समाधान की तलाश में है, तो कृपया इस उत्तर को उदाहरण के लिए देखें ।


1
बहुत अच्छा! एक नोट, मैंने देखा कि ind["ind"]वास्तव में क्यूरर्स के तहत सभी बिंदुओं के लिए अनुक्रमित की एक सूची है। इसका मतलब यह है कि उपरोक्त कोड वास्तव में आपको दिए गए स्थान पर सभी बिंदुओं तक पहुंच प्रदान करता है, और न केवल शीर्ष सबसे अधिक बिंदु। उदाहरण के लिए, यदि आपके पास दो अतिव्यापी बिंदु हैं तो पाठ पढ़ सकता है 1 2, B Cया भले 1 2 3, B C Dही आपके पास 3 अतिव्यापी बिंदु हों।
१२:४५ पर जेविनेक

@Jvinniec वास्तव में, उपरोक्त प्लाट में जानबूझकर एक ऐसा मामला है (x ~ 0.4 पर हरे और लाल बिंदु)। यदि आप इसे घुमाते हैं तो यह प्रदर्शित होगा 0 8, A I, ( चित्र देखें )।
ImportanceOfBeingErnest

@ImportanceOfBeingErnest यह एक बेहतरीन कोड है, लेकिन जब एक बिंदु पर मँडराते और हिलते हुए यह fig.canvas.draw_idle()कई बार कॉल करता है (यह कर्सर को निष्क्रिय करने के लिए भी बदल जाता है)। मैंने इसे पिछले इंडेक्स को स्टोर करके हल किया और चेक किया कि क्या ind["ind"][0] == prev_ind। फिर केवल तभी अपडेट करें जब आप एक बिंदु से दूसरे स्थान पर जाएं (पाठ को अपडेट करें), होवरिंग बंद करें (एनोटेशन अदृश्य करें) या होवरिंग शुरू करें (एनोटेशन दृश्यमान करें)। इस परिवर्तन के साथ यह अधिक स्वच्छ और कुशल है।
सेम्बी नोरिमकी

3
@Konstantin हाँ यह समाधान %matplotlib notebookIPython / Jupyter नोटबुक में उपयोग करते समय काम करेगा ।
महत्त्व 8

1
@OriolAbril (और बाकी सभी), यदि आपके पास एक समस्या है जो इस उत्तर से कोड को संशोधित करते समय उत्पन्न हुई है, तो कृपया इसके बारे में एक प्रश्न पूछें, इस उत्तर से लिंक करें और उस कोड को दिखाएं जिसे आपने प्रयास किया है। मेरे पास यह जानने का कोई तरीका नहीं है कि वास्तव में देखे बिना आपके प्रत्येक कोड में क्या गलत है।
इम्पोर्टेंसऑफबिंगएर्नेस्ट

66

जब यह क्लिक करने की आवश्यकता के बिना एक लाइन मँडराता है तो यह समाधान काम करता है:

import matplotlib.pyplot as plt

# Need to create as global variable so our callback(on_plot_hover) can access
fig = plt.figure()
plot = fig.add_subplot(111)

# create some curves
for i in range(4):
    # Giving unique ids to each data member
    plot.plot(
        [i*1,i*2,i*3,i*4],
        gid=i)

def on_plot_hover(event):
    # Iterating over each data member plotted
    for curve in plot.get_lines():
        # Searching which data member corresponds to current mouse position
        if curve.contains(event)[0]:
            print "over %s" % curve.get_gid()

fig.canvas.mpl_connect('motion_notify_event', on_plot_hover)           
plt.show()

1
बहुत उपयोगी + 1 ई। आपको संभवतः इसे 'डेबिट' करने की आवश्यकता है क्योंकि वक्र क्षेत्र के अंदर गति के लिए गति_नोटी_ईवेंट दोहराएगा। बस यह जाँचना कि वक्र वस्तु पिछले वक्र के बराबर है काम करने लगती है।
bvanlew

5
हम्म - यह मेरे लिए काम नहीं करता है (इसलिए कुछ चीजें मेरे साथ matplotlib...) - क्या यह नोटबंदी ipython/ jupyterनोटबंदी के साथ काम करती है ? क्या यह भी काम करता है जब कई सबप्लॉट होते हैं? लाइन-ग्राफ के बजाय बार-चार्ट के बारे में क्या?
dwanderson

12
यह लेबल को होवर करते समय कंसोल में प्रिंट करता है। होवर करते समय तस्वीर पर लेबल दिखाई देने के बारे में क्या ? मैं समझ गया कि यही सवाल है।
निकाना रेक्लाविक्स

@mbernasocchi बहुत-बहुत धन्यवाद, अगर मुझे हिस्टोग्राम (तितर बितर में प्रत्येक बिंदु के लिए एक अलग) या, और भी बेहतर, 2 डी हिस्टोग्राम का हीट-मैप देखना हो तो मुझे क्या करना चाहिए?
अमिताई

@NikanaReklawyks मैंने एक उत्तर जोड़ा जो वास्तव में प्रश्न का उत्तर देता है।
इम्पोर्टेंसऑफबिंगएर्नेस्ट

37

से http://matplotlib.sourceforge.net/examples/event_handling/pick_event_demo.html :

from matplotlib.pyplot import figure, show
import numpy as npy
from numpy.random import rand


if 1: # picking on a scatter plot (matplotlib.collections.RegularPolyCollection)

    x, y, c, s = rand(4, 100)
    def onpick3(event):
        ind = event.ind
        print('onpick3 scatter:', ind, npy.take(x, ind), npy.take(y, ind))

    fig = figure()
    ax1 = fig.add_subplot(111)
    col = ax1.scatter(x, y, 100*s, c, picker=True)
    #fig.savefig('pscoll.eps')
    fig.canvas.mpl_connect('pick_event', onpick3)

show()

यह सिर्फ मुझे क्या चाहिए, धन्यवाद! एक बोनस के रूप में, इसे लागू करने के लिए, मैंने अपने कार्यक्रम को फिर से लिखा, ताकि डेटा के दो सेटों का प्रतिनिधित्व करने के लिए एक ही आकृति पर अलग-अलग रंगों में दो अलग-अलग तितर बितर प्लॉट बनाने के बजाय, मैंने एक बिंदु पर रंग असाइन करने के लिए उदाहरण की विधि की प्रतिलिपि बनाई। इससे मेरा प्रोग्राम पढ़ने में थोड़ा सरल हो गया, और कम कोड। अब एक नंबर पर रंग बदलने के लिए एक गाइड खोजने के लिए बंद!
jdmcbr

1
यह तितर बितर भूखंडों के लिए है। लाइन भूखंडों के बारे में क्या? मैंने उन पर काम करने की कोशिश की, लेकिन ऐसा नहीं हुआ। क्या कोई वर्कअराउंड है?
सोहैब

@ सोहेब मेरा जवाब देखें
टेक्ससफ्लड

इस पर मेरा एक सवाल है। जब मैं अपने बिंदुओं को इस तरह बिखेरता हूँ: plt.scatter (X_reduced [y == i, 0], X_reduced [y == i, 1], c = c, label = target_name, picker = True = एक ज़िप के साथ i, c और target_name, तो क्या मेरे अनुक्रमित का क्रम गड़बड़ है? और मैं अब तक नहीं देख सकता कि यह किस डाटापॉइंट का है?
क्रिस

यह ipython 5 के साथ जुपिटर 5 नोटबुक के लिए काम नहीं करता है। क्या इसे ठीक करने का एक आसान तरीका है? printबयान में यह भी साथ अजगर 3 संगतता के लिए कोष्ठक का उपयोग करना चाहिए
nealmcb

14

Http://matplotlib.org/users/shell.html में दिए गए उदाहरण पर एक हल्का संपादन :

import numpy as np
import matplotlib.pyplot as plt

fig = plt.figure()
ax = fig.add_subplot(111)
ax.set_title('click on points')

line, = ax.plot(np.random.rand(100), '-', picker=5)  # 5 points tolerance


def onpick(event):
    thisline = event.artist
    xdata = thisline.get_xdata()
    ydata = thisline.get_ydata()
    ind = event.ind
    print('onpick points:', *zip(xdata[ind], ydata[ind]))


fig.canvas.mpl_connect('pick_event', onpick)

plt.show()

यह एक सीधी रेखा का प्लॉट है, जैसा कि सोहेब पूछ रहा था


5

mpld3 मेरे लिए इसे हल करें। संपादित करें (कोडित):

import matplotlib.pyplot as plt
import numpy as np
import mpld3

fig, ax = plt.subplots(subplot_kw=dict(axisbg='#EEEEEE'))
N = 100

scatter = ax.scatter(np.random.normal(size=N),
                 np.random.normal(size=N),
                 c=np.random.random(size=N),
                 s=1000 * np.random.random(size=N),
                 alpha=0.3,
                 cmap=plt.cm.jet)
ax.grid(color='white', linestyle='solid')

ax.set_title("Scatter Plot (with tooltips!)", size=20)

labels = ['point {0}'.format(i + 1) for i in range(N)]
tooltip = mpld3.plugins.PointLabelTooltip(scatter, labels=labels)
mpld3.plugins.connect(fig, tooltip)

mpld3.show()

आप इस उदाहरण को देख सकते हैं


कृपया नमूना कोड शामिल करें और बिना संदर्भ या जानकारी के केवल बाहरी स्रोतों से लिंक न करें। देखें सहायता केंद्र में अधिक जानकारी के लिए।
जोसेफ फराह

5
दुर्भाग्य से mpld3 अब जुलाई 2017 तक सक्रिय रूप से बनाए नहीं रखा जा रहा है
बेन लिंडसे

कोड नमूना ए के साथ विफल रहता है TypeError: array([1.]) is not JSON serializable
P-Gn

@ P-Gn बस यहाँ ट्रिक को फॉलो करें stackoverflow.com/questions/48015030/mpld3-with-python-error MPLD3 इसके लिए एक सरल उपाय है और एक बार उपरोक्त उत्तर का पालन करने पर यह काम करता है।
ज़लाकैन

1
@Zalakain दुर्भाग्य से, mpl3d को छोड़ दिया जा रहा है
पी-ग्न

5

mplcursors ने मेरे लिए काम किया। mplcursors matplotlib के लिए क्लिक करने योग्य एनोटेशन प्रदान करता है। यह एक बहुत ही सरल एपीआई के साथ, एमपील्डाटासकोर ( https://github.com/joferkington/mpldatacursor ) से काफी प्रेरित है।

import matplotlib.pyplot as plt
import numpy as np
import mplcursors

data = np.outer(range(10), range(1, 5))

fig, ax = plt.subplots()
lines = ax.plot(data)
ax.set_title("Click somewhere on a line.\nRight-click to deselect.\n"
             "Annotations can be dragged.")

mplcursors.cursor(lines) # or just mplcursors.cursor()

plt.show()

मैं इसका उपयोग खुद करता हूं, अब तक किसी के लिए सबसे आसान समाधान जल्दी में है। मैंने सिर्फ 70 लेबल प्लॉट किए हैं और matplotlibहर 10 वीं पंक्ति को समान रंग, ऐसा दर्द देता है। mplcursorsहालांकि इसे सुलझाएं।
अंजप

5

अन्य उत्तरों ने ज्यूपिटर इनलाइन मैटलोट्लिब आकृति के हाल के संस्करण में टूलटिप्स को ठीक से दिखाने की मेरी आवश्यकता को संबोधित नहीं किया। हालांकि यह एक काम करता है:

import matplotlib.pyplot as plt
import numpy as np
import mplcursors
np.random.seed(42)

fig, ax = plt.subplots()
ax.scatter(*np.random.random((2, 26)))
ax.set_title("Mouse over a point")
crs = mplcursors.cursor(ax,hover=True)

crs.connect("add", lambda sel: sel.annotation.set_text(
    'Point {},{}'.format(sel.target[0], sel.target[1])))
plt.show()

माउस के साथ एक बिंदु पर जाने पर निम्न चित्र जैसा कुछ दिखाई देता है: यहां छवि विवरण दर्ज करें



मैं यह काम जूपीटर लैब में नहीं कर सकता था। क्या यह शायद ज्यूपिटर नोटबुक में काम करता है लेकिन ज्यूपिटर लैब में नहीं?
MD004

3

यदि आप जूपिटर नोटबुक का उपयोग करते हैं, तो मेरा समाधान उतना ही सरल है:

%pylab
import matplotlib.pyplot as plt
import mplcursors
plt.plot(...)
mplcursors.cursor(hover=True)
plt.show()

आप कुछ पसंद कर सकते हैं यहां छवि विवरण दर्ज करें


अब तक का सबसे अच्छा समाधान, कोड की केवल कुछ पंक्तियाँ ही ओपी से
पूछती हैं

0

मैंने इसमें जोड़ने के लिए एक बहु-पंक्ति एनोटेशन प्रणाली बनाई है: https://stackoverflow.com/a/47166787/10302020 । नवीनतम संस्करण के लिए: https://github.com/AidenBurgess/MultiAnnotationLineGraph

बस नीचे खंड में डेटा बदलें।

import matplotlib.pyplot as plt


def update_annot(ind, line, annot, ydata):
    x, y = line.get_data()
    annot.xy = (x[ind["ind"][0]], y[ind["ind"][0]])
    # Get x and y values, then format them to be displayed
    x_values = " ".join(list(map(str, ind["ind"])))
    y_values = " ".join(str(ydata[n]) for n in ind["ind"])
    text = "{}, {}".format(x_values, y_values)
    annot.set_text(text)
    annot.get_bbox_patch().set_alpha(0.4)


def hover(event, line_info):
    line, annot, ydata = line_info
    vis = annot.get_visible()
    if event.inaxes == ax:
        # Draw annotations if cursor in right position
        cont, ind = line.contains(event)
        if cont:
            update_annot(ind, line, annot, ydata)
            annot.set_visible(True)
            fig.canvas.draw_idle()
        else:
            # Don't draw annotations
            if vis:
                annot.set_visible(False)
                fig.canvas.draw_idle()


def plot_line(x, y):
    line, = plt.plot(x, y, marker="o")
    # Annotation style may be changed here
    annot = ax.annotate("", xy=(0, 0), xytext=(-20, 20), textcoords="offset points",
                        bbox=dict(boxstyle="round", fc="w"),
                        arrowprops=dict(arrowstyle="->"))
    annot.set_visible(False)
    line_info = [line, annot, y]
    fig.canvas.mpl_connect("motion_notify_event",
                           lambda event: hover(event, line_info))


# Your data values to plot
x1 = range(21)
y1 = range(0, 21)
x2 = range(21)
y2 = range(0, 42, 2)
# Plot line graphs
fig, ax = plt.subplots()
plot_line(x1, y1)
plot_line(x2, y2)
plt.show()
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.