0

I have been provided existing code that draws multiple lines on a given plot. The code is long and so I will only post the code I have written and hope that is sufficient.The code I wrote is built off of code that I found here: Possible to make labels appear when hovering over a point in matplotlib?

The problem is that it will only print an annotation on the last line that is printed on the figure with multiple lines (I also print out a legend and it is the last in the list of that legend).

I placed a couple of print statements that you can see in the code below. Under the conditional hit I print the label to the console and this changes as I move from line to line and works flawlessly in the console. Next you'll notice that I call the update_annot function. Inside this function I print out another statement verifying I am in the function. The console shows that each time I hover over a line it does, in fact, enter the function; however, the annotation box does not show up, except for the one line. Below is my code. The first snippet is called with the existing function, plotData.

annot = ax.annotate("", xy=(-20,20), xytext=(None),textcoords="offset 
                    points",
                    bbox=dict(fc="b"),
                    arrowprops=dict(arrowstyle="->"))
annot.set_visible(True)
h = lambda x: self.hover(x, ax, annot)
fig.canvas.mpl_connect("motion_notify_event", h)

#

def update_annot(self, annot, label, ind, x, y):
    print ("Entered update annot")
    annot.xy = (x[ind["ind"][0]], y[ind["ind"][0]])
    annot.set_text(label)
    annot.get_bbox_patch().set_alpha(0.4)
#end of update_annot



def hover(self, event, ax, annot):
    #if event.inaxes == ax:
    for curve in ax.get_lines():
        label = curve.get_label()
        x,y = curve.get_data()
        hit, ind = curve.contains(event)

        if hit:
            print(label)
            self.update_annot(annot, label, ind, x, y)
            annot.set_visible(True)
            plt.draw()
        else:
            annot.set_visible(False)
            plt.draw()

I expect to see the annotation box show up on every line; but instead it only shows up on one of the lines printed. This confuses me because it prints the label on the console correctly each time it enter the conditional hit and it also enters the update function each time. I am really new to Python, so if there are any suggestions in my code (even outside of the problem) I would love to hear them. Also, as I noted I am building off of code that I found on here. I am still unsure what the annot.xy does since the xy is already defined when annot is defined. Thank you in advance.

  • 1
    You have a single annotation but, say, 6 lines. Suppose your mouse is over one of the lines, say, the third. Then the annotation will be set invisible twice, then set visible, then again set invisible three more times. The result is that it is invisible. Same for every line, except the last, which is set invisible five times first, and then set visible; it therefore stays visible. – ImportanceOfBeingErnest Dec 19 '18 at 19:27
  • I understand. Fixed with a simple return! Thank you for your help. I am still not understanding a portion of the code that I would really like to understand. What is going on here: `annot.xy = (x[ind["ind"][0]], y[ind["ind"][0]])`? – Dymaxion Fuller Dec 19 '18 at 19:44
  • 1
    This part gives you the coordinates of the point of the line where the mouse hits it and sets the annotation's position to those coordinates. You may or may not find it necessary, as you are annotating the complete line. You may also choose a fixed position, or use the mouse coordinates themselves as position. – ImportanceOfBeingErnest Dec 19 '18 at 19:50
  • @ImportanceOfBeingErnest I see that it places it near the data point, but being new to Python I am trying to understand the syntax. So, x coordinate is set by `x[ind["ind"][0]]`. How does that work? Why do you need the `"ind"`? What is the `[0]`? Perhaps there is documentation on this? Thanks for the help and your time. It is much appreciated. – Dymaxion Fuller Dec 19 '18 at 20:50
  • `ind` is a dictionary. `ind["ind"]` selects the list of indices that are hit from it. `[0]` takes the first (and possibly only) element from that list. This index is then used to select the respective element from `x`. This is then the x-coordinate where to position the annotation. Same thing for `y`. – ImportanceOfBeingErnest Dec 19 '18 at 21:36

0 Answers0