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

Skip to content

Commit 6254645

Browse files
committed
remove unused '_save_seq' data attribute in 'FuncAnimation' class. fixes #8528.
1 parent e5d5d40 commit 6254645

File tree

2 files changed

+61
-42
lines changed

2 files changed

+61
-42
lines changed

lib/matplotlib/animation.py

Lines changed: 19 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1661,49 +1661,34 @@ def __init__(self, fig, func, frames=None, init_func=None, fargs=None,
16611661

16621662
self._init_func = init_func
16631663

1664-
# Needs to be initialized so the draw functions work without checking
1665-
self._save_seq = []
1666-
16671664
TimedAnimation.__init__(self, fig, **kwargs)
16681665

1669-
# Need to reset the saved seq, since right now it will contain data
1670-
# for a single frame from init, which is not what we want.
1671-
self._save_seq = []
1672-
16731666
def new_frame_seq(self):
16741667
# Use the generating function to generate a new frame sequence
16751668
return self._iter_gen()
16761669

16771670
def new_saved_frame_seq(self):
1678-
# Generate an iterator for the sequence of saved data. If there are
1679-
# no saved frames, generate a new frame sequence and take the first
1680-
# save_count entries in it.
1681-
if self._save_seq:
1682-
# While iterating we are going to update _save_seq
1683-
# so make a copy to safely iterate over
1684-
self._old_saved_seq = list(self._save_seq)
1685-
return iter(self._old_saved_seq)
1671+
# Generate a new frame sequence
1672+
# and take the first save_count entries in it.
1673+
if self.save_count is not None:
1674+
return itertools.islice(self.new_frame_seq(), self.save_count)
16861675
else:
1687-
if self.save_count is not None:
1688-
return itertools.islice(self.new_frame_seq(), self.save_count)
1676+
frame_seq = self.new_frame_seq()
16891677

1690-
else:
1691-
frame_seq = self.new_frame_seq()
1692-
1693-
def gen():
1694-
try:
1695-
for _ in range(100):
1696-
yield next(frame_seq)
1697-
except StopIteration:
1698-
pass
1699-
else:
1700-
cbook.warn_deprecated(
1701-
"2.2", "FuncAnimation.save has truncated your "
1702-
"animation to 100 frames. In the future, no such "
1703-
"truncation will occur; please pass 'save_count' "
1704-
"accordingly.")
1705-
1706-
return gen()
1678+
def gen():
1679+
try:
1680+
for _ in range(100):
1681+
yield next(frame_seq)
1682+
except StopIteration:
1683+
pass
1684+
else:
1685+
cbook.warn_deprecated(
1686+
"2.2", "FuncAnimation.save has truncated your "
1687+
"animation to 100 frames. In the future, no such "
1688+
"truncation will occur; please pass 'save_count' "
1689+
"accordingly.")
1690+
1691+
return gen()
17071692

17081693
def _init_draw(self):
17091694
# Initialize the drawing either using the given init_func or by
@@ -1721,16 +1706,8 @@ def _init_draw(self):
17211706
'sequence of Artist objects.')
17221707
for a in self._drawn_artists:
17231708
a.set_animated(self._blit)
1724-
self._save_seq = []
17251709

17261710
def _draw_frame(self, framedata):
1727-
# Save the data for potential saving of movies.
1728-
self._save_seq.append(framedata)
1729-
1730-
# Make sure to respect save_count (keep only the last save_count
1731-
# around)
1732-
self._save_seq = self._save_seq[-self.save_count:]
1733-
17341711
# Call the func with framedata and args. If blitting is desired,
17351712
# func needs to return a sequence of any artists that were modified.
17361713
self._drawn_artists = self._func(framedata, *self._args)

lib/matplotlib/tests/test_animation.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import os
22
from pathlib import Path
33
import sys
4+
import weakref
45

56
import numpy as np
67
import pytest
@@ -260,3 +261,44 @@ def test_failing_ffmpeg(tmpdir, monkeypatch):
260261
make_animation().save("test.mpeg")
261262
finally:
262263
animation.writers.reset_available_writers()
264+
265+
266+
def test_funcanimation_does_not_hold_references_to_frames():
267+
fig, ax = plt.subplots()
268+
line, = ax.plot([], [])
269+
270+
class Frame(dict):
271+
# this subclassing enables to use weakref.ref()
272+
pass
273+
274+
def init():
275+
line.set_data([], [])
276+
return line,
277+
278+
def animate(frame):
279+
line.set_data(frame['x'], frame['y'])
280+
return line,
281+
282+
frames_generated = []
283+
284+
def frames_generator():
285+
for _ in range(5):
286+
x = np.linspace(0, 10, 100)
287+
y = np.random.rand(100)
288+
289+
frame = Frame(x=x, y=y)
290+
291+
# collect weak references to frames
292+
# to validate their references later
293+
frames_generated.append(weakref.ref(frame))
294+
295+
yield frame
296+
297+
anim = animation.FuncAnimation(fig, animate, init_func=init,
298+
frames=frames_generator, save_count=5)
299+
300+
writer = NullMovieWriter()
301+
anim.save('unused.null', writer=writer)
302+
303+
for f in frames_generated:
304+
assert f() is None

0 commit comments

Comments
 (0)