@@ -213,7 +213,13 @@ def grab_frame(self, **savefig_kwargs):
213213 Grab the image information from the figure and save as a movie frame.
214214
215215 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.
217223 """
218224
219225 @abc .abstractmethod
@@ -227,12 +233,18 @@ def saving(self, fig, outfile, dpi, *args, **kwargs):
227233
228234 ``*args, **kw`` are any parameters that should be passed to `setup`.
229235 """
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+
230241 # This particular sequence is what contextlib.contextmanager wants
231242 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 ()
236248
237249
238250class MovieWriter (AbstractMovieWriter ):
@@ -351,6 +363,7 @@ def finish(self):
351363
352364 def grab_frame (self , ** savefig_kwargs ):
353365 # docstring inherited
366+ _validate_grabframe_kwargs (savefig_kwargs )
354367 _log .debug ('MovieWriter.grab_frame: Grabbing frame.' )
355368 # Readjust the figure size in case it has been changed by the user.
356369 # All frames must have the same size to save the movie correctly.
@@ -457,6 +470,7 @@ def _base_temp_name(self):
457470 def grab_frame (self , ** savefig_kwargs ):
458471 # docstring inherited
459472 # Creates a filename for saving using basename and counter.
473+ _validate_grabframe_kwargs (savefig_kwargs )
460474 path = Path (self ._base_temp_name () % self ._frame_counter )
461475 self ._temp_paths .append (path ) # Record the filename for later use.
462476 self ._frame_counter += 1 # Ensures each created name is unique.
@@ -491,6 +505,7 @@ def setup(self, fig, outfile, dpi=None):
491505 self ._frames = []
492506
493507 def grab_frame (self , ** savefig_kwargs ):
508+ _validate_grabframe_kwargs (savefig_kwargs )
494509 buf = BytesIO ()
495510 self .fig .savefig (
496511 buf , ** {** savefig_kwargs , "format" : "rgba" , "dpi" : self .dpi })
@@ -747,6 +762,7 @@ def setup(self, fig, outfile, dpi=None, frame_dir=None):
747762 self ._clear_temp = False
748763
749764 def grab_frame (self , ** savefig_kwargs ):
765+ _validate_grabframe_kwargs (savefig_kwargs )
750766 if self .embed_frames :
751767 # Just stop processing if we hit the limit
752768 if self ._hit_limit :
@@ -1051,10 +1067,6 @@ def func(current_frame: int, total_frames: int) -> Any
10511067 # TODO: Right now, after closing the figure, saving a movie won't work
10521068 # since GUI widgets are gone. Either need to remove extra code to
10531069 # 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." )
10581070
10591071 facecolor = savefig_kwargs .get ('facecolor' ,
10601072 mpl .rcParams ['savefig.facecolor' ])
@@ -1070,10 +1082,8 @@ def _pre_composite_to_white(color):
10701082 # canvas._is_saving = True makes the draw_event animation-starting
10711083 # callback a no-op; canvas.manager = None prevents resizing the GUI
10721084 # 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 ):
10771087 for anim in all_anim :
10781088 anim ._init_draw () # Clear the initial frame
10791089 frame_number = 0
@@ -1776,3 +1786,16 @@ def _draw_frame(self, framedata):
17761786 a .set_animated (self ._blit )
17771787
17781788 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