diff --git a/lib/matplotlib/backend_bases.py b/lib/matplotlib/backend_bases.py index e6fb59fe52a7..3736fe28db7b 100644 --- a/lib/matplotlib/backend_bases.py +++ b/lib/matplotlib/backend_bases.py @@ -1640,8 +1640,10 @@ def _fix_ipython_backend2gui(cls): @contextmanager def _idle_draw_cntx(self): self._is_idle_drawing = True - yield - self._is_idle_drawing = False + try: + yield + finally: + self._is_idle_drawing = False def is_saving(self): """ diff --git a/lib/matplotlib/backends/backend_qt5.py b/lib/matplotlib/backends/backend_qt5.py index 181dcb4843f7..66a685eee223 100644 --- a/lib/matplotlib/backends/backend_qt5.py +++ b/lib/matplotlib/backends/backend_qt5.py @@ -498,16 +498,17 @@ def draw_idle(self): QtCore.QTimer.singleShot(0, self._draw_idle) def _draw_idle(self): - if not self._draw_pending: - return - self._draw_pending = False - if self.height() < 0 or self.width() < 0: - return - try: - self.draw() - except Exception: - # Uncaught exceptions are fatal for PyQt5, so catch them instead. - traceback.print_exc() + with self._idle_draw_cntx(): + if not self._draw_pending: + return + self._draw_pending = False + if self.height() < 0 or self.width() < 0: + return + try: + self.draw() + except Exception: + # Uncaught exceptions are fatal for PyQt5, so catch them. + traceback.print_exc() def drawRectangle(self, rect): # Draw the zoom rectangle to the QPainter. _draw_rect_callback needs diff --git a/lib/matplotlib/pyplot.py b/lib/matplotlib/pyplot.py index 88d13ed3eab4..0313ee6ac3c8 100644 --- a/lib/matplotlib/pyplot.py +++ b/lib/matplotlib/pyplot.py @@ -585,8 +585,15 @@ def _auto_draw_if_interactive(fig, val): fig : Figure A figure object which is assumed to be associated with a canvas """ - if val and matplotlib.is_interactive() and not fig.canvas.is_saving(): - fig.canvas.draw_idle() + if (val and matplotlib.is_interactive() + and not fig.canvas.is_saving() + and not fig.canvas._is_idle_drawing): + # Some artists can mark themselves as stale in the middle of drawing + # (e.g. axes position & tick labels being computed at draw time), but + # this shouldn't trigger a redraw because the current redraw will + # already take them into account. + with fig.canvas._idle_draw_cntx(): + fig.canvas.draw_idle() def gcf():