@@ -188,6 +188,10 @@ class AbstractMovieWriter(abc.ABC):
188
188
``writer`` argument of `Animation.save()`.
189
189
'''
190
190
191
+ def __init__ (self , fps = 5 , metadata = None ):
192
+ self .fps = fps
193
+ self .metadata = metadata if metadata is not None else {}
194
+
191
195
@abc .abstractmethod
192
196
def setup (self , fig , outfile , dpi = None ):
193
197
'''
@@ -203,6 +207,17 @@ def setup(self, fig, outfile, dpi=None):
203
207
The DPI (or resolution) for the file. This controls the size
204
208
in pixels of the resulting movie file. Default is ``fig.dpi``.
205
209
'''
210
+ self .outfile = outfile
211
+ self .fig = fig
212
+ if dpi is None :
213
+ dpi = self .fig .dpi
214
+ self .dpi = dpi
215
+
216
+ @property
217
+ def frame_size (self ):
218
+ '''A tuple ``(width, height)`` in pixels of a movie frame.'''
219
+ w , h = self .fig .get_size_inches ()
220
+ return int (w * self .dpi ), int (h * self .dpi )
206
221
207
222
@abc .abstractmethod
208
223
def grab_frame (self , ** savefig_kwargs ):
@@ -275,7 +290,7 @@ def __init__(self, fps=5, codec=None, bitrate=None, extra_args=None,
275
290
output file. Some keys that may be of use include:
276
291
title, artist, genre, subject, copyright, srcform, comment.
277
292
"""
278
- if self . __class__ is MovieWriter :
293
+ if type ( self ) is MovieWriter :
279
294
# TODO MovieWriter is still an abstract class and needs to be
280
295
# extended with a mixin. This should be clearer in naming
281
296
# and description. For now, just give a reasonable error
@@ -284,7 +299,8 @@ def __init__(self, fps=5, codec=None, bitrate=None, extra_args=None,
284
299
'MovieWriter cannot be instantiated directly. Please use one '
285
300
'of its subclasses.' )
286
301
287
- self .fps = fps
302
+ super ().__init__ (fps = fps , metadata = metadata )
303
+
288
304
self .frame_format = 'rgba'
289
305
290
306
if codec is None :
@@ -302,17 +318,6 @@ def __init__(self, fps=5, codec=None, bitrate=None, extra_args=None,
302
318
else :
303
319
self .extra_args = extra_args
304
320
305
- if metadata is None :
306
- self .metadata = dict ()
307
- else :
308
- self .metadata = metadata
309
-
310
- @property
311
- def frame_size (self ):
312
- '''A tuple ``(width, height)`` in pixels of a movie frame.'''
313
- w , h = self .fig .get_size_inches ()
314
- return int (w * self .dpi ), int (h * self .dpi )
315
-
316
321
def _adjust_frame_size (self ):
317
322
if self .codec == 'h264' :
318
323
wo , ho = self .fig .get_size_inches ()
@@ -340,13 +345,8 @@ def setup(self, fig, outfile, dpi=None):
340
345
The DPI (or resolution) for the file. This controls the size
341
346
in pixels of the resulting movie file. Default is fig.dpi.
342
347
'''
343
- self .outfile = outfile
344
- self .fig = fig
345
- if dpi is None :
346
- dpi = self .fig .dpi
347
- self .dpi = dpi
348
+ super ().setup (fig , outfile , dpi = dpi )
348
349
self ._w , self ._h = self ._adjust_frame_size ()
349
-
350
350
# Run here so that grab_frame() can write the data to a pipe. This
351
351
# eliminates the need for temp files.
352
352
self ._run ()
@@ -540,35 +540,27 @@ def cleanup(self):
540
540
541
541
542
542
@writers .register ('pillow' )
543
- class PillowWriter (MovieWriter ):
543
+ class PillowWriter (AbstractMovieWriter ):
544
544
@classmethod
545
545
def isAvailable (cls ):
546
546
return True
547
547
548
- def __init__ (self , * args , ** kwargs ):
549
- if kwargs .get ("extra_args" ) is None :
550
- kwargs ["extra_args" ] = ()
551
- super ().__init__ (* args , ** kwargs )
552
-
553
548
def setup (self , fig , outfile , dpi = None ):
549
+ super ().setup (fig , outfile , dpi = dpi )
554
550
self ._frames = []
555
- self ._outfile = outfile
556
- self ._dpi = dpi
557
- self ._fig = fig
558
551
559
552
def grab_frame (self , ** savefig_kwargs ):
560
553
from PIL import Image
561
554
buf = BytesIO ()
562
- self ._fig .savefig (buf , ** dict (savefig_kwargs , format = "rgba" ))
563
- renderer = self ._fig .canvas .get_renderer ()
555
+ self .fig .savefig (
556
+ buf , ** {** savefig_kwargs , "format" : "rgba" , "dpi" : self .dpi })
557
+ renderer = self .fig .canvas .get_renderer ()
564
558
self ._frames .append (Image .frombuffer (
565
- "RGBA" ,
566
- (int (renderer .width ), int (renderer .height )), buf .getbuffer (),
567
- "raw" , "RGBA" , 0 , 1 ))
559
+ "RGBA" , self .frame_size , buf .getbuffer (), "raw" , "RGBA" , 0 , 1 ))
568
560
569
561
def finish (self ):
570
562
self ._frames [0 ].save (
571
- self ._outfile , save_all = True , append_images = self ._frames [1 :],
563
+ self .outfile , save_all = True , append_images = self ._frames [1 :],
572
564
duration = int (1000 / self .fps ), loop = 0 )
573
565
574
566
@@ -1075,11 +1067,15 @@ def func(current_frame: int, total_frames: int) -> Any
1075
1067
if dpi == 'figure' :
1076
1068
dpi = self ._fig .dpi
1077
1069
1078
- if codec is None :
1079
- codec = mpl .rcParams ['animation.codec' ]
1080
-
1081
- if bitrate is None :
1082
- bitrate = mpl .rcParams ['animation.bitrate' ]
1070
+ writer_kwargs = {}
1071
+ if codec is not None :
1072
+ writer_kwargs ['codec' ] = codec
1073
+ if bitrate is not None :
1074
+ writer_kwargs ['bitrate' ] = bitrate
1075
+ if extra_args is not None :
1076
+ writer_kwargs ['extra_args' ] = extra_args
1077
+ if metadata is not None :
1078
+ writer_kwargs ['metadata' ] = metadata
1083
1079
1084
1080
all_anim = [self ]
1085
1081
if extra_anim is not None :
@@ -1091,9 +1087,7 @@ def func(current_frame: int, total_frames: int) -> Any
1091
1087
# registered class.
1092
1088
if isinstance (writer , str ):
1093
1089
if writers .is_available (writer ):
1094
- writer = writers [writer ](fps , codec , bitrate ,
1095
- extra_args = extra_args ,
1096
- metadata = metadata )
1090
+ writer = writers [writer ](fps , ** writer_kwargs )
1097
1091
else :
1098
1092
alt_writer = next (writers , None )
1099
1093
if alt_writer is None :
@@ -1102,9 +1096,7 @@ def func(current_frame: int, total_frames: int) -> Any
1102
1096
"save animations." )
1103
1097
_log .warning ("MovieWriter %s unavailable; trying to use %s "
1104
1098
"instead." , writer , alt_writer )
1105
- writer = alt_writer (
1106
- fps , codec , bitrate ,
1107
- extra_args = extra_args , metadata = metadata )
1099
+ writer = alt_writer (fps , ** writer_kwargs )
1108
1100
_log .info ('Animation.save using %s' , type (writer ))
1109
1101
1110
1102
if 'bbox_inches' in savefig_kwargs :
0 commit comments