Skip to content

Commit 1c6f6c9

Browse files
committed
Prevent GC of animations, sliders still in use.
1 parent 5914990 commit 1c6f6c9

File tree

2 files changed

+17
-42
lines changed

2 files changed

+17
-42
lines changed

lib/matplotlib/animation.py

+6-3
Original file line numberDiff line numberDiff line change
@@ -929,14 +929,17 @@ def __init__(self, fig, event_source=None, blit=False):
929929
self.frame_seq = self.new_frame_seq()
930930
self.event_source = event_source
931931

932+
# Wrapper lambdas prevent GC.
933+
932934
# Instead of starting the event source now, we connect to the figure's
933935
# draw_event, so that we only start once the figure has been drawn.
934-
self._first_draw_id = fig.canvas.mpl_connect('draw_event', self._start)
936+
self._first_draw_id = fig.canvas.mpl_connect(
937+
'draw_event', lambda event: self._start(event))
935938

936939
# Connect to the figure's close_event so that we don't continue to
937940
# fire events and try to draw to a deleted figure.
938-
self._close_id = self._fig.canvas.mpl_connect('close_event',
939-
self._stop)
941+
self._close_id = self._fig.canvas.mpl_connect(
942+
'close_event', lambda event: self._stop(event))
940943
if self._blit:
941944
self._setup_blit()
942945

lib/matplotlib/widgets.py

+11-39
Original file line numberDiff line numberDiff line change
@@ -94,14 +94,6 @@ class AxesWidget(Widget):
9494
"""
9595
Widget connected to a single `~matplotlib.axes.Axes`.
9696
97-
To guarantee that the widget remains responsive and not garbage-collected,
98-
a reference to the object should be maintained by the user.
99-
100-
This is necessary because the callback registry
101-
maintains only weak-refs to the functions, which are member
102-
functions of the widget. If there are no references to the widget
103-
object it may be garbage collected which will disconnect the callbacks.
104-
10597
Attributes
10698
----------
10799
ax : `~matplotlib.axes.Axes`
@@ -121,9 +113,11 @@ def connect_event(self, event, callback):
121113
Connect callback with an event.
122114
123115
This should be used in lieu of `figure.canvas.mpl_connect` since this
124-
function stores callback ids for later clean up.
116+
function stores callback ids for later clean up, and sets up a wrapper
117+
callback to prevent the original callback and thus the widget from
118+
being garbage collected.
125119
"""
126-
cid = self.canvas.mpl_connect(event, callback)
120+
cid = self.canvas.mpl_connect(event, lambda event: callback(event))
127121
self.cids.append(cid)
128122

129123
def disconnect_events(self):
@@ -136,7 +130,6 @@ class Button(AxesWidget):
136130
"""
137131
A GUI neutral button.
138132
139-
For the button to remain responsive you must keep a reference to it.
140133
Call `.on_clicked` to connect to the button.
141134
142135
Attributes
@@ -247,9 +240,8 @@ class Slider(AxesWidget):
247240
"""
248241
A slider representing a floating point range.
249242
250-
Create a slider from *valmin* to *valmax* in axes *ax*. For the slider to
251-
remain responsive you must maintain a reference to it. Call
252-
:meth:`on_changed` to connect to the slider event.
243+
Create a slider from *valmin* to *valmax* in axes *ax*.
244+
Call :meth:`on_changed` to connect to the slider event.
253245
254246
Attributes
255247
----------
@@ -505,9 +497,6 @@ class CheckButtons(AxesWidget):
505497
r"""
506498
A GUI neutral set of check buttons.
507499
508-
For the check buttons to remain responsive you must keep a
509-
reference to this object.
510-
511500
Connect to the CheckButtons with the `.on_clicked` method.
512501
513502
Attributes
@@ -660,8 +649,6 @@ class TextBox(AxesWidget):
660649
"""
661650
A GUI neutral text input box.
662651
663-
For the text box to remain responsive you must keep a reference to it.
664-
665652
Call `.on_text_change` to be updated whenever the text changes.
666653
667654
Call `.on_submit` to be updated whenever the user hits enter or
@@ -968,9 +955,6 @@ class RadioButtons(AxesWidget):
968955
"""
969956
A GUI neutral radio button.
970957
971-
For the buttons to remain responsive you must keep a reference to this
972-
object.
973-
974958
Connect to the RadioButtons with the `.on_clicked` method.
975959
976960
Attributes
@@ -1236,8 +1220,6 @@ class Cursor(AxesWidget):
12361220
"""
12371221
A crosshair cursor that spans the axes and moves with mouse cursor.
12381222
1239-
For the cursor to remain responsive you must keep a reference to it.
1240-
12411223
Parameters
12421224
----------
12431225
ax : `matplotlib.axes.Axes`
@@ -1331,8 +1313,6 @@ class MultiCursor(Widget):
13311313
Provide a vertical (default) and/or horizontal line cursor shared between
13321314
multiple axes.
13331315
1334-
For the cursor to remain responsive you must keep a reference to it.
1335-
13361316
Example usage::
13371317
13381318
from matplotlib.widgets import MultiCursor
@@ -1386,9 +1366,11 @@ def __init__(self, canvas, axes, useblit=True, horizOn=False, vertOn=True,
13861366

13871367
def connect(self):
13881368
"""connect events"""
1389-
self._cidmotion = self.canvas.mpl_connect('motion_notify_event',
1390-
self.onmove)
1391-
self._ciddraw = self.canvas.mpl_connect('draw_event', self.clear)
1369+
# Wrapper lambdas prevent GC.
1370+
self._cidmotion = self.canvas.mpl_connect(
1371+
'motion_notify_event', lambda event: self.onmove(event))
1372+
self._ciddraw = self.canvas.mpl_connect(
1373+
'draw_event', lambda event: self.clear(event))
13921374

13931375
def disconnect(self):
13941376
"""disconnect events"""
@@ -1656,8 +1638,6 @@ class SpanSelector(_SelectorWidget):
16561638
Visually select a min/max range on a single axis and call a function with
16571639
those values.
16581640
1659-
To guarantee that the selector remains responsive, keep a reference to it.
1660-
16611641
In order to turn off the SpanSelector, set ``span_selector.active`` to
16621642
False. To turn it back on, set it to True.
16631643
@@ -1932,8 +1912,6 @@ class RectangleSelector(_SelectorWidget):
19321912
"""
19331913
Select a rectangular region of an axes.
19341914
1935-
For the cursor to remain responsive you must keep a reference to it.
1936-
19371915
Example usage::
19381916
19391917
import numpy as np
@@ -2357,8 +2335,6 @@ class EllipseSelector(RectangleSelector):
23572335
"""
23582336
Select an elliptical region of an axes.
23592337
2360-
For the cursor to remain responsive you must keep a reference to it.
2361-
23622338
Example usage::
23632339
23642340
import numpy as np
@@ -2427,8 +2403,6 @@ class LassoSelector(_SelectorWidget):
24272403
"""
24282404
Selection curve of an arbitrary shape.
24292405
2430-
For the selector to remain responsive you must keep a reference to it.
2431-
24322406
The selected path can be used in conjunction with `~.Path.contains_point`
24332407
to select data points from an image.
24342408
@@ -2509,8 +2483,6 @@ class PolygonSelector(_SelectorWidget):
25092483
drag anywhere in the axes to move all vertices. Press the *esc* key to
25102484
start a new polygon.
25112485
2512-
For the selector to remain responsive you must keep a reference to it.
2513-
25142486
Parameters
25152487
----------
25162488
ax : `~matplotlib.axes.Axes`

0 commit comments

Comments
 (0)