Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 017d88b

Browse filesBrowse files
committed
add cache_frame_data kwarg into FuncAnimation. fixes #8528.
1 parent 7c0e760 commit 017d88b
Copy full SHA for 017d88b

File tree

Expand file treeCollapse file tree

2 files changed

+94
-3
lines changed
Filter options
Expand file treeCollapse file tree

2 files changed

+94
-3
lines changed

‎lib/matplotlib/animation.py

Copy file name to clipboardExpand all lines: lib/matplotlib/animation.py
+10-3Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1621,9 +1621,13 @@ def init_func() -> iterable_of_artists:
16211621
However, they will be drawn on top of any previous artists, regardless
16221622
of their zorder. Defaults to ``False``.
16231623
1624+
cache_frame_data : bool, optional
1625+
Controls whether frame data is cached. Defaults to ``True``.
1626+
Disabling cache might be helpful when frames contain large objects.
1627+
16241628
'''
16251629
def __init__(self, fig, func, frames=None, init_func=None, fargs=None,
1626-
save_count=None, **kwargs):
1630+
save_count=None, cache_frame_data=True, **kwargs):
16271631
if fargs:
16281632
self._args = fargs
16291633
else:
@@ -1671,6 +1675,8 @@ def __init__(self, fig, func, frames=None, init_func=None, fargs=None,
16711675
# for a single frame from init, which is not what we want.
16721676
self._save_seq = []
16731677

1678+
self._cache_frame_data = cache_frame_data
1679+
16741680
def new_frame_seq(self):
16751681
# Use the generating function to generate a new frame sequence
16761682
return self._iter_gen()
@@ -1725,8 +1731,9 @@ def _init_draw(self):
17251731
self._save_seq = []
17261732

17271733
def _draw_frame(self, framedata):
1728-
# Save the data for potential saving of movies.
1729-
self._save_seq.append(framedata)
1734+
if self._cache_frame_data:
1735+
# Save the data for potential saving of movies.
1736+
self._save_seq.append(framedata)
17301737

17311738
# Make sure to respect save_count (keep only the last save_count
17321739
# around)

‎lib/matplotlib/tests/test_animation.py

Copy file name to clipboardExpand all lines: lib/matplotlib/tests/test_animation.py
+84Lines changed: 84 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,86 @@ 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_holds_frames_by_default():
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 not None
305+
306+
307+
def test_funcanimation_does_not_hold_frames_when_cache_frame_data_is_False():
308+
fig, ax = plt.subplots()
309+
line, = ax.plot([], [])
310+
311+
class Frame(dict):
312+
# this subclassing enables to use weakref.ref()
313+
pass
314+
315+
def init():
316+
line.set_data([], [])
317+
return line,
318+
319+
def animate(frame):
320+
line.set_data(frame['x'], frame['y'])
321+
return line,
322+
323+
frames_generated = []
324+
325+
def frames_generator():
326+
for _ in range(5):
327+
x = np.linspace(0, 10, 100)
328+
y = np.random.rand(100)
329+
330+
frame = Frame(x=x, y=y)
331+
332+
# collect weak references to frames
333+
# to validate their references later
334+
frames_generated.append(weakref.ref(frame))
335+
336+
yield frame
337+
338+
anim = animation.FuncAnimation(fig, animate, init_func=init,
339+
frames=frames_generator, save_count=5,
340+
cache_frame_data=False)
341+
342+
writer = NullMovieWriter()
343+
anim.save('unused.null', writer=writer)
344+
345+
for f in frames_generated:
346+
assert f() is None

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.