Skip to content

Commit f13e212

Browse files
committed
Fix pickling of AxesWidgets.
There's no need to hold onto the (non-picklable) canvas as an attribute.
1 parent d347c32 commit f13e212

File tree

3 files changed

+23
-28
lines changed

3 files changed

+23
-28
lines changed

lib/matplotlib/tests/test_pickle.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -307,3 +307,11 @@ def test_cycler():
307307
ax = pickle.loads(pickle.dumps(ax))
308308
l, = ax.plot([3, 4])
309309
assert l.get_color() == "m"
310+
311+
312+
# Run under an interactive backend to test that we don't try to pickle the
313+
# (interactive and non-picklable) canvas.
314+
@pytest.mark.backend('tkagg')
315+
def test_axeswidget_interactive():
316+
ax = plt.figure().add_subplot()
317+
pickle.dumps(mpl.widgets.Button(ax, "button"))

lib/matplotlib/widgets.py

Lines changed: 8 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -90,22 +90,6 @@ def ignore(self, event):
9090
"""
9191
return not self.active
9292

93-
def _changed_canvas(self):
94-
"""
95-
Someone has switched the canvas on us!
96-
97-
This happens if `savefig` needs to save to a format the previous
98-
backend did not support (e.g. saving a figure using an Agg based
99-
backend saved to a vector format).
100-
101-
Returns
102-
-------
103-
bool
104-
True if the canvas has been changed.
105-
106-
"""
107-
return self.canvas is not self.ax.figure.canvas
108-
10993

11094
class AxesWidget(Widget):
11195
"""
@@ -131,9 +115,10 @@ class AxesWidget(Widget):
131115

132116
def __init__(self, ax):
133117
self.ax = ax
134-
self.canvas = ax.figure.canvas
135118
self._cids = []
136119

120+
canvas = property(lambda self: self.ax.figure.canvas)
121+
137122
def connect_event(self, event, callback):
138123
"""
139124
Connect a callback function with an event.
@@ -1100,7 +1085,7 @@ def __init__(self, ax, labels, actives=None, *, useblit=True,
11001085

11011086
def _clear(self, event):
11021087
"""Internal event handler to clear the buttons."""
1103-
if self.ignore(event) or self._changed_canvas():
1088+
if self.ignore(event) or self.canvas.is_saving():
11041089
return
11051090
self._background = self.canvas.copy_from_bbox(self.ax.bbox)
11061091
self.ax.draw_artist(self._checks)
@@ -1677,7 +1662,7 @@ def __init__(self, ax, labels, active=0, activecolor=None, *,
16771662

16781663
def _clear(self, event):
16791664
"""Internal event handler to clear the buttons."""
1680-
if self.ignore(event) or self._changed_canvas():
1665+
if self.ignore(event) or self.canvas.is_saving():
16811666
return
16821667
self._background = self.canvas.copy_from_bbox(self.ax.bbox)
16831668
self.ax.draw_artist(self._buttons)
@@ -1933,7 +1918,7 @@ def __init__(self, ax, *, horizOn=True, vertOn=True, useblit=False,
19331918

19341919
def clear(self, event):
19351920
"""Internal event handler to clear the cursor."""
1936-
if self.ignore(event) or self._changed_canvas():
1921+
if self.ignore(event) or self.canvas.is_saving():
19371922
return
19381923
if self.useblit:
19391924
self.background = self.canvas.copy_from_bbox(self.ax.bbox)
@@ -2573,9 +2558,7 @@ def __init__(self, ax, onselect, direction, *, minspan=0, useblit=False,
25732558
self.drag_from_anywhere = drag_from_anywhere
25742559
self.ignore_event_outside = ignore_event_outside
25752560

2576-
# Reset canvas so that `new_axes` connects events.
2577-
self.canvas = None
2578-
self.new_axes(ax, _props=props)
2561+
self.new_axes(ax, _props=props, _init=True)
25792562

25802563
# Setup handles
25812564
self._handle_props = {
@@ -2588,14 +2571,12 @@ def __init__(self, ax, onselect, direction, *, minspan=0, useblit=False,
25882571

25892572
self._active_handle = None
25902573

2591-
def new_axes(self, ax, *, _props=None):
2574+
def new_axes(self, ax, *, _props=None, _init=False):
25922575
"""Set SpanSelector to operate on a new Axes."""
25932576
self.ax = ax
2594-
if self.canvas is not ax.figure.canvas:
2577+
if _init or self.canvas is not ax.figure.canvas:
25952578
if self.canvas is not None:
25962579
self.disconnect_events()
2597-
2598-
self.canvas = ax.figure.canvas
25992580
self.connect_default_events()
26002581

26012582
# Reset

lib/matplotlib/widgets.pyi

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -330,7 +330,13 @@ class SpanSelector(_SelectorWidget):
330330
ignore_event_outside: bool = ...,
331331
snap_values: ArrayLike | None = ...,
332332
) -> None: ...
333-
def new_axes(self, ax: Axes, *, _props: dict[str, Any] | None = ...) -> None: ...
333+
def new_axes(
334+
self,
335+
ax: Axes,
336+
*,
337+
_props: dict[str, Any] | None = ...,
338+
_init: bool = ...,
339+
) -> None: ...
334340
def connect_default_events(self) -> None: ...
335341
@property
336342
def direction(self) -> Literal["horizontal", "vertical"]: ...

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy