From 702b4292792dddf45e540eabf6ef91da24c640a2 Mon Sep 17 00:00:00 2001 From: Vikash Kumar Date: Wed, 18 Mar 2026 11:15:37 +0530 Subject: [PATCH 1/2] FIX: Prevent crash when removing a subfigure containing subplots --- lib/matplotlib/artist.py | 3 ++- lib/matplotlib/tests/test_figure.py | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/matplotlib/artist.py b/lib/matplotlib/artist.py index cb6e650a94cc..62778d42b7dd 100644 --- a/lib/matplotlib/artist.py +++ b/lib/matplotlib/artist.py @@ -255,7 +255,8 @@ def remove(self): # clear stale callback self.stale_callback = None _ax_flag = False - if hasattr(self, 'axes') and self.axes: + from matplotlib.axes import Axes + if hasattr(self, 'axes') and self.axes is not None and isinstance(self.axes, Axes): # remove from the mouse hit list self.axes._mouseover_set.discard(self) self.axes.stale = True diff --git a/lib/matplotlib/tests/test_figure.py b/lib/matplotlib/tests/test_figure.py index 93aff4b1a632..744f12846bb9 100644 --- a/lib/matplotlib/tests/test_figure.py +++ b/lib/matplotlib/tests/test_figure.py @@ -1575,6 +1575,7 @@ def test_subfigures_wspace_hspace(): def test_subfigure_remove(): fig = plt.figure() sfs = fig.subfigures(2, 2) + sfs[1, 1].subplots() sfs[1, 1].remove() assert len(fig.subfigs) == 3 From 270287d7df126f05b55187fc6fdec70272d8d9f7 Mon Sep 17 00:00:00 2001 From: Vikash Kumar Date: Wed, 18 Mar 2026 19:59:12 +0530 Subject: [PATCH 2/2] Use attribute-based guard in Artist.remove --- lib/matplotlib/artist.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/matplotlib/artist.py b/lib/matplotlib/artist.py index 62778d42b7dd..e3e6b3ca2d7c 100644 --- a/lib/matplotlib/artist.py +++ b/lib/matplotlib/artist.py @@ -255,11 +255,12 @@ def remove(self): # clear stale callback self.stale_callback = None _ax_flag = False - from matplotlib.axes import Axes - if hasattr(self, 'axes') and self.axes is not None and isinstance(self.axes, Axes): + ax = getattr(self, 'axes', None) + mouseover_set = getattr(ax, '_mouseover_set', None) + if mouseover_set is not None: # remove from the mouse hit list - self.axes._mouseover_set.discard(self) - self.axes.stale = True + mouseover_set.discard(self) + ax.stale = True self.axes = None # decouple the artist from the Axes _ax_flag = True