Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 58b1000

Browse files
committed
Prevent GC of animations and widgets still in use.
1 parent 5914990 commit 58b1000

10 files changed

+28
-54
lines changed

examples/animation/animate_decay.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,6 @@ def run(data):
4747

4848
return line,
4949

50-
ani = animation.FuncAnimation(fig, run, data_gen, blit=False, interval=10,
51-
repeat=False, init_func=init)
50+
animation.FuncAnimation(fig, run, data_gen, blit=False, interval=10,
51+
repeat=False, init_func=init)
5252
plt.show()

examples/animation/animated_histogram.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,5 +87,5 @@ def animate(i):
8787
ax.set_xlim(left[0], right[-1])
8888
ax.set_ylim(bottom.min(), top.max())
8989

90-
ani = animation.FuncAnimation(fig, animate, 100, repeat=False, blit=True)
90+
animation.FuncAnimation(fig, animate, 100, repeat=False, blit=True)
9191
plt.show()

examples/animation/bayes_update.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,6 @@ def __call__(self, i):
6262

6363
fig, ax = plt.subplots()
6464
ud = UpdateDist(ax, prob=0.7)
65-
anim = FuncAnimation(fig, ud, frames=np.arange(100), init_func=ud.init,
66-
interval=100, blit=True)
65+
FuncAnimation(fig, ud, frames=np.arange(100), init_func=ud.init,
66+
interval=100, blit=True)
6767
plt.show()

examples/animation/double_pendulum_sgskip.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,6 @@ def animate(i):
9494
return line, time_text
9595

9696

97-
ani = animation.FuncAnimation(fig, animate, range(1, len(y)),
98-
interval=dt*1000, blit=True, init_func=init)
97+
animation.FuncAnimation(fig, animate, range(1, len(y)),
98+
interval=dt*1000, blit=True, init_func=init)
9999
plt.show()

examples/animation/rain.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,5 +67,5 @@ def update(frame_number):
6767

6868

6969
# Construct the animation, using the update function as the animation director.
70-
animation = FuncAnimation(fig, update, interval=10)
70+
FuncAnimation(fig, update, interval=10)
7171
plt.show()

examples/animation/random_walk.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ def update_lines(num, data_lines, lines):
6868
ax.set_title('3D Test')
6969

7070
# Creating the Animation object
71-
line_ani = animation.FuncAnimation(
71+
animation.FuncAnimation(
7272
fig, update_lines, 25, fargs=(data, lines), interval=50)
7373

7474
plt.show()

examples/animation/strip_chart.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,6 @@ def emitter(p=0.03):
5656
scope = Scope(ax)
5757

5858
# pass a generator in "emitter" to produce data for the update func
59-
ani = animation.FuncAnimation(fig, scope.update, emitter, interval=10,
60-
blit=True)
59+
animation.FuncAnimation(fig, scope.update, emitter, interval=10, blit=True)
6160

6261
plt.show()

examples/animation/unchained.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,5 +69,5 @@ def update(*args):
6969
return lines
7070

7171
# Construct the animation, using the update function as the animation director.
72-
anim = animation.FuncAnimation(fig, update, interval=10)
72+
animation.FuncAnimation(fig, update, interval=10)
7373
plt.show()

lib/matplotlib/animation.py

Lines changed: 6 additions & 3 deletions
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

Lines changed: 11 additions & 39 deletions
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)