Picker event handler is being invoked multiple times for a single event

23 Views Asked by At

In my Matplotlib plot, I've created a number Circle artists that, when one is clicked, should result in having some information appear in an annotation. I have the basic code working except that I am seeing multiple calls to the handler occur even when the artist is only clicked one time. Normally, I'd try to debug this with the Python debugger except that it won't work in the Matplotlib event loop.

The handler code for this event is below. The artists parameter is a dict, keyed by the artist and holding a data structure as its value. This is the info to be put into the annotation.

def on_pick(event, artists):
    artist = event.artist
    print(f"pick event, {artist} class {artist.__class__}")
    if artist in artists:
        x = artist.center[0]
        y = artist.center[1]
        a = plt.annotate(f"{artists[artist].getX()}", xy=(x,y), xycoords='data')
        artist.axes.figure.canvas.draw_idle()
        print("done")
    else:
        print("on_pick: artist not found")

Each artist has it's picker attribute set to True and the on_pick function is installed as the handler for the pick event. When I run my program, the plot is created, and I click on one of the circles. I do see the annotation appear, as expected, but then I get a second, or more, invocation of the handler as seen here.

pick event, Circle(xy=(0.427338, 0.431087), radius=0.00287205) class <class 'matplotlib.patches.Circle'>
done
pick event, Circle(xy=(0.427338, 0.431087), radius=0.00287205) class <class 'matplotlib.patches.Circle'>
on_pick: artist not found

The first two lines are the correct ones while the second two are from the unexpected 2nd invocation. I'm also mystified as to why the artist isn't being found since its the exact same from the first call.

Any thoughts as to what might be happening?

2

There are 2 best solutions below

0
paime On

Can't reproduce with the following, please provide a reproducible example.

import matplotlib.pyplot as plt
from matplotlib.patches import Circle

fig, ax = plt.subplots()

circle1 = Circle((0, 0), 0.6, color="blue", fill=False)
circle2 = Circle((1, 1), 0.9, color="red", fill=False)

circle1.set_picker(True)
circle2.set_picker(True)

ax.add_patch(circle1)
ax.add_patch(circle2)

def on_pick(event):
    print(f"Clicked on {event.artist}")

fig.canvas.mpl_connect("pick_event", on_pick)

ax.set_xlim(-1, 2)
ax.set_ylim(-1, 2)
ax.set_aspect("equal")

plt.show()
0
sizzzzlerz On

I discovered the cause. In other code, the rectangle in which the circle resides is being filled when the mouse enters. This covers the circle, hiding it from view. as a result, I recreate the circle artist in the same position so that, one, it appears in the rectangle, and two, creates a second circle artist. When a pick event occurs, the first invocation of the handler is passed the first instantiation of the artist. The second invocation is passed the second. Since this second circle wasn't part of the dict, the search for it on the second time fails. In short, the problem was a coding/logic error, not an issue with Matplotlib and the picker.