2323import six
2424from six .moves import xrange , zip
2525
26+ import numpy as np
2627import os
2728import platform
2829import sys
6263
6364
6465def adjusted_figsize (w , h , dpi , n ):
66+ '''Compute figure size so that pixels are a multiple of n
67+
68+ Parameters
69+ ----------
70+ w, h : float
71+ Size in inches
72+
73+ dpi : float
74+ The dpi
75+
76+ n : int
77+ The target multiple
78+
79+ Returns
80+ -------
81+ wnew, hnew : float
82+ The new figure size in inches.
83+ '''
84+
85+ # this maybe simplified if / when we adopt consistent rounding for
86+ # pixel size across the whole library
87+ def correct_roundoff (x , dpi , n ):
88+ if int (x * dpi ) % n != 0 :
89+ if int (np .nextafter (x , np .inf )* dpi ) % n == 0 :
90+ x = np .nextafter (x , np .inf )
91+ elif int (np .nextafter (x , - np .inf )* dpi ) % n == 0 :
92+ x = np .nextafter (x , - np .inf )
93+ return x
94+
6595 wnew = int (w * dpi / n ) * n / dpi
6696 hnew = int (h * dpi / n ) * n / dpi
67- return wnew , hnew
97+ return ( correct_roundoff ( wnew , dpi , n ), correct_roundoff ( hnew , dpi , n ))
6898
6999
70100# A registry for available MovieWriter classes
@@ -278,8 +308,11 @@ def _adjust_frame_size(self):
278308 verbose .report ('figure size (inches) has been adjusted '
279309 'from %s x %s to %s x %s' % (wo , ho , w , h ),
280310 level = 'helpful' )
311+ else :
312+ w , h = self .fig .get_size_inches ()
281313 verbose .report ('frame size in pixels is %s x %s' % self .frame_size ,
282314 level = 'debug' )
315+ return w , h
283316
284317 def setup (self , fig , outfile , dpi = None ):
285318 '''
@@ -301,7 +334,7 @@ def setup(self, fig, outfile, dpi=None):
301334 if dpi is None :
302335 dpi = self .fig .dpi
303336 self .dpi = dpi
304- self ._adjust_frame_size ()
337+ self ._w , self . _h = self . _adjust_frame_size ()
305338
306339 # Run here so that grab_frame() can write the data to a pipe. This
307340 # eliminates the need for temp files.
@@ -337,6 +370,10 @@ def grab_frame(self, **savefig_kwargs):
337370 verbose .report ('MovieWriter.grab_frame: Grabbing frame.' ,
338371 level = 'debug' )
339372 try :
373+ # re-adjust the figure size in case it has been changed by the
374+ # user. We must ensure that every frame is the same size or
375+ # the movie will not save correctly.
376+ self .fig .set_size_inches (self ._w , self ._h )
340377 # Tell the figure to save its data to the sink, using the
341378 # frame format and dpi.
342379 self .fig .savefig (self ._frame_sink (), format = self .frame_format ,
@@ -386,16 +423,21 @@ def isAvailable(cls):
386423 if not bin_path :
387424 return False
388425 try :
389- p = subprocess .Popen (bin_path ,
390- shell = False ,
391- stdout = subprocess . PIPE ,
392- stderr = subprocess .PIPE ,
393- creationflags = subprocess_creation_flags )
394- p . communicate ( )
395- return True
426+ p = subprocess .Popen (
427+ bin_path ,
428+ shell = False ,
429+ stdout = subprocess .PIPE ,
430+ stderr = subprocess . PIPE ,
431+ creationflags = subprocess_creation_flags )
432+ return cls . _handle_subprocess ( p )
396433 except OSError :
397434 return False
398435
436+ @classmethod
437+ def _handle_subprocess (cls , process ):
438+ process .communicate ()
439+ return True
440+
399441
400442class FileMovieWriter (MovieWriter ):
401443 '''`MovieWriter` for writing to individual files and stitching at the end.
@@ -570,10 +612,18 @@ def output_args(self):
570612
571613 return args + ['-y' , self .outfile ]
572614
615+ @classmethod
616+ def _handle_subprocess (cls , process ):
617+ _ , err = process .communicate ()
618+ # Ubuntu 12.04 ships a broken ffmpeg binary which we shouldn't use
619+ if 'Libav' in err .decode ():
620+ return False
621+ return True
622+
573623
574624# Combine FFMpeg options with pipe-based writing
575625@writers .register ('ffmpeg' )
576- class FFMpegWriter (MovieWriter , FFMpegBase ):
626+ class FFMpegWriter (FFMpegBase , MovieWriter ):
577627 '''Pipe-based ffmpeg writer.
578628
579629 Frames are streamed directly to ffmpeg via a pipe and written in a single
@@ -594,7 +644,7 @@ def _args(self):
594644
595645# Combine FFMpeg options with temp file-based writing
596646@writers .register ('ffmpeg_file' )
597- class FFMpegFileWriter (FileMovieWriter , FFMpegBase ):
647+ class FFMpegFileWriter (FFMpegBase , FileMovieWriter ):
598648 '''File-based ffmpeg writer.
599649
600650 Frames are written to temporary files on disk and then stitched
0 commit comments