From e59706fdf9f78cd2df5ff059059dbca15ecefbc4 Mon Sep 17 00:00:00 2001 From: Anselm Hahn Date: Sat, 25 Jan 2025 18:14:44 +0100 Subject: [PATCH 1/3] FIX: Correct variable name from _frame to _frames in PillowWriter class --- lib/matplotlib/animation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/matplotlib/animation.py b/lib/matplotlib/animation.py index 2be61284073a..a87f00201124 100644 --- a/lib/matplotlib/animation.py +++ b/lib/matplotlib/animation.py @@ -496,7 +496,7 @@ def grab_frame(self, **savefig_kwargs): "RGBA", self.frame_size, buf.getbuffer(), "raw", "RGBA", 0, 1) if im.getextrema()[3][0] < 255: # This frame has transparency, so we'll just add it as is. - self._frame.append(im) + self._frames.append(im) else: # Without transparency, we switch to RGB mode, which converts to P mode a # little better if needed (specifically, this helps with GIF output.) From d9193dfad9f44ea67e4961fd3bfb1e8f1c38fcaf Mon Sep 17 00:00:00 2001 From: Anselm Hahn Date: Sun, 26 Jan 2025 14:23:52 +0000 Subject: [PATCH 2/3] test: Add test for animation with transparency and exhausted warning --- lib/matplotlib/tests/test_animation.py | 28 ++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/lib/matplotlib/tests/test_animation.py b/lib/matplotlib/tests/test_animation.py index a2b35f802c78..5261656907bd 100644 --- a/lib/matplotlib/tests/test_animation.py +++ b/lib/matplotlib/tests/test_animation.py @@ -526,3 +526,31 @@ def test_movie_writer_invalid_path(anim): with pytest.raises(FileNotFoundError, match=match_str): anim.save("/foo/bar/aardvark/thiscannotreallyexist.mp4", writer=animation.FFMpegFileWriter()) + + +def test_exhausted_animation_with_transparency(tmp_path): + fig, ax = plt.subplots() + rect = plt.Rectangle((0, 0), 1, 1, color='red', alpha=0.5) + ax.add_patch(rect) + ax.set_xlim(0, 1) + ax.set_ylim(0, 1) + + def update(frame): + # Modify transparency in each frame + rect.set_alpha(0.1 + frame * 0.1) + return [rect] + + # Create and save animation + anim = animation.FuncAnimation( + fig, update, frames=iter(range(5)), repeat=False, + cache_frame_data=False, + + ) + tmp_file = tmp_path / "test_transparent.gif" + anim.save(tmp_file, writer='pillow', savefig_kwargs={"transparent": True}) + + # Verify exhausted warning + with pytest.warns(UserWarning, match="exhausted"): + anim._start() + + plt.close(fig) From 0be53be37ed6c448939b4de837dab5ce450acc35 Mon Sep 17 00:00:00 2001 From: Anselm Hahn Date: Mon, 27 Jan 2025 20:20:33 +0000 Subject: [PATCH 3/3] TEST: Update animation test to use PillowWriter for transparency handling --- lib/matplotlib/tests/test_animation.py | 28 +++++++++----------------- 1 file changed, 9 insertions(+), 19 deletions(-) diff --git a/lib/matplotlib/tests/test_animation.py b/lib/matplotlib/tests/test_animation.py index 5261656907bd..0b5aeaaec889 100644 --- a/lib/matplotlib/tests/test_animation.py +++ b/lib/matplotlib/tests/test_animation.py @@ -13,6 +13,7 @@ import matplotlib as mpl from matplotlib import pyplot as plt from matplotlib import animation +from matplotlib.animation import PillowWriter from matplotlib.testing.decorators import check_figures_equal @@ -528,29 +529,18 @@ def test_movie_writer_invalid_path(anim): writer=animation.FFMpegFileWriter()) -def test_exhausted_animation_with_transparency(tmp_path): +def test_animation_with_transparency(): + """Test animation exhaustion with transparency using PillowWriter directly""" fig, ax = plt.subplots() rect = plt.Rectangle((0, 0), 1, 1, color='red', alpha=0.5) ax.add_patch(rect) ax.set_xlim(0, 1) ax.set_ylim(0, 1) - def update(frame): - # Modify transparency in each frame - rect.set_alpha(0.1 + frame * 0.1) - return [rect] - - # Create and save animation - anim = animation.FuncAnimation( - fig, update, frames=iter(range(5)), repeat=False, - cache_frame_data=False, - - ) - tmp_file = tmp_path / "test_transparent.gif" - anim.save(tmp_file, writer='pillow', savefig_kwargs={"transparent": True}) - - # Verify exhausted warning - with pytest.warns(UserWarning, match="exhausted"): - anim._start() - + writer = PillowWriter(fps=30) + writer.setup(fig, 'unused.gif', dpi=100) + writer.grab_frame(transparent=True) + frame = writer._frames[-1] + # Check that the alpha channel is not 255, so frame has transparency + assert frame.getextrema()[3][0] < 255 plt.close(fig)