Scott
Scott

Reputation: 51

Pause Python script until user clicks on plot twice

I'm trying to write a script that saves the coordinates of the first two mouse clicks on a plot (generated via matplotlib), pausing the script until these clicks occur. I tried to implement the "pause" with a while loop, which should finish once the callback function detects that the mouse has been clicked twice. However, once the while loop starts running, clicking on the plot area seems to have no effect. Any help would be much appreciated.

coords = []
pause = True

fig, ax = plt.subplots()
plt.pcolormesh(x_grid, y_grid, arr)
plt.show()

def onclick(event):
    global coords
    coords.append((event.xdata, event.ydata))
    if (len(coords)==2):
        pause = False
        fig.canvas.mpl_disconnect(cid)

cid = fig.canvas.mpl_connect('button_press_event', onclick)

while pause:
    pass

# ...More code to follow, after the while loop finishes

Upvotes: 2

Views: 1716

Answers (1)

Andrew Long
Andrew Long

Reputation: 1011

Edited Answer: I would look into something like this, they have a demo app but this seems to be exactly the functionality you want.

https://matplotlib.org/devdocs/api/_as_gen/matplotlib.pyplot.ginput.html

This would turn your code into:

plt.pcolormesh(x_grid, y_grid, arr)
coords = plt.ginput(2, show_clicks=False)
plot.show(block=False)

This would return the first two click coords in the window and leave the plot open.

-- Original Answer

Do you care about the plot being open after clicking? If not, then you can remove the while loop because the plt.show() function is inherently blocking. New version of code is then:

coords = []
fig, ax = plt.subplots()
plt.pcolormesh(x_grid, y_grid,arr)

def onclick(event):
    global coords
    coords.append((event.xdata, event.ydata))
    if (len(coords)==2):
        fig.canvas.mpl_disconnect(cid)
        plt.close()

cid = fig.canvas.mpl_connect('button_press_event', onclick)
plt.show()
print('Finished')

You could always (assuming the plot isn't super long to render) just have a call afterwards like:

plt.pcolormesh(x_grid, y_grid, arr)
plt.show(block=False)

To generate a non-blocking version of your plot after the clicking process is done. (This seems dumb but I can't seem to find a quick way to convert a blocking figure into a nonblocking figure)

Upvotes: 1

Related Questions