22Helper module for the *bbox_inches* parameter in `.Figure.savefig`.
33"""
44
5- import contextlib
6-
7- from matplotlib .cbook import _setattr_cm
85from matplotlib .transforms import Bbox , TransformedBbox , Affine2D
96
107
@@ -18,18 +15,42 @@ def adjust_bbox(fig, bbox_inches, fixed_dpi=None):
1815 changes, the scale of the original figure is conserved. A
1916 function which restores the original values are returned.
2017 """
18+ origBbox = fig .bbox
19+ origBboxInches = fig .bbox_inches
20+ orig_tight_layout = fig .get_tight_layout ()
21+ _boxout = fig .transFigure ._boxout
2122
22- stack = contextlib .ExitStack ()
23-
24- stack .callback (fig .set_tight_layout , fig .get_tight_layout ())
2523 fig .set_tight_layout (False )
2624
25+ old_aspect = []
26+ locator_list = []
27+ sentinel = object ()
2728 for ax in fig .axes :
28- stack . callback ( ax . set_axes_locator , ax .get_axes_locator ())
29+ locator_list . append ( ax .get_axes_locator ())
2930 current_pos = ax .get_position (original = False ).frozen ()
3031 ax .set_axes_locator (lambda a , r , _pos = current_pos : _pos )
3132 # override the method that enforces the aspect ratio on the Axes
32- stack .enter_context (_setattr_cm (ax , apply_aspect = lambda pos : None ))
33+ if 'apply_aspect' in ax .__dict__ :
34+ old_aspect .append (ax .apply_aspect )
35+ else :
36+ old_aspect .append (sentinel )
37+ ax .apply_aspect = lambda pos = None : None
38+
39+ def restore_bbox ():
40+ for ax , loc , aspect in zip (fig .axes , locator_list , old_aspect ):
41+ ax .set_axes_locator (loc )
42+ if aspect is sentinel :
43+ # delete our no-op function which un-hides the original method
44+ del ax .apply_aspect
45+ else :
46+ ax .apply_aspect = aspect
47+
48+ fig .bbox = origBbox
49+ fig .bbox_inches = origBboxInches
50+ fig .set_tight_layout (orig_tight_layout )
51+ fig .transFigure ._boxout = _boxout
52+ fig .transFigure .invalidate ()
53+ fig .patch .set_bounds (0 , 0 , 1 , 1 )
3354
3455 if fixed_dpi is None :
3556 fixed_dpi = fig .dpi
@@ -38,25 +59,19 @@ def adjust_bbox(fig, bbox_inches, fixed_dpi=None):
3859
3960 _bbox = TransformedBbox (bbox_inches , tr )
4061
41- stack .enter_context (
42- _setattr_cm (fig , bbox_inches = Bbox .from_bounds (
43- 0 , 0 , bbox_inches .width , bbox_inches .height )))
62+ fig .bbox_inches = Bbox .from_bounds (0 , 0 ,
63+ bbox_inches .width , bbox_inches .height )
4464 x0 , y0 = _bbox .x0 , _bbox .y0
4565 w1 , h1 = fig .bbox .width * dpi_scale , fig .bbox .height * dpi_scale
46- stack .enter_context (
47- _setattr_cm (fig .transFigure ,
48- _boxout = Bbox .from_bounds (- x0 , - y0 , w1 , h1 )))
66+ fig .transFigure ._boxout = Bbox .from_bounds (- x0 , - y0 , w1 , h1 )
4967 fig .transFigure .invalidate ()
50- stack .callback (fig .transFigure .invalidate )
5168
52- stack .enter_context (
53- _setattr_cm (fig , bbox = TransformedBbox (fig .bbox_inches , tr )))
69+ fig .bbox = TransformedBbox (fig .bbox_inches , tr )
5470
55- stack .callback (fig .patch .set_bounds , 0 , 0 , 1 , 1 )
5671 fig .patch .set_bounds (x0 / w1 , y0 / h1 ,
5772 fig .bbox .width / w1 , fig .bbox .height / h1 )
5873
59- return stack . close
74+ return restore_bbox
6075
6176
6277def process_figure_for_rasterizing (fig , bbox_inches_restore , fixed_dpi = None ):
0 commit comments