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

Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
``TimedAnimation``/``Animation`` now perform .stop() on mpl_disconnect
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Previously these classes set ``self.event_source = None`` when
``self._fig.canvas.mpl_disconnect`` was called. Now they run
``self.event_source.stop()``.

This hange is for issue `30622 <https://github.com/matplotlib/matplotlib/issues/30622>`__.

The following code snippet would before have returned None but would now return a
``matplotlib.backend_bases.TimerBase``. Code that used None to check for successful
stoppage should be updated.

.. code-block:: python

import matplotlib
matplotlib.use('agg')
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation

fig, ax = plt.subplots()
anim = FuncAnimation(fig, lambda f: [], frames=3, repeat=False)
anim._start()
while anim._step():
pass
print(anim.event_source)
4 changes: 2 additions & 2 deletions lib/matplotlib/animation.py
Original file line number Diff line number Diff line change
Expand Up @@ -946,7 +946,7 @@ def _stop(self, *args):
self._fig.canvas.mpl_disconnect(self._resize_id)
self._fig.canvas.mpl_disconnect(self._close_id)
self.event_source.remove_callback(self._step)
self.event_source = None
self.event_source.stop()

def save(self, filename, writer=None, fps=None, dpi=None, codec=None,
bitrate=None, extra_args=None, metadata=None, extra_anim=None,
Expand Down Expand Up @@ -1483,7 +1483,7 @@ def _step(self, *args):
# Remove the resize callback if we were blitting
self._fig.canvas.mpl_disconnect(self._resize_id)
self._fig.canvas.mpl_disconnect(self._close_id)
self.event_source = None
self.event_source.stop()
return False

self.event_source.interval = self._interval
Expand Down
2 changes: 1 addition & 1 deletion lib/matplotlib/animation.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ class EventSourceProtocol(Protocol):

class Animation:
frame_seq: Iterable[Artist]
event_source: EventSourceProtocol | None # TODO: We should remove None
event_source: EventSourceProtocol
def __init__(
self, fig: Figure, event_source: EventSourceProtocol, blit: bool = ...
) -> None: ...
Expand Down
32 changes: 31 additions & 1 deletion lib/matplotlib/tests/test_animation.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
import matplotlib as mpl
from matplotlib import pyplot as plt
from matplotlib import animation
from matplotlib.animation import PillowWriter
from matplotlib.animation import PillowWriter, FuncAnimation
from matplotlib.testing.decorators import check_figures_equal


Expand Down Expand Up @@ -571,3 +571,33 @@ def test_animation_with_transparency():
# Check that the alpha channel is not 255, so frame has transparency
assert frame.getextrema()[3][0] < 255
plt.close(fig)


def test_event_source_stops_leaves_event():
"""
Added for issue #30622

Tests that animations now stop the event source instead
of destroying it on animation completion.
"""
fig, ax = plt.subplots()
anim = FuncAnimation(fig, lambda f: [], frames=3, repeat=False)
anim._start()
while anim._step():
pass # goes through all 3 steps
assert anim.event_source is not None
plt.close(fig)


def test_event_source_stops_early_leaves_event():
"""
Added for issue #30622

Tests that animations now stop the event source instead
of destroying it on animation early stop.
"""
fig, ax = plt.subplots()
anim = FuncAnimation(fig, lambda f: [], frames=3)
anim._start()
plt.close(fig)
assert anim.event_source is not None
Loading