pythonmatplotlibplotinteractiveipympl

Why does matplotlib draw updates for the first interactive plot I show, but not the second?


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:

I'm using matplotlib 3.9.4 in Python 3.9.20 for compatibility with things beyond my control.


Solution

  • In addition to Fff's answer, which reattaches the event handler after each plt.show(), I found two others that work:

    It 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)