Source code for dantro.plot.utils._file_writer

"""This module implements custom matplotlib movie writers; basically, these
are specializations of :py:class:`matplotlib.animation.AbstractMovieWriter`."""

import os

import matplotlib as mpl
import matplotlib.animation
import matplotlib.figure

# -----------------------------------------------------------------------------


[docs]@mpl.animation.writers.register("frames") class FileWriter(mpl.animation.AbstractMovieWriter): """A specialization of :py:class:`matplotlib.animation.AbstractMovieWriter` that writes each frame to a file. It is registered as the ``frames`` writer. """
[docs] def __init__( self, *, name_padding: int = 7, fstr: str = "{dir:}/{num:0{pad:}d}.{ext:}", ): """ Initialize the FileWriter, which adheres to the :py:mod:`matplotlib.animation` interface and can be used to write each frame of an animation to individual files. Args: name_padding (int, optional): How wide the numbering should be fstr (str, optional): The format string to generate the name """ self.cntr = 0 self.name_padding = name_padding self.fstr = fstr # Other attributes that are to be determined later self.fig = None self.out_dir = None self.dpi = None self.format = None
[docs] def setup(self): """Called when entering the saving context""" pass
[docs] def finish(self): """Called when finished""" pass
[docs] @classmethod def isAvailable(cls) -> bool: """Always available.""" return True
[docs] def saving( self, fig: mpl.figure.Figure, base_outfile: str, dpi: int = None, **setup_kwargs, ): """Create an instance of the context manager Args: fig (matplotlib.figure.Figure): The figure object to save base_outfile (str): The path this movie writer would store a movie file at; the file name will be interpreted as the name of the directory that the frames are saved to; the file extension is retained. dpi (int, optional): The desired densiy **setup_kwargs: Passed to setup method Returns: FileWriter: this object, which also is a context manager. """ # Parse the given base file path to get a directory and extension out_dir, ext = os.path.splitext(base_outfile) self.format = ext[1:] # includes leading dot # Store all required objects self.fig = fig self.dpi = dpi if dpi is not None else self.fig.dpi self.out_dir = out_dir # Now, call the setup function self.setup(**setup_kwargs) # As this writer is itself a context manager, return self return self
[docs] def grab_frame(self, **savefig_kwargs): """Stores a single frame""" # Build the output path from the info of the context manager outfile = self.fstr.format( dir=self.out_dir, num=self.cntr, pad=self.name_padding, ext=self.format, ) # Save the frame using the context manager, then increment the cntr self.fig.savefig( outfile, dpi=self.dpi, format=self.format, **savefig_kwargs, ) self.cntr += 1
# .. Context manager magic methods ........................................
[docs] def __enter__(self): """Called when entering context. Makes sure that the output directory exists. """ os.makedirs(self.out_dir, exist_ok=True)
[docs] def __exit__(self, *args): """Called when exiting context. Closes the figure. """ import matplotlib.pyplot as plt plt.close(self.fig)