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
8
5
from matplotlib .transforms import Bbox , TransformedBbox , Affine2D
9
6
10
7
@@ -18,18 +15,42 @@ def adjust_bbox(fig, bbox_inches, fixed_dpi=None):
18
15
changes, the scale of the original figure is conserved. A
19
16
function which restores the original values are returned.
20
17
"""
18
+ origBbox = fig .bbox
19
+ origBboxInches = fig .bbox_inches
20
+ orig_tight_layout = fig .get_tight_layout ()
21
+ _boxout = fig .transFigure ._boxout
21
22
22
- stack = contextlib .ExitStack ()
23
-
24
- stack .callback (fig .set_tight_layout , fig .get_tight_layout ())
25
23
fig .set_tight_layout (False )
26
24
25
+ old_aspect = []
26
+ locator_list = []
27
+ sentinel = object ()
27
28
for ax in fig .axes :
28
- stack . callback ( ax . set_axes_locator , ax .get_axes_locator ())
29
+ locator_list . append ( ax .get_axes_locator ())
29
30
current_pos = ax .get_position (original = False ).frozen ()
30
31
ax .set_axes_locator (lambda a , r , _pos = current_pos : _pos )
31
32
# 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 )
33
54
34
55
if fixed_dpi is None :
35
56
fixed_dpi = fig .dpi
@@ -38,25 +59,19 @@ def adjust_bbox(fig, bbox_inches, fixed_dpi=None):
38
59
39
60
_bbox = TransformedBbox (bbox_inches , tr )
40
61
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 )
44
64
x0 , y0 = _bbox .x0 , _bbox .y0
45
65
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 )
49
67
fig .transFigure .invalidate ()
50
- stack .callback (fig .transFigure .invalidate )
51
68
52
- stack .enter_context (
53
- _setattr_cm (fig , bbox = TransformedBbox (fig .bbox_inches , tr )))
69
+ fig .bbox = TransformedBbox (fig .bbox_inches , tr )
54
70
55
- stack .callback (fig .patch .set_bounds , 0 , 0 , 1 , 1 )
56
71
fig .patch .set_bounds (x0 / w1 , y0 / h1 ,
57
72
fig .bbox .width / w1 , fig .bbox .height / h1 )
58
73
59
- return stack . close
74
+ return restore_bbox
60
75
61
76
62
77
def process_figure_for_rasterizing (fig , bbox_inches_restore , fixed_dpi = None ):
0 commit comments