-
-
Notifications
You must be signed in to change notification settings - Fork 8k
Description
Current PillowWriter functionality does not allow me to specify the duration for each of the gif frames and it is not possible to not have the gif loop.
Additionally, I frequently get a ValueError: buffer is not large enough when animating multi axes figures. (Not sure if this is a common problem).
Animation to help introduce a visual story can be quite beneficial to understanding and for that I would like to be able to not loop the gif and "pause" the gif via different durations for all frames.
Proposed Solution
-
add duration=None, loop=0 arguments to setup() and to a PillowWriter specific saving context_manager.
To not loop we can specify loop=None and then we specifically need to not pass the loop argument to save() in finish(). -
What is the difference between Image.frombuffer and Image.open(buf)? I find that Image.open(buf) solves my problem of the ValueError: buffer is not large enough.
It seems to take more time for me though. (about +33%) -
removed unused variable assignment: renderer = self.fig.canvas.get_renderer() from grab_frame()
class PillowWriter(AbstractMovieWriter):
@classmethod
def isAvailable(cls):
return True
def setup(self, fig, outfile, dpi=None, duration=None, loop=None):
super().setup(fig, outfile, dpi=dpi)
self.duration = duration
self.loop = loop
self._frames = []
def grab_frame(self, **savefig_kwargs):
buf = BytesIO()
self.fig.savefig(
buf, **{**savefig_kwargs, "dpi": self.dpi})
self._frames.append(Image.open(buf))
def finish(self):
duration = self.duration or int(1000 / self.fps)
# to not loop at all we need to avoid passing the loop argument to save
if self.loop is None:
self._frames[0].save(
self.outfile, save_all=True, append_images=self._frames[1:],
duration=duration)
else:
self._frames[0].save(
self.outfile, save_all=True, append_images=self._frames[1:],
duration=duration, loop=self.loop)
@contextlib.contextmanager
def saving(self, fig, outfile, dpi, duration=None, loop=0, *args, **kwargs):
"""
Context manager to facilitate writing the movie file.
``*args, **kw`` are any parameters that should be passed to `setup`.
"""
# This particular sequence is what contextlib.contextmanager wants
self.setup(fig, outfile, dpi, duration, loop, *args, **kwargs)
try:
yield self
finally:
self.finish()
Additional context and prior art
endless looping for gifs was introduced here:
#11789
Documentation would have to be updated I suppose.
If this seems like a useful improvement to the PillowWriter I could go ahead and create a PR.