23
23
import six
24
24
from six .moves import xrange , zip
25
25
26
+ import numpy as np
26
27
import os
27
28
import platform
28
29
import sys
62
63
63
64
64
65
def 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
+
65
95
wnew = int (w * dpi / n ) * n / dpi
66
96
hnew = int (h * dpi / n ) * n / dpi
67
- return wnew , hnew
97
+ return ( correct_roundoff ( wnew , dpi , n ), correct_roundoff ( hnew , dpi , n ))
68
98
69
99
70
100
# A registry for available MovieWriter classes
@@ -278,8 +308,11 @@ def _adjust_frame_size(self):
278
308
verbose .report ('figure size (inches) has been adjusted '
279
309
'from %s x %s to %s x %s' % (wo , ho , w , h ),
280
310
level = 'helpful' )
311
+ else :
312
+ w , h = self .fig .get_size_inches ()
281
313
verbose .report ('frame size in pixels is %s x %s' % self .frame_size ,
282
314
level = 'debug' )
315
+ return w , h
283
316
284
317
def setup (self , fig , outfile , dpi = None ):
285
318
'''
@@ -301,7 +334,7 @@ def setup(self, fig, outfile, dpi=None):
301
334
if dpi is None :
302
335
dpi = self .fig .dpi
303
336
self .dpi = dpi
304
- self ._adjust_frame_size ()
337
+ self ._w , self . _h = self . _adjust_frame_size ()
305
338
306
339
# Run here so that grab_frame() can write the data to a pipe. This
307
340
# eliminates the need for temp files.
@@ -337,6 +370,10 @@ def grab_frame(self, **savefig_kwargs):
337
370
verbose .report ('MovieWriter.grab_frame: Grabbing frame.' ,
338
371
level = 'debug' )
339
372
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 )
340
377
# Tell the figure to save its data to the sink, using the
341
378
# frame format and dpi.
342
379
self .fig .savefig (self ._frame_sink (), format = self .frame_format ,
@@ -386,16 +423,21 @@ def isAvailable(cls):
386
423
if not bin_path :
387
424
return False
388
425
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 )
396
433
except OSError :
397
434
return False
398
435
436
+ @classmethod
437
+ def _handle_subprocess (cls , process ):
438
+ process .communicate ()
439
+ return True
440
+
399
441
400
442
class FileMovieWriter (MovieWriter ):
401
443
'''`MovieWriter` for writing to individual files and stitching at the end.
@@ -570,10 +612,18 @@ def output_args(self):
570
612
571
613
return args + ['-y' , self .outfile ]
572
614
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
+
573
623
574
624
# Combine FFMpeg options with pipe-based writing
575
625
@writers .register ('ffmpeg' )
576
- class FFMpegWriter (MovieWriter , FFMpegBase ):
626
+ class FFMpegWriter (FFMpegBase , MovieWriter ):
577
627
'''Pipe-based ffmpeg writer.
578
628
579
629
Frames are streamed directly to ffmpeg via a pipe and written in a single
@@ -594,7 +644,7 @@ def _args(self):
594
644
595
645
# Combine FFMpeg options with temp file-based writing
596
646
@writers .register ('ffmpeg_file' )
597
- class FFMpegFileWriter (FileMovieWriter , FFMpegBase ):
647
+ class FFMpegFileWriter (FFMpegBase , FileMovieWriter ):
598
648
'''File-based ffmpeg writer.
599
649
600
650
Frames are written to temporary files on disk and then stitched
0 commit comments