I'm trying to show two interactive plots. The second plot is displayed after the first plot is closed. In this minimal example, the interactive part just draws a dot wherever the user clicks and prints the coordinates to the console.
import matplotlib.pyplot as plt
def onclick(event):
# This prints both times
print(event.xdata, event.ydata)
# This only works the first time
plt.scatter(event.xdata, event.ydata)
for i in range(2):
plt.plot([1, 2, 3, 4])
plt.gca().figure.canvas.mpl_connect('button_press_event', onclick)
with plt.ion():
plt.show(block=True)
Using the code above, dots don't show up on the second plot. It still prints the coordinates, so the event is firing; it's just not drawing. Everything else works.
Things I've tried that didn't help:
plt.close()
as the last step inside loopplt.pause(1)
as the last step inside loopplt.ion()
and plt.ioff()
instead of the context managercanvas.mpl_disconnect(cid)
with the cid returned from mpl_connect
plt.draw()
& plt.pause(1)
to try and force updatesfig, ax = plt.subplots()
in the loop and ax.scatter()
in the onclick
handler to explicitly plot to the same axesI'm using matplotlib 3.9.4 in Python 3.9.20 for compatibility with things beyond my control.
In addition to Fff's answer, which reattaches the event handler after each plt.show()
, I found two others that work:
plt.draw()
at the end of the event handler (plt.draw_idle()
does not work)plt.ion()
and leave it that wayIt seems like toggling interactive mode off and on again confuses matplotlib such that it doesn't know where to draw stuff.
For now, I'm using plt.draw()
since that seems like the least complicated solution; attaching the same event multiple times seems less intuitive. If anyone has an explanation or a better solution, please let me know!
Solution for now:
import matplotlib.pyplot as plt
def onclick(event):
print(event.xdata, event.ydata)
plt.gca().scatter(event.xdata, event.ydata)
plt.draw() # draw_idle() doesn't work, but this does!
for i in range(2):
plt.plot([1, 2, 3, 4])
plt.gca().figure.canvas.mpl_connect('button_press_event', onclick)
with plt.ion():
plt.show(block=True)