Coverage for /usr/lib/python3/dist-packages/matplotlib/_tight_bbox.py: 85%
47 statements
« prev ^ index » next coverage.py v7.9.1, created at 2025-06-14 15:55 +0200
« prev ^ index » next coverage.py v7.9.1, created at 2025-06-14 15:55 +0200
1"""
2Helper module for the *bbox_inches* parameter in `.Figure.savefig`.
3"""
5from matplotlib.transforms import Bbox, TransformedBbox, Affine2D
8def adjust_bbox(fig, bbox_inches, fixed_dpi=None):
9 """
10 Temporarily adjust the figure so that only the specified area
11 (bbox_inches) is saved.
13 It modifies fig.bbox, fig.bbox_inches,
14 fig.transFigure._boxout, and fig.patch. While the figure size
15 changes, the scale of the original figure is conserved. A
16 function which restores the original values are returned.
17 """
18 origBbox = fig.bbox
19 origBboxInches = fig.bbox_inches
20 orig_layout = fig.get_layout_engine()
21 fig.set_layout_engine(None)
22 _boxout = fig.transFigure._boxout
24 old_aspect = []
25 locator_list = []
26 sentinel = object()
27 for ax in fig.axes:
28 locator_list.append(ax.get_axes_locator())
29 current_pos = ax.get_position(original=False).frozen()
30 ax.set_axes_locator(lambda a, r, _pos=current_pos: _pos)
31 # override the method that enforces the aspect ratio on the Axes
32 if 'apply_aspect' in ax.__dict__:
33 old_aspect.append(ax.apply_aspect)
34 else:
35 old_aspect.append(sentinel)
36 ax.apply_aspect = lambda pos=None: None
38 def restore_bbox():
39 for ax, loc, aspect in zip(fig.axes, locator_list, old_aspect):
40 ax.set_axes_locator(loc)
41 if aspect is sentinel:
42 # delete our no-op function which un-hides the original method
43 del ax.apply_aspect
44 else:
45 ax.apply_aspect = aspect
47 fig.bbox = origBbox
48 fig.bbox_inches = origBboxInches
49 fig.set_layout_engine(orig_layout)
50 fig.transFigure._boxout = _boxout
51 fig.transFigure.invalidate()
52 fig.patch.set_bounds(0, 0, 1, 1)
54 if fixed_dpi is None:
55 fixed_dpi = fig.dpi
56 tr = Affine2D().scale(fixed_dpi)
57 dpi_scale = fixed_dpi / fig.dpi
59 fig.bbox_inches = Bbox.from_bounds(0, 0, *bbox_inches.size)
60 x0, y0 = tr.transform(bbox_inches.p0)
61 w1, h1 = fig.bbox.size * dpi_scale
62 fig.transFigure._boxout = Bbox.from_bounds(-x0, -y0, w1, h1)
63 fig.transFigure.invalidate()
65 fig.bbox = TransformedBbox(fig.bbox_inches, tr)
67 fig.patch.set_bounds(x0 / w1, y0 / h1,
68 fig.bbox.width / w1, fig.bbox.height / h1)
70 return restore_bbox
73def process_figure_for_rasterizing(fig, bbox_inches_restore, fixed_dpi=None):
74 """
75 A function that needs to be called when figure dpi changes during the
76 drawing (e.g., rasterizing). It recovers the bbox and re-adjust it with
77 the new dpi.
78 """
80 bbox_inches, restore_bbox = bbox_inches_restore
81 restore_bbox()
82 r = adjust_bbox(fig, bbox_inches, fixed_dpi)
84 return bbox_inches, r