2323import six
2424from six .moves import xrange , zip
2525
26+ import numpy as np
2627import os
2728import platform
2829import sys
6162
6263
6364def adjusted_figsize (w , h , dpi , n ):
65+ '''Compute figure size so that pixels are a multiple of n
66+
67+ Parameters
68+ ----------
69+ w, h : float
70+ Size in inches
71+
72+ dpi : float
73+ The dpi
74+
75+ n : int
76+ The target multiple
77+
78+ Returns
79+ -------
80+ wnew, hnew : float
81+ The new figure size in inches.
82+ '''
83+
84+ # this maybe simplified if / when we adopt consistent rounding for
85+ # pixel size across the whole library
86+ def correct_roundoff (x , dpi , n ):
87+ if int (x * dpi ) % n != 0 :
88+ if int (np .nextafter (x , np .inf )* dpi ) % n == 0 :
89+ x = np .nextafter (x , np .inf )
90+ elif int (np .nextafter (x , - np .inf )* dpi ) % n == 0 :
91+ x = np .nextafter (x , - np .inf )
92+ return x
93+
6494 wnew = int (w * dpi / n ) * n / dpi
6595 hnew = int (h * dpi / n ) * n / dpi
66- return wnew , hnew
96+ return ( correct_roundoff ( wnew , dpi , n ), correct_roundoff ( hnew , dpi , n ))
6797
6898
6999# A registry for available MovieWriter classes
@@ -214,8 +244,11 @@ def _adjust_frame_size(self):
214244 verbose .report ('figure size (inches) has been adjusted '
215245 'from %s x %s to %s x %s' % (wo , ho , w , h ),
216246 level = 'helpful' )
247+ else :
248+ w , h = self .fig .get_size_inches ()
217249 verbose .report ('frame size in pixels is %s x %s' % self .frame_size ,
218250 level = 'debug' )
251+ return w , h
219252
220253 def setup (self , fig , outfile , dpi ):
221254 '''
@@ -235,7 +268,7 @@ def setup(self, fig, outfile, dpi):
235268 self .outfile = outfile
236269 self .fig = fig
237270 self .dpi = dpi
238- self ._adjust_frame_size ()
271+ self ._w , self . _h = self . _adjust_frame_size ()
239272
240273 # Run here so that grab_frame() can write the data to a pipe. This
241274 # eliminates the need for temp files.
@@ -285,6 +318,10 @@ def grab_frame(self, **savefig_kwargs):
285318 verbose .report ('MovieWriter.grab_frame: Grabbing frame.' ,
286319 level = 'debug' )
287320 try :
321+ # re-adjust the figure size in case it has been changed by the
322+ # user. We must ensure that every frame is the same size or
323+ # the movie will not save correctly.
324+ self .fig .set_size_inches (self ._w , self ._h )
288325 # Tell the figure to save its data to the sink, using the
289326 # frame format and dpi.
290327 self .fig .savefig (self ._frame_sink (), format = self .frame_format ,
@@ -334,16 +371,21 @@ def isAvailable(cls):
334371 if not bin_path :
335372 return False
336373 try :
337- p = subprocess .Popen (bin_path ,
338- shell = False ,
339- stdout = subprocess . PIPE ,
340- stderr = subprocess .PIPE ,
341- creationflags = subprocess_creation_flags )
342- p . communicate ( )
343- return True
374+ p = subprocess .Popen (
375+ bin_path ,
376+ shell = False ,
377+ stdout = subprocess .PIPE ,
378+ stderr = subprocess . PIPE ,
379+ creationflags = subprocess_creation_flags )
380+ return cls . _handle_subprocess ( p )
344381 except OSError :
345382 return False
346383
384+ @classmethod
385+ def _handle_subprocess (cls , process ):
386+ process .communicate ()
387+ return True
388+
347389
348390class FileMovieWriter (MovieWriter ):
349391 '''`MovieWriter` for writing to individual files and stitching at the end.
@@ -514,10 +556,18 @@ def output_args(self):
514556
515557 return args + ['-y' , self .outfile ]
516558
559+ @classmethod
560+ def _handle_subprocess (cls , process ):
561+ _ , err = process .communicate ()
562+ # Ubuntu 12.04 ships a broken ffmpeg binary which we shouldn't use
563+ if 'Libav' in err .decode ():
564+ return False
565+ return True
566+
517567
518568# Combine FFMpeg options with pipe-based writing
519569@writers .register ('ffmpeg' )
520- class FFMpegWriter (MovieWriter , FFMpegBase ):
570+ class FFMpegWriter (FFMpegBase , MovieWriter ):
521571 '''Pipe-based ffmpeg writer.
522572
523573 Frames are streamed directly to ffmpeg via a pipe and written in a single
@@ -538,7 +588,7 @@ def _args(self):
538588
539589# Combine FFMpeg options with temp file-based writing
540590@writers .register ('ffmpeg_file' )
541- class FFMpegFileWriter (FileMovieWriter , FFMpegBase ):
591+ class FFMpegFileWriter (FFMpegBase , FileMovieWriter ):
542592 '''File-based ffmpeg writer.
543593
544594 Frames are written to temporary files on disk and then stitched
0 commit comments