|
33 | 33 | except ImportError:
|
34 | 34 | # python2
|
35 | 35 | from base64 import encodestring as encodebytes
|
| 36 | +import abc |
36 | 37 | import contextlib
|
37 | 38 | import tempfile
|
38 | 39 | from matplotlib.cbook import iterable, is_string_like
|
@@ -91,17 +92,76 @@ def __getitem__(self, name):
|
91 | 92 | writers = MovieWriterRegistry()
|
92 | 93 |
|
93 | 94 |
|
94 |
| -class MovieWriter(object): |
| 95 | +class AbstractMovieWriter(six.with_metaclass(abc.ABCMeta)): |
| 96 | + ''' |
| 97 | + Abstract base class for writing movies. Fundamentally, what a MovieWriter |
| 98 | + does is provide is a way to grab frames by calling grab_frame(). |
| 99 | +
|
| 100 | + setup() is called to start the process and finish() is called afterwards. |
| 101 | +
|
| 102 | + This class is set up to provide for writing movie frame data to a pipe. |
| 103 | + saving() is provided as a context manager to facilitate this process as:: |
| 104 | +
|
| 105 | + with moviewriter.saving(fig, outfile='myfile.mp4', dpi=100): |
| 106 | + # Iterate over frames |
| 107 | + moviewriter.grab_frame(**savefig_kwargs) |
| 108 | +
|
| 109 | + The use of the context manager ensures that setup() and finish() are |
| 110 | + performed as necessary. |
| 111 | +
|
| 112 | + An instance of a concrete subclass of this class can be given as the |
| 113 | + `writer` argument of `Animation.save()`. |
| 114 | + ''' |
| 115 | + |
| 116 | + @abc.abstractmethod |
| 117 | + def setup(self, fig, outfile, dpi, *args): |
| 118 | + ''' |
| 119 | + Perform setup for writing the movie file. |
| 120 | +
|
| 121 | + fig: `matplotlib.Figure` instance |
| 122 | + The figure object that contains the information for frames |
| 123 | + outfile: string |
| 124 | + The filename of the resulting movie file |
| 125 | + dpi: int |
| 126 | + The DPI (or resolution) for the file. This controls the size |
| 127 | + in pixels of the resulting movie file. |
| 128 | + ''' |
| 129 | + |
| 130 | + @abc.abstractmethod |
| 131 | + def grab_frame(self, **savefig_kwargs): |
| 132 | + ''' |
| 133 | + Grab the image information from the figure and save as a movie frame. |
| 134 | + All keyword arguments in savefig_kwargs are passed on to the 'savefig' |
| 135 | + command that saves the figure. |
| 136 | + ''' |
| 137 | + |
| 138 | + @abc.abstractmethod |
| 139 | + def finish(self): |
| 140 | + 'Finish any processing for writing the movie.' |
| 141 | + |
| 142 | + @contextlib.contextmanager |
| 143 | + def saving(self, fig, outfile, dpi, *args): |
| 144 | + ''' |
| 145 | + Context manager to facilitate writing the movie file. |
| 146 | +
|
| 147 | + All arguments are passed on to `setup`. |
| 148 | + ''' |
| 149 | + self.setup(fig, outfile, dpi, *args) |
| 150 | + yield |
| 151 | + self.finish() |
| 152 | + |
| 153 | + |
| 154 | +class MovieWriter(AbstractMovieWriter): |
95 | 155 | '''
|
96 | 156 | Base class for writing movies. Fundamentally, what a MovieWriter does
|
97 | 157 | is provide is a way to grab frames by calling grab_frame(). setup()
|
98 | 158 | is called to start the process and finish() is called afterwards.
|
99 | 159 | This class is set up to provide for writing movie frame data to a pipe.
|
100 | 160 | saving() is provided as a context manager to facilitate this process as::
|
101 | 161 |
|
102 |
| - with moviewriter.saving('myfile.mp4'): |
| 162 | + with moviewriter.saving(fig, outfile='myfile.mp4', dpi=100): |
103 | 163 | # Iterate over frames
|
104 |
| - moviewriter.grab_frame() |
| 164 | + moviewriter.grab_frame(**savefig_kwargs) |
105 | 165 |
|
106 | 166 | The use of the context manager ensures that setup and cleanup are
|
107 | 167 | performed as necessary.
|
@@ -183,18 +243,6 @@ def setup(self, fig, outfile, dpi, *args):
|
183 | 243 | # eliminates the need for temp files.
|
184 | 244 | self._run()
|
185 | 245 |
|
186 |
| - @contextlib.contextmanager |
187 |
| - def saving(self, *args): |
188 |
| - ''' |
189 |
| - Context manager to facilitate writing the movie file. |
190 |
| -
|
191 |
| - ``*args`` are any parameters that should be passed to `setup`. |
192 |
| - ''' |
193 |
| - # This particular sequence is what contextlib.contextmanager wants |
194 |
| - self.setup(*args) |
195 |
| - yield |
196 |
| - self.finish() |
197 |
| - |
198 | 246 | def _run(self):
|
199 | 247 | # Uses subprocess to call the program for assembling frames into a
|
200 | 248 | # movie file. *args* returns the sequence of command line arguments
|
@@ -669,10 +717,10 @@ def save(self, filename, writer=None, fps=None, dpi=None, codec=None,
|
669 | 717 |
|
670 | 718 | *filename* is the output filename, e.g., :file:`mymovie.mp4`
|
671 | 719 |
|
672 |
| - *writer* is either an instance of :class:`MovieWriter` or a string |
673 |
| - key that identifies a class to use, such as 'ffmpeg' or 'mencoder'. |
674 |
| - If nothing is passed, the value of the rcparam `animation.writer` is |
675 |
| - used. |
| 720 | + *writer* is either an instance of :class:`AbstractMovieWriter` or |
| 721 | + a string key that identifies a class to use, such as 'ffmpeg' or |
| 722 | + 'mencoder'. If nothing is passed, the value of the rcparam |
| 723 | + `animation.writer` is used. |
676 | 724 |
|
677 | 725 | *fps* is the frames per second in the movie. Defaults to None,
|
678 | 726 | which will use the animation's specified interval to set the frames
|
|
0 commit comments