Order of function execution in callbacks

The following code puts some text on the screen, and makes a callback that should replace the text with “Please wait…” and then sleep for 2 seconds when the user clicks on the figure. Instead, when the user clicks on the figure, the code waits for 2 seconds and then updates the screen.

Is this a bug, or an error on my part? I was sure to create the new text and call plt.draw() before sleep(2) so I would expect the new text to appear before the 2-second sleep.

import matplotlib.pyplot as plt
from time import sleep

class TimeDemo():
    
    def __init__(self):
        self.fig, self.ax = plt.subplots()
        self.ax.axis("off")
        self.axtext = self.ax.annotate("Please click somewhere.", xy=(0, 0.5), ha="left", va="center")
        self.donecid = self.fig.canvas.mpl_connect("button_press_event", self.donecallback)    
    def sleeper(self):
        sleep(2)
        plt.draw()
    
    def donecallback(self, event):
        self.fig.canvas.mpl_disconnect(self.donecid)
        self.axtext.remove()
        self.axtext = self.ax.annotate("Please wait...", xy=(0, 0.5), ha="left", va="center")
        plt.draw()
        self.sleeper()

mydemo = TimeDemo()

plt.show()

sleep will stop running entirely. This will cause your window to be unresponsive. You probably want to use plt.sleep instead.

Thank you! Interesting. Using plt.pause does resolve that particular problem. I should have explained in my first post, though, that sleep or plt.pause was just a stand-in for another method which takes a few seconds to execute. If I try

def sleeper(self):
        n = 100
        for j in range(50000):
            np.ones((n, n))*np.ones((n, n))
        plt.draw()

then I still do not see the new text until after sleeper has finished executing. Why is this occurring, and how can I fix this?

plt.draw is lazy; to force a redraw, use fig.canvas.draw().

Or if your slow process has some leeway, you should call plt.pause periodically with a short interval so that the window stays responsive.

Thank you very much! I see what you mean - according to the documentation, plt.draw() is equivalent to fig.canvas.draw_idle() which does not redraw until the end of the event loop. On the other hand, fig.canvas.draw() draws on demand. Using it fixed my problem.