From 9faecaf9cc21452ca7167825ee5a4b397ce2af62 Mon Sep 17 00:00:00 2001 From: Mohit Pal Date: Tue, 24 Mar 2026 21:41:33 +0000 Subject: [PATCH 1/6] Fix: Prevent Cursor blitting from erasing overlapping axes --- lib/matplotlib/widgets.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/lib/matplotlib/widgets.py b/lib/matplotlib/widgets.py index 92c9b779ff09..70968755484e 100644 --- a/lib/matplotlib/widgets.py +++ b/lib/matplotlib/widgets.py @@ -2124,6 +2124,14 @@ def onmove(self, event): background = self._load_blit_background() if background is not None: self.canvas.restore_region(background) + + # --- UPDATED FIX STARTS HERE --- + # If there are other axes overlapping with the cursor's area, redraw them completely + for ax_ in self.ax.get_figure(root=True).get_axes(): + if ax_ is not self.ax and self.ax.bbox.overlaps(ax_.bbox): + self.ax.draw_artist(ax_) + # --- UPDATED FIX ENDS HERE --- + self.ax.draw_artist(self.linev) self.ax.draw_artist(self.lineh) self.canvas.blit(self.ax.bbox) From b39eaf19e6d76c0fe1e82a184de98ce338545a10 Mon Sep 17 00:00:00 2001 From: Mohit Pal Date: Tue, 24 Mar 2026 21:54:46 +0000 Subject: [PATCH 2/6] Fix styling: remove trailing whitespace and shorten comment --- lib/matplotlib/widgets.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/matplotlib/widgets.py b/lib/matplotlib/widgets.py index 70968755484e..514ee32853e5 100644 --- a/lib/matplotlib/widgets.py +++ b/lib/matplotlib/widgets.py @@ -2119,14 +2119,15 @@ def onmove(self, event): self.lineh.set_visible(self.visible and self.horizOn) if not (self.visible and (self.vertOn or self.horizOn)): return - # Redraw. + # Redraw. if self.useblit: background = self._load_blit_background() if background is not None: self.canvas.restore_region(background) - + # --- UPDATED FIX STARTS HERE --- - # If there are other axes overlapping with the cursor's area, redraw them completely + # If there are other axes overlapping with the cursor's area, + # redraw them completely. for ax_ in self.ax.get_figure(root=True).get_axes(): if ax_ is not self.ax and self.ax.bbox.overlaps(ax_.bbox): self.ax.draw_artist(ax_) From d1f0a3342b5eeef2747f36f6a4a8febd645c22f2 Mon Sep 17 00:00:00 2001 From: Mohit Pal Date: Sun, 29 Mar 2026 22:06:44 +0000 Subject: [PATCH 3/6] MAINT: explicitly mark Cursor blitting on overlapping axes as unsupported --- lib/matplotlib/widgets.py | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/lib/matplotlib/widgets.py b/lib/matplotlib/widgets.py index 514ee32853e5..b19726e3e380 100644 --- a/lib/matplotlib/widgets.py +++ b/lib/matplotlib/widgets.py @@ -2084,6 +2084,18 @@ def __init__(self, ax, *, horizOn=True, vertOn=True, useblit=False, self.vertOn = vertOn self.useblit = useblit and self.canvas.supports_blit # TODO: make dynamic + # --- NEW CODE: Check for overlapping axes and fallback --- + if self.useblit: + for ax_ in ax.get_figure(root=True).get_axes(): + if ax_ is not ax and ax.bbox.overlaps(ax_.bbox): + _api.warn_external( + "Cursor blitting is currently not supported on overlapping axes; " + "falling back to useblit=False." + ) + self.useblit = False + break + # --------------------------------------------------------- + if self.useblit: lineprops['animated'] = True self.lineh = ax.axhline(ax.get_ybound()[0], visible=False, **lineprops) @@ -2125,14 +2137,6 @@ def onmove(self, event): if background is not None: self.canvas.restore_region(background) - # --- UPDATED FIX STARTS HERE --- - # If there are other axes overlapping with the cursor's area, - # redraw them completely. - for ax_ in self.ax.get_figure(root=True).get_axes(): - if ax_ is not self.ax and self.ax.bbox.overlaps(ax_.bbox): - self.ax.draw_artist(ax_) - # --- UPDATED FIX ENDS HERE --- - self.ax.draw_artist(self.linev) self.ax.draw_artist(self.lineh) self.canvas.blit(self.ax.bbox) From 1a29cbcb03aebf758661475019d8504b99a7bfd4 Mon Sep 17 00:00:00 2001 From: Mohit Pal Date: Sun, 29 Mar 2026 22:11:39 +0000 Subject: [PATCH 4/6] style: fix ruff line length limit in widgets.py --- lib/matplotlib/widgets.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/matplotlib/widgets.py b/lib/matplotlib/widgets.py index b19726e3e380..e32197a8dcf7 100644 --- a/lib/matplotlib/widgets.py +++ b/lib/matplotlib/widgets.py @@ -2089,8 +2089,8 @@ def __init__(self, ax, *, horizOn=True, vertOn=True, useblit=False, for ax_ in ax.get_figure(root=True).get_axes(): if ax_ is not ax and ax.bbox.overlaps(ax_.bbox): _api.warn_external( - "Cursor blitting is currently not supported on overlapping axes; " - "falling back to useblit=False." + "Cursor blitting is currently not supported on " + "overlapping axes; falling back to useblit=False." ) self.useblit = False break From 1098b0564a4e75d4d425639639982e59ceeb126e Mon Sep 17 00:00:00 2001 From: Mohit Pal Date: Mon, 30 Mar 2026 07:31:36 +0000 Subject: [PATCH 5/6] test: add coverage for cursor overlapping axes warning --- lib/matplotlib/tests/test_widgets.py | 16 ++++++++++++++++ lib/matplotlib/widgets.py | 5 +---- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/lib/matplotlib/tests/test_widgets.py b/lib/matplotlib/tests/test_widgets.py index 0ac24dc8e8e4..a35e310c2962 100644 --- a/lib/matplotlib/tests/test_widgets.py +++ b/lib/matplotlib/tests/test_widgets.py @@ -1817,3 +1817,19 @@ def test_parent_axes_removal(): evt = DrawEvent('draw_event', fig.canvas, renderer) radio._clear(evt) checks._clear(evt) + + +def test_cursor_overlapping_axes_blitting_warning(): + """Test that a warning is raised and useblit is disabled for overlapping axes.""" + fig = plt.figure() + ax1 = fig.add_axes([0.1, 0.1, 0.8, 0.8]) + ax2 = fig.add_axes([0.2, 0.2, 0.6, 0.6]) # Explicitly overlaps ax1 + + match_text = ( + "Cursor blitting is currently not supported on " + "overlapping axes" + ) + with pytest.warns(UserWarning, match=match_text): + cursor = widgets.Cursor(ax1, useblit=True) + + assert cursor.useblit is False diff --git a/lib/matplotlib/widgets.py b/lib/matplotlib/widgets.py index e32197a8dcf7..9ab4548157fd 100644 --- a/lib/matplotlib/widgets.py +++ b/lib/matplotlib/widgets.py @@ -2084,7 +2084,6 @@ def __init__(self, ax, *, horizOn=True, vertOn=True, useblit=False, self.vertOn = vertOn self.useblit = useblit and self.canvas.supports_blit # TODO: make dynamic - # --- NEW CODE: Check for overlapping axes and fallback --- if self.useblit: for ax_ in ax.get_figure(root=True).get_axes(): if ax_ is not ax and ax.bbox.overlaps(ax_.bbox): @@ -2094,7 +2093,6 @@ def __init__(self, ax, *, horizOn=True, vertOn=True, useblit=False, ) self.useblit = False break - # --------------------------------------------------------- if self.useblit: lineprops['animated'] = True @@ -2131,12 +2129,11 @@ def onmove(self, event): self.lineh.set_visible(self.visible and self.horizOn) if not (self.visible and (self.vertOn or self.horizOn)): return - # Redraw. + # Redraw. if self.useblit: background = self._load_blit_background() if background is not None: self.canvas.restore_region(background) - self.ax.draw_artist(self.linev) self.ax.draw_artist(self.lineh) self.canvas.blit(self.ax.bbox) From f2050aefd22fe82247ae90a631587dcd384e219d Mon Sep 17 00:00:00 2001 From: Mohit Pal Date: Mon, 30 Mar 2026 08:46:17 +0000 Subject: [PATCH 6/6] chore: trigger CI to clear Windows timeout flake