From a264c0fb0b42b59efce1957f31c414015731ebed Mon Sep 17 00:00:00 2001 From: Antony Lee Date: Thu, 5 Nov 2020 21:16:45 +0100 Subject: [PATCH] Simplify repeat_delay and fix support for it when using iterable frames. - Simplify the implementation of `repeat_delay`: instead of switching callbacks back and forth, just set the timer interval at each iteration to either the normal delay or the end-of-loop delay. - Fix support for `repeat_delay` when `frames` is an iterable: the previous implementation handled looping in `iter_frames` and therefore `_step` never saw the end of the iterable. Instead, just iterate through `frames` once in `iter_frames`, but still `tee` the iterable so that `_step` can take care of repeating the animation. Can be checked with ```python import matplotlib.pyplot as plt import matplotlib.animation as animation fig, ax = plt.subplots() line, = ax.plot(range(10)) def animate(i): line.set_ydata(range(i, i + 10)) # update the data. return line, ani = animation.FuncAnimation( fig, animate, frames=range(5), interval=1000, repeat_delay=2000, blit=True, save_count=50) plt.show() ``` Previously repeat_delay would not be applied. --- lib/matplotlib/animation.py | 23 ++++------------------- 1 file changed, 4 insertions(+), 19 deletions(-) diff --git a/lib/matplotlib/animation.py b/lib/matplotlib/animation.py index 4edeb05ae4bc..995728ff21fa 100644 --- a/lib/matplotlib/animation.py +++ b/lib/matplotlib/animation.py @@ -1433,27 +1433,12 @@ def _step(self, *args): if not still_going and self.repeat: self._init_draw() self.frame_seq = self.new_frame_seq() - self.event_source.remove_callback(self._step) - self.event_source.add_callback(self._loop_delay) self.event_source.interval = self._repeat_delay return True else: + self.event_source.interval = self._interval return still_going - def _stop(self, *args): - # If we stop in the middle of a loop delay (which is relatively likely - # given the potential pause here), remove the loop_delay callback as - # well. - self.event_source.remove_callback(self._loop_delay) - super()._stop() - - def _loop_delay(self, *args): - # Reset the interval and change callbacks after the delay. - self.event_source.remove_callback(self._loop_delay) - self.event_source.interval = self._interval - self.event_source.add_callback(self._step) - Animation._step(self) - class ArtistAnimation(TimedAnimation): """ @@ -1633,10 +1618,10 @@ def __init__(self, fig, func, frames=None, init_func=None, fargs=None, self._iter_gen = frames elif np.iterable(frames): if kwargs.get('repeat', True): + self._tee_from = frames def iter_frames(frames=frames): - while True: - this, frames = itertools.tee(frames, 2) - yield from this + this, self._tee_from = itertools.tee(self._tee_from, 2) + yield from this self._iter_gen = iter_frames else: self._iter_gen = lambda: iter(frames)