Skip to content

Commit 1503ac4

Browse files
authored
Merge pull request #25573 from tacaswell/fix_removed_widget_axes
FIX: be very paranoid about checking what the current canvas is
2 parents 2b75c9e + 5c83d7b commit 1503ac4

File tree

2 files changed

+34
-3
lines changed

2 files changed

+34
-3
lines changed

lib/matplotlib/tests/test_widgets.py

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import operator
44
from unittest import mock
55

6-
from matplotlib.backend_bases import MouseEvent
6+
from matplotlib.backend_bases import MouseEvent, DrawEvent
77
import matplotlib.colors as mcolors
88
import matplotlib.widgets as widgets
99
import matplotlib.pyplot as plt
@@ -1757,3 +1757,26 @@ def test_MultiCursor(horizOn, vertOn):
17571757
assert l.get_xdata() == (.5, .5)
17581758
for l in multi.hlines:
17591759
assert l.get_ydata() == (.25, .25)
1760+
1761+
1762+
def test_parent_axes_removal():
1763+
1764+
fig, (ax_radio, ax_checks) = plt.subplots(1, 2)
1765+
1766+
radio = widgets.RadioButtons(ax_radio, ['1', '2'], 0)
1767+
checks = widgets.CheckButtons(ax_checks, ['1', '2'], [True, False])
1768+
1769+
ax_checks.remove()
1770+
ax_radio.remove()
1771+
with io.BytesIO() as out:
1772+
# verify that saving does not raise
1773+
fig.savefig(out, format='raw')
1774+
1775+
# verify that this method which is triggered by a draw_event callback when
1776+
# blitting is enabled does not raise. Calling private methods is simpler
1777+
# than trying to force blitting to be enabled with Agg or use a GUI
1778+
# framework.
1779+
renderer = fig._get_renderer()
1780+
evt = DrawEvent('draw_event', fig.canvas, renderer)
1781+
radio._clear(evt)
1782+
checks._clear(evt)

lib/matplotlib/widgets.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,9 @@ def __init__(self, ax):
117117
self.ax = ax
118118
self._cids = []
119119

120-
canvas = property(lambda self: self.ax.get_figure(root=True).canvas)
120+
canvas = property(
121+
lambda self: getattr(self.ax.get_figure(root=True), 'canvas', None)
122+
)
121123

122124
def connect_event(self, event, callback):
123125
"""
@@ -144,6 +146,10 @@ def _get_data_coords(self, event):
144146
return ((event.xdata, event.ydata) if event.inaxes is self.ax
145147
else self.ax.transData.inverted().transform((event.x, event.y)))
146148

149+
def ignore(self, event):
150+
# docstring inherited
151+
return super().ignore(event) or self.canvas is None
152+
147153

148154
class Button(AxesWidget):
149155
"""
@@ -2181,7 +2187,9 @@ def connect_default_events(self):
21812187

21822188
def ignore(self, event):
21832189
# docstring inherited
2184-
if not self.active or not self.ax.get_visible():
2190+
if super().ignore(event):
2191+
return True
2192+
if not self.ax.get_visible():
21852193
return True
21862194
# If canvas was locked
21872195
if not self.canvas.widgetlock.available(self):

0 commit comments

Comments
 (0)