@@ -213,7 +213,13 @@ def grab_frame(self, **savefig_kwargs):
213
213
Grab the image information from the figure and save as a movie frame.
214
214
215
215
All keyword arguments in *savefig_kwargs* are passed on to the
216
- `~.Figure.savefig` call that saves the figure.
216
+ `~.Figure.savefig` call that saves the figure. However, several
217
+ keyword arguments that are supported by `~.Figure.savefig` may not be
218
+ passed as they are controlled by the MovieWriter:
219
+
220
+ - *dpi*, *bbox_inches*: These may not be passed because each frame of the
221
+ animation much be exactly the same size in pixels.
222
+ - *format*: This is controlled by the MovieWriter.
217
223
"""
218
224
219
225
@abc .abstractmethod
@@ -227,12 +233,18 @@ def saving(self, fig, outfile, dpi, *args, **kwargs):
227
233
228
234
``*args, **kw`` are any parameters that should be passed to `setup`.
229
235
"""
236
+ if mpl .rcParams ['savefig.bbox' ] == 'tight' :
237
+ _log .info ("Disabling savefig.bbox = 'tight', as it may cause "
238
+ "frame size to vary, which is inappropriate for "
239
+ "animation." )
240
+
230
241
# This particular sequence is what contextlib.contextmanager wants
231
242
self .setup (fig , outfile , dpi , * args , ** kwargs )
232
- try :
233
- yield self
234
- finally :
235
- self .finish ()
243
+ with mpl .rc_context ({'savefig.bbox' : None }):
244
+ try :
245
+ yield self
246
+ finally :
247
+ self .finish ()
236
248
237
249
238
250
class MovieWriter (AbstractMovieWriter ):
@@ -351,6 +363,7 @@ def finish(self):
351
363
352
364
def grab_frame (self , ** savefig_kwargs ):
353
365
# docstring inherited
366
+ _validate_grabframe_kwargs (savefig_kwargs )
354
367
_log .debug ('MovieWriter.grab_frame: Grabbing frame.' )
355
368
# Readjust the figure size in case it has been changed by the user.
356
369
# All frames must have the same size to save the movie correctly.
@@ -457,6 +470,7 @@ def _base_temp_name(self):
457
470
def grab_frame (self , ** savefig_kwargs ):
458
471
# docstring inherited
459
472
# Creates a filename for saving using basename and counter.
473
+ _validate_grabframe_kwargs (savefig_kwargs )
460
474
path = Path (self ._base_temp_name () % self ._frame_counter )
461
475
self ._temp_paths .append (path ) # Record the filename for later use.
462
476
self ._frame_counter += 1 # Ensures each created name is unique.
@@ -491,6 +505,7 @@ def setup(self, fig, outfile, dpi=None):
491
505
self ._frames = []
492
506
493
507
def grab_frame (self , ** savefig_kwargs ):
508
+ _validate_grabframe_kwargs (savefig_kwargs )
494
509
buf = BytesIO ()
495
510
self .fig .savefig (
496
511
buf , ** {** savefig_kwargs , "format" : "rgba" , "dpi" : self .dpi })
@@ -747,6 +762,7 @@ def setup(self, fig, outfile, dpi=None, frame_dir=None):
747
762
self ._clear_temp = False
748
763
749
764
def grab_frame (self , ** savefig_kwargs ):
765
+ _validate_grabframe_kwargs (savefig_kwargs )
750
766
if self .embed_frames :
751
767
# Just stop processing if we hit the limit
752
768
if self ._hit_limit :
@@ -1051,10 +1067,6 @@ def func(current_frame: int, total_frames: int) -> Any
1051
1067
# TODO: Right now, after closing the figure, saving a movie won't work
1052
1068
# since GUI widgets are gone. Either need to remove extra code to
1053
1069
# allow for this non-existent use case or find a way to make it work.
1054
- if mpl .rcParams ['savefig.bbox' ] == 'tight' :
1055
- _log .info ("Disabling savefig.bbox = 'tight', as it may cause "
1056
- "frame size to vary, which is inappropriate for "
1057
- "animation." )
1058
1070
1059
1071
facecolor = savefig_kwargs .get ('facecolor' ,
1060
1072
mpl .rcParams ['savefig.facecolor' ])
@@ -1070,10 +1082,8 @@ def _pre_composite_to_white(color):
1070
1082
# canvas._is_saving = True makes the draw_event animation-starting
1071
1083
# callback a no-op; canvas.manager = None prevents resizing the GUI
1072
1084
# widget (both are likewise done in savefig()).
1073
- with mpl .rc_context ({'savefig.bbox' : None }), \
1074
- writer .saving (self ._fig , filename , dpi ), \
1075
- cbook ._setattr_cm (self ._fig .canvas ,
1076
- _is_saving = True , manager = None ):
1085
+ with writer .saving (self ._fig , filename , dpi ), \
1086
+ cbook ._setattr_cm (self ._fig .canvas , _is_saving = True , manager = None ):
1077
1087
for anim in all_anim :
1078
1088
anim ._init_draw () # Clear the initial frame
1079
1089
frame_number = 0
@@ -1776,3 +1786,16 @@ def _draw_frame(self, framedata):
1776
1786
a .set_animated (self ._blit )
1777
1787
1778
1788
save_count = _api .deprecate_privatize_attribute ("3.7" )
1789
+
1790
+
1791
+ def _validate_grabframe_kwargs (savefig_kwargs ):
1792
+ if mpl .rcParams ['savefig.bbox' ] == 'tight' :
1793
+ raise ValueError (
1794
+ f"{ mpl .rcParams ['savefig.bbox' ]= } must not be 'tight' as it "
1795
+ "may cause frame size to vary, which is inappropriate for animation."
1796
+ )
1797
+ for k in ('dpi' , 'bbox_inches' , 'format' ):
1798
+ if k in savefig_kwargs :
1799
+ raise TypeError (
1800
+ f"grab_frame got an unexpected keyword argument { k !r} "
1801
+ )
0 commit comments