From 7d1f71791fbee330d377d8ef42b6cb8d79bd1f3d Mon Sep 17 00:00:00 2001 From: Ryan May Date: Tue, 17 May 2016 11:05:30 -0600 Subject: [PATCH 1/4] MNT: Raise an error for invalid args in animation.save. When passed arguments that are only used when creating a new MovieWriter instance, raise an error if writer is an existing instance rather than silently ignoring the arguments. Also document the fact that these arguments are invalid in that case. --- lib/matplotlib/animation.py | 36 ++++++++++++++++++++++++++---------- 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/lib/matplotlib/animation.py b/lib/matplotlib/animation.py index b45d3ca3561a..256d31bb808b 100644 --- a/lib/matplotlib/animation.py +++ b/lib/matplotlib/animation.py @@ -686,28 +686,35 @@ def save(self, filename, writer=None, fps=None, dpi=None, codec=None, *fps* is the frames per second in the movie. Defaults to None, which will use the animation's specified interval to set the frames - per second. + per second. This argument is only valid if *writer* is not a + :class:`MovieWriter` instance. *dpi* controls the dots per inch for the movie frames. This combined with the figure's size in inches controls the size of the movie. *codec* is the video codec to be used. Not all codecs are supported by a given :class:`MovieWriter`. If none is given, this defaults to the - value specified by the rcparam `animation.codec`. + value specified by the rcparam `animation.codec`. This argument is only + valid if *writer* is not a :class:`MovieWriter` instance. *bitrate* specifies the amount of bits used per second in the compressed movie, in kilobits per second. A higher number means a higher quality movie, but at the cost of increased file size. If no value is given, this defaults to the value given by the rcparam - `animation.bitrate`. + `animation.bitrate`. This argument is only valid if *writer* is not a + :class:`MovieWriter` instance. *extra_args* is a list of extra string arguments to be passed to the underlying movie utility. The default is None, which passes the - additional arguments in the 'animation.extra_args' rcParam. + additional arguments in the 'animation.extra_args' rcParam. This + argument is only valid if *writer* is not a :class:`MovieWriter` + instance. *metadata* is a dictionary of keys and values for metadata to include in the output file. Some keys that may be of use include: - title, artist, genre, subject, copyright, srcform, comment. + title, artist, genre, subject, copyright, srcform, comment. This + argument is only valid if *writer* is not a :class:`MovieWriter` + instance. *extra_anim* is a list of additional `Animation` objects that should be included in the saved movie file. These need to be from the same @@ -720,6 +727,20 @@ def save(self, filename, writer=None, fps=None, dpi=None, codec=None, the individual frames. This can be used to set tight bounding boxes, for example. ''' + # If the writer is None, use the rc param to find the name of the one + # to use + if writer is None: + writer = rcParams['animation.writer'] + elif (not is_string_like(writer) and + any(arg is not None + for arg in (fps, codec, bitrate, extra_args, metadata))): + raise RuntimeError('Passing in values for arguments for arguments ' + 'fps, codec, bitrate, extra_args, or metadata ' + 'is not supported when writer is an existing ' + 'MovieWriter instance. These should instead be ' + 'passed as arguments when creating the ' + 'MovieWriter instance.') + if savefig_kwargs is None: savefig_kwargs = {} @@ -735,11 +756,6 @@ def save(self, filename, writer=None, fps=None, dpi=None, codec=None, # Convert interval in ms to frames per second fps = 1000. / self._interval - # If the writer is None, use the rc param to find the name of the one - # to use - if writer is None: - writer = rcParams['animation.writer'] - # Re-use the savefig DPI for ours if none is given if dpi is None: dpi = rcParams['savefig.dpi'] From ecfc1e724173e2ac7bb8e3d1fe9a368e976b3df5 Mon Sep 17 00:00:00 2001 From: Ryan May Date: Tue, 17 May 2016 11:07:15 -0600 Subject: [PATCH 2/4] MNT: Improve error message when saving animation fails. --- lib/matplotlib/animation.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/matplotlib/animation.py b/lib/matplotlib/animation.py index 256d31bb808b..6a9232f1d834 100644 --- a/lib/matplotlib/animation.py +++ b/lib/matplotlib/animation.py @@ -234,12 +234,14 @@ def grab_frame(self, **savefig_kwargs): # frame format and dpi. self.fig.savefig(self._frame_sink(), format=self.frame_format, dpi=self.dpi, **savefig_kwargs) - except RuntimeError: + except (RuntimeError, IOError): out, err = self._proc.communicate() verbose.report('MovieWriter -- Error ' 'running proc:\n%s\n%s' % (out, err), level='helpful') - raise + raise IOError('Error saving animation to file. ' + 'Stdout: {0} StdError: {1}. It may help to re-run ' + 'with --verbose-debug.'.format(out, err)) def _frame_sink(self): 'Returns the place to which frames should be written.' From 5e5999f8a3b26a8d34d7cb69d5ab5b697af3c7a1 Mon Sep 17 00:00:00 2001 From: Ryan May Date: Tue, 17 May 2016 13:10:11 -0600 Subject: [PATCH 3/4] MNT: Add original exception to raised IOError. --- lib/matplotlib/animation.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/matplotlib/animation.py b/lib/matplotlib/animation.py index 6a9232f1d834..52cafea7fc0f 100644 --- a/lib/matplotlib/animation.py +++ b/lib/matplotlib/animation.py @@ -234,14 +234,14 @@ def grab_frame(self, **savefig_kwargs): # frame format and dpi. self.fig.savefig(self._frame_sink(), format=self.frame_format, dpi=self.dpi, **savefig_kwargs) - except (RuntimeError, IOError): + except (RuntimeError, IOError) as e: out, err = self._proc.communicate() verbose.report('MovieWriter -- Error ' 'running proc:\n%s\n%s' % (out, err), level='helpful') - raise IOError('Error saving animation to file. ' - 'Stdout: {0} StdError: {1}. It may help to re-run ' - 'with --verbose-debug.'.format(out, err)) + raise IOError('Error saving animation to file (cause: {0}) ' + 'Stdout: {1} StdError: {2}. It may help to re-run ' + 'with --verbose-debug.'.format(e, out, err)) def _frame_sink(self): 'Returns the place to which frames should be written.' From 7c98a9886e5be6186edcfb701e761776a6f7d40f Mon Sep 17 00:00:00 2001 From: Ryan May Date: Tue, 17 May 2016 13:10:41 -0600 Subject: [PATCH 4/4] MNT: Re-arrange docs to avoid repeating save verbiage. --- lib/matplotlib/animation.py | 49 +++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 26 deletions(-) diff --git a/lib/matplotlib/animation.py b/lib/matplotlib/animation.py index 52cafea7fc0f..a86871fe255d 100644 --- a/lib/matplotlib/animation.py +++ b/lib/matplotlib/animation.py @@ -686,48 +686,45 @@ def save(self, filename, writer=None, fps=None, dpi=None, codec=None, If nothing is passed, the value of the rcparam `animation.writer` is used. - *fps* is the frames per second in the movie. Defaults to None, - which will use the animation's specified interval to set the frames - per second. This argument is only valid if *writer* is not a - :class:`MovieWriter` instance. - *dpi* controls the dots per inch for the movie frames. This combined with the figure's size in inches controls the size of the movie. + *savefig_kwargs* is a dictionary containing keyword arguments to be + passed on to the 'savefig' command which is called repeatedly to save + the individual frames. This can be used to set tight bounding boxes, + for example. + + *extra_anim* is a list of additional `Animation` objects that should + be included in the saved movie file. These need to be from the same + `matplotlib.Figure` instance. Also, animation frames will just be + simply combined, so there should be a 1:1 correspondence between + the frames from the different animations. + + These remaining arguments are used to construct a :class:`MovieWriter` + instance when necessary and are only considered valid if *writer* is + not a :class:`MovieWriter` instance. + + *fps* is the frames per second in the movie. Defaults to None, + which will use the animation's specified interval to set the frames + per second. + *codec* is the video codec to be used. Not all codecs are supported by a given :class:`MovieWriter`. If none is given, this defaults to the - value specified by the rcparam `animation.codec`. This argument is only - valid if *writer* is not a :class:`MovieWriter` instance. + value specified by the rcparam `animation.codec`. *bitrate* specifies the amount of bits used per second in the compressed movie, in kilobits per second. A higher number means a higher quality movie, but at the cost of increased file size. If no value is given, this defaults to the value given by the rcparam - `animation.bitrate`. This argument is only valid if *writer* is not a - :class:`MovieWriter` instance. + `animation.bitrate`. *extra_args* is a list of extra string arguments to be passed to the underlying movie utility. The default is None, which passes the - additional arguments in the 'animation.extra_args' rcParam. This - argument is only valid if *writer* is not a :class:`MovieWriter` - instance. + additional arguments in the 'animation.extra_args' rcParam. *metadata* is a dictionary of keys and values for metadata to include in the output file. Some keys that may be of use include: - title, artist, genre, subject, copyright, srcform, comment. This - argument is only valid if *writer* is not a :class:`MovieWriter` - instance. - - *extra_anim* is a list of additional `Animation` objects that should - be included in the saved movie file. These need to be from the same - `matplotlib.Figure` instance. Also, animation frames will just be - simply combined, so there should be a 1:1 correspondence between - the frames from the different animations. - - *savefig_kwargs* is a dictionary containing keyword arguments to be - passed on to the 'savefig' command which is called repeatedly to save - the individual frames. This can be used to set tight bounding boxes, - for example. + title, artist, genre, subject, copyright, srcform, comment. ''' # If the writer is None, use the rc param to find the name of the one # to use