Skip to content

Commit 01c41a0

Browse files
jklymakQuLogic
authored andcommitted
Backport PR #18089: Revert "Convert adjust_bbox to use ExitStack."
1 parent 5d166a5 commit 01c41a0

File tree

2 files changed

+49
-38
lines changed

2 files changed

+49
-38
lines changed

lib/matplotlib/tests/test_bbox_tight.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,13 @@ def test_noop_tight_bbox():
125125
ax.get_yaxis().set_visible(False)
126126

127127
data = np.arange(x_size * y_size).reshape(y_size, x_size)
128-
ax.imshow(data)
128+
ax.imshow(data, rasterized=True)
129+
130+
# When a rasterized Artist is included, a mixed-mode renderer does
131+
# additional bbox adjustment. It should also be a no-op, and not affect the
132+
# next save.
133+
fig.savefig(BytesIO(), bbox_inches='tight', pad_inches=0, format='pdf')
134+
129135
out = BytesIO()
130136
fig.savefig(out, bbox_inches='tight', pad_inches=0)
131137
out.seek(0)

lib/matplotlib/tight_bbox.py

Lines changed: 42 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,6 @@
22
Helper module for the *bbox_inches* parameter in `.Figure.savefig`.
33
"""
44

5-
import contextlib
6-
7-
from matplotlib.cbook import _setattr_cm
85
from matplotlib.transforms import Bbox, TransformedBbox, Affine2D
96

107

@@ -18,55 +15,63 @@ 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
"""
21-
def no_op_apply_aspect(position=None):
22-
return
23-
24-
stack = contextlib.ExitStack()
18+
origBbox = fig.bbox
19+
origBboxInches = fig.bbox_inches
20+
orig_tight_layout = fig.get_tight_layout()
21+
_boxout = fig.transFigure._boxout
2522

26-
stack.callback(fig.set_tight_layout, fig.get_tight_layout())
2723
fig.set_tight_layout(False)
2824

25+
old_aspect = []
26+
locator_list = []
27+
sentinel = object()
2928
for ax in fig.axes:
30-
pos = ax.get_position(original=False).frozen()
31-
32-
def _l(a, r, pos=pos):
33-
return pos
34-
35-
stack.callback(ax.set_axes_locator, ax.get_axes_locator())
36-
ax.set_axes_locator(_l)
37-
38-
# override the method that enforces the aspect ratio
39-
# on the Axes
40-
stack.enter_context(_setattr_cm(ax, apply_aspect=no_op_apply_aspect))
41-
42-
if fixed_dpi is not None:
43-
tr = Affine2D().scale(fixed_dpi)
44-
dpi_scale = fixed_dpi / fig.dpi
45-
else:
46-
tr = Affine2D().scale(fig.dpi)
47-
dpi_scale = 1.
29+
locator_list.append(ax.get_axes_locator())
30+
current_pos = ax.get_position(original=False).frozen()
31+
ax.set_axes_locator(lambda a, r, _pos=current_pos: _pos)
32+
# override the method that enforces the aspect ratio on the Axes
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)
54+
55+
if fixed_dpi is None:
56+
fixed_dpi = fig.dpi
57+
tr = Affine2D().scale(fixed_dpi)
58+
dpi_scale = fixed_dpi / fig.dpi
4859

4960
_bbox = TransformedBbox(bbox_inches, tr)
5061

51-
stack.enter_context(
52-
_setattr_cm(fig, bbox_inches=Bbox.from_bounds(
53-
0, 0, bbox_inches.width, bbox_inches.height)))
62+
fig.bbox_inches = Bbox.from_bounds(0, 0,
63+
bbox_inches.width, bbox_inches.height)
5464
x0, y0 = _bbox.x0, _bbox.y0
5565
w1, h1 = fig.bbox.width * dpi_scale, fig.bbox.height * dpi_scale
56-
stack.enter_context(
57-
_setattr_cm(fig.transFigure,
58-
_boxout=Bbox.from_bounds(-x0, -y0, w1, h1)))
66+
fig.transFigure._boxout = Bbox.from_bounds(-x0, -y0, w1, h1)
5967
fig.transFigure.invalidate()
60-
stack.callback(fig.transFigure.invalidate)
6168

62-
stack.enter_context(
63-
_setattr_cm(fig, bbox=TransformedBbox(fig.bbox_inches, tr)))
69+
fig.bbox = TransformedBbox(fig.bbox_inches, tr)
6470

65-
stack.callback(fig.patch.set_bounds, 0, 0, 1, 1)
6671
fig.patch.set_bounds(x0 / w1, y0 / h1,
6772
fig.bbox.width / w1, fig.bbox.height / h1)
6873

69-
return stack.close
74+
return restore_bbox
7075

7176

7277
def process_figure_for_rasterizing(fig, bbox_inches_restore, fixed_dpi=None):

0 commit comments

Comments
 (0)