2
2
Helper module for the *bbox_inches* parameter in `.Figure.savefig`.
3
3
"""
4
4
5
+ import contextlib
6
+
7
+ from matplotlib .cbook import _setattr_cm
5
8
from matplotlib .transforms import Bbox , TransformedBbox , Affine2D
6
9
7
10
@@ -18,46 +21,23 @@ def adjust_bbox(fig, bbox_inches, fixed_dpi=None):
18
21
def no_op_apply_aspect (position = None ):
19
22
return
20
23
21
- origBbox = fig .bbox
22
- origBboxInches = fig .bbox_inches
23
- orig_tight_layout = fig .get_tight_layout ()
24
- _boxout = fig .transFigure ._boxout
24
+ stack = contextlib .ExitStack ()
25
25
26
+ stack .callback (fig .set_tight_layout , fig .get_tight_layout ())
26
27
fig .set_tight_layout (False )
27
- old_aspect = []
28
- locator_list = []
29
- sentinel = object ()
28
+
30
29
for ax in fig .axes :
31
30
pos = ax .get_position (original = False ).frozen ()
32
- locator_list .append (ax .get_axes_locator ())
33
31
34
32
def _l (a , r , pos = pos ):
35
33
return pos
34
+
35
+ stack .callback (ax .set_axes_locator , ax .get_axes_locator ())
36
36
ax .set_axes_locator (_l )
37
+
37
38
# override the method that enforces the aspect ratio
38
39
# on the Axes
39
- if 'apply_aspect' in ax .__dict__ :
40
- old_aspect .append (ax .apply_aspect )
41
- else :
42
- old_aspect .append (sentinel )
43
- ax .apply_aspect = no_op_apply_aspect
44
-
45
- def restore_bbox ():
46
- for ax , loc , aspect in zip (fig .axes , locator_list , old_aspect ):
47
- ax .set_axes_locator (loc )
48
- if aspect is sentinel :
49
- # delete our no-op function which un-hides the
50
- # original method
51
- del ax .apply_aspect
52
- else :
53
- ax .apply_aspect = aspect
54
-
55
- fig .bbox = origBbox
56
- fig .bbox_inches = origBboxInches
57
- fig .set_tight_layout (orig_tight_layout )
58
- fig .transFigure ._boxout = _boxout
59
- fig .transFigure .invalidate ()
60
- fig .patch .set_bounds (0 , 0 , 1 , 1 )
40
+ stack .enter_context (_setattr_cm (ax , apply_aspect = no_op_apply_aspect ))
61
41
62
42
if fixed_dpi is not None :
63
43
tr = Affine2D ().scale (fixed_dpi )
@@ -68,19 +48,25 @@ def restore_bbox():
68
48
69
49
_bbox = TransformedBbox (bbox_inches , tr )
70
50
71
- fig .bbox_inches = Bbox .from_bounds (0 , 0 ,
72
- bbox_inches .width , bbox_inches .height )
51
+ stack .enter_context (
52
+ _setattr_cm (fig , bbox_inches = Bbox .from_bounds (
53
+ 0 , 0 , bbox_inches .width , bbox_inches .height )))
73
54
x0 , y0 = _bbox .x0 , _bbox .y0
74
55
w1 , h1 = fig .bbox .width * dpi_scale , fig .bbox .height * dpi_scale
75
- fig .transFigure ._boxout = Bbox .from_bounds (- x0 , - y0 , w1 , h1 )
56
+ stack .enter_context (
57
+ _setattr_cm (fig .transFigure ,
58
+ _boxout = Bbox .from_bounds (- x0 , - y0 , w1 , h1 )))
76
59
fig .transFigure .invalidate ()
60
+ stack .callback (fig .transFigure .invalidate )
77
61
78
- fig .bbox = TransformedBbox (fig .bbox_inches , tr )
62
+ stack .enter_context (
63
+ _setattr_cm (fig , bbox = TransformedBbox (fig .bbox_inches , tr )))
79
64
65
+ stack .callback (fig .patch .set_bounds , 0 , 0 , 1 , 1 )
80
66
fig .patch .set_bounds (x0 / w1 , y0 / h1 ,
81
67
fig .bbox .width / w1 , fig .bbox .height / h1 )
82
68
83
- return restore_bbox
69
+ return stack . close
84
70
85
71
86
72
def process_figure_for_rasterizing (fig , bbox_inches_restore , fixed_dpi = None ):
0 commit comments