From 7ba25e02dc7eb27777eaf7e06f82618efa24c4ce Mon Sep 17 00:00:00 2001 From: Theodore Shaw Date: Tue, 17 Jun 2025 12:50:47 -0500 Subject: [PATCH 1/5] savefig's pad_inches specifies per border padding Added a new padding function to transforms.py, called it in backend_bases, and updated documentation where pad_inches shows up --- lib/matplotlib/backend_bases.py | 23 +++++++++++++++-------- lib/matplotlib/figure.py | 10 +++++----- lib/matplotlib/transforms.py | 8 ++++++++ 3 files changed, 28 insertions(+), 13 deletions(-) diff --git a/lib/matplotlib/backend_bases.py b/lib/matplotlib/backend_bases.py index 527d8c010710..a5ab8eb94a55 100644 --- a/lib/matplotlib/backend_bases.py +++ b/lib/matplotlib/backend_bases.py @@ -2088,11 +2088,11 @@ def print_figure( Bounding box in inches: only the given portion of the figure is saved. If 'tight', try to figure out the tight bbox of the figure. - pad_inches : float or 'layout', default: :rc:`savefig.pad_inches` - Amount of padding in inches around the figure when bbox_inches is - 'tight'. If 'layout' use the padding from the constrained or - compressed layout engine; ignored if one of those engines is not in - use. + pad_inches : float, 4-tuple of floats, or 'layout', + default: :rc:`savefig.pad_inches`. Amount of padding in inches + around the figure when bbox_inches is 'tight'. If 'layout' use the + padding from the constrained or compressed layout engine; ignored + if one of those engines is not in use. bbox_extra_artists : list of `~matplotlib.artist.Artist`, optional A list of extra artists that will be considered when the @@ -2164,10 +2164,17 @@ def print_figure( h_pad = layout_engine.get()["h_pad"] w_pad = layout_engine.get()["w_pad"] else: - if pad_inches in [None, "layout"]: + if isinstance(pad_inches, (int, float)): + l_pad = r_pad = b_pad = t_pad = pad_inches + elif pad_inches in [None, "layout"]: pad_inches = rcParams['savefig.pad_inches'] - h_pad = w_pad = pad_inches - bbox_inches = bbox_inches.padded(w_pad, h_pad) + l_pad = r_pad = b_pad = t_pad = pad_inches + else: + l_pad = pad_inches[0] + r_pad = pad_inches[1] + b_pad = pad_inches[2] + t_pad = pad_inches[3] + bbox_inches = bbox_inches.padded_4sides(l_pad, r_pad, b_pad, t_pad) # call adjust_bbox to save only the given area restore_bbox = _tight_bbox.adjust_bbox( diff --git a/lib/matplotlib/figure.py b/lib/matplotlib/figure.py index c15da7597acd..a9feb73f3f3e 100644 --- a/lib/matplotlib/figure.py +++ b/lib/matplotlib/figure.py @@ -3409,11 +3409,11 @@ def savefig(self, fname, *, transparent=None, **kwargs): Bounding box in inches: only the given portion of the figure is saved. If 'tight', try to figure out the tight bbox of the figure. - pad_inches : float or 'layout', default: :rc:`savefig.pad_inches` - Amount of padding in inches around the figure when bbox_inches is - 'tight'. If 'layout' use the padding from the constrained or - compressed layout engine; ignored if one of those engines is not in - use. + pad_inches : float, 4-tuple of floats, or 'layout', + default: :rc:`savefig.pad_inches`. Amount of padding in inches + around the figure when bbox_inches is 'tight'. If 'layout' use the + padding from the constrained or compressed layout engine; ignored + if one of those engines is not in use. facecolor : :mpltype:`color` or 'auto', default: :rc:`savefig.facecolor` The facecolor of the figure. If 'auto', use the current figure diff --git a/lib/matplotlib/transforms.py b/lib/matplotlib/transforms.py index 7228f05bcf9e..9bc40b6c545d 100644 --- a/lib/matplotlib/transforms.py +++ b/lib/matplotlib/transforms.py @@ -612,6 +612,14 @@ def padded(self, w_pad, h_pad=None): if h_pad is None: h_pad = w_pad return Bbox(points + [[-w_pad, -h_pad], [w_pad, h_pad]]) + + def padded_4sides(self, l, r, b, t): + """ + Construct a `Bbox` by padding this one by a possibly different + amount on each side. + """ + points = self.get_points() + return Bbox(points + [[-l, -b], [r, t]]) def translated(self, tx, ty): """Construct a `Bbox` by translating this one by *tx* and *ty*.""" From 683e8039a3e5e25d177c00fc272229463ed08fa4 Mon Sep 17 00:00:00 2001 From: Theodore Shaw Date: Tue, 17 Jun 2025 13:08:08 -0500 Subject: [PATCH 2/5] API change and what's new documentation --- doc/api/next_api_changes/behavior/30183-TS.rst | 3 +++ doc/users/next_whats_new/pad_inches_per_border.rst | 4 ++++ 2 files changed, 7 insertions(+) create mode 100644 doc/api/next_api_changes/behavior/30183-TS.rst create mode 100644 doc/users/next_whats_new/pad_inches_per_border.rst diff --git a/doc/api/next_api_changes/behavior/30183-TS.rst b/doc/api/next_api_changes/behavior/30183-TS.rst new file mode 100644 index 000000000000..9aad35a278f3 --- /dev/null +++ b/doc/api/next_api_changes/behavior/30183-TS.rst @@ -0,0 +1,3 @@ +savefig() pad_inches per-border specification +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +pad_inches will now accept a 4-tuple specifying the padding per border, in the order [left, right, bottom, top]. \ No newline at end of file diff --git a/doc/users/next_whats_new/pad_inches_per_border.rst b/doc/users/next_whats_new/pad_inches_per_border.rst new file mode 100644 index 000000000000..f74f0e5001b7 --- /dev/null +++ b/doc/users/next_whats_new/pad_inches_per_border.rst @@ -0,0 +1,4 @@ +savefig() pad_inches per-border specification +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +pad_inches will now accept a 4-tuple specifying the padding per border, in the order [left, right, bottom, top]. This can be used to simply and precisely modify the bounding box of what in a figure is saved to a file. \ No newline at end of file From bdf0d81c4f61d76cb093c1f1476dde2c0b6cfe12 Mon Sep 17 00:00:00 2001 From: Theodore Shaw Date: Tue, 17 Jun 2025 14:21:00 -0500 Subject: [PATCH 3/5] Fix for "layout" Overlooked a change I made earlier but lost --- lib/matplotlib/backend_bases.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/matplotlib/backend_bases.py b/lib/matplotlib/backend_bases.py index a5ab8eb94a55..e71e9baf1a49 100644 --- a/lib/matplotlib/backend_bases.py +++ b/lib/matplotlib/backend_bases.py @@ -2161,8 +2161,8 @@ def print_figure( renderer, bbox_extra_artists=bbox_extra_artists) if (isinstance(layout_engine, ConstrainedLayoutEngine) and pad_inches == "layout"): - h_pad = layout_engine.get()["h_pad"] - w_pad = layout_engine.get()["w_pad"] + b_pad = t_pad = layout_engine.get()["h_pad"] + l_pad = r_pad = layout_engine.get()["w_pad"] else: if isinstance(pad_inches, (int, float)): l_pad = r_pad = b_pad = t_pad = pad_inches From 85964201c747c3cecc47d15f5b21934237a6d584 Mon Sep 17 00:00:00 2001 From: Theodore Shaw Date: Tue, 17 Jun 2025 15:19:43 -0500 Subject: [PATCH 4/5] Extraneous whitespace formatting --- lib/matplotlib/figure.py | 8 ++++---- lib/matplotlib/transforms.py | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/matplotlib/figure.py b/lib/matplotlib/figure.py index a9feb73f3f3e..3d9a46421a92 100644 --- a/lib/matplotlib/figure.py +++ b/lib/matplotlib/figure.py @@ -3409,10 +3409,10 @@ def savefig(self, fname, *, transparent=None, **kwargs): Bounding box in inches: only the given portion of the figure is saved. If 'tight', try to figure out the tight bbox of the figure. - pad_inches : float, 4-tuple of floats, or 'layout', - default: :rc:`savefig.pad_inches`. Amount of padding in inches - around the figure when bbox_inches is 'tight'. If 'layout' use the - padding from the constrained or compressed layout engine; ignored + pad_inches : float, 4-tuple of floats, or 'layout', + default: :rc:`savefig.pad_inches`. Amount of padding in inches + around the figure when bbox_inches is 'tight'. If 'layout' use the + padding from the constrained or compressed layout engine; ignored if one of those engines is not in use. facecolor : :mpltype:`color` or 'auto', default: :rc:`savefig.facecolor` diff --git a/lib/matplotlib/transforms.py b/lib/matplotlib/transforms.py index 9bc40b6c545d..2a55047a9a60 100644 --- a/lib/matplotlib/transforms.py +++ b/lib/matplotlib/transforms.py @@ -612,7 +612,7 @@ def padded(self, w_pad, h_pad=None): if h_pad is None: h_pad = w_pad return Bbox(points + [[-w_pad, -h_pad], [w_pad, h_pad]]) - + def padded_4sides(self, l, r, b, t): """ Construct a `Bbox` by padding this one by a possibly different From 4f4ee46aa4b23a6ee75139ac2dca95f452006a54 Mon Sep 17 00:00:00 2001 From: Theodore Shaw Date: Tue, 17 Jun 2025 16:01:33 -0500 Subject: [PATCH 5/5] More trailing whitespace formatting --- lib/matplotlib/backend_bases.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/matplotlib/backend_bases.py b/lib/matplotlib/backend_bases.py index e71e9baf1a49..5f54b71edae0 100644 --- a/lib/matplotlib/backend_bases.py +++ b/lib/matplotlib/backend_bases.py @@ -2088,10 +2088,10 @@ def print_figure( Bounding box in inches: only the given portion of the figure is saved. If 'tight', try to figure out the tight bbox of the figure. - pad_inches : float, 4-tuple of floats, or 'layout', - default: :rc:`savefig.pad_inches`. Amount of padding in inches - around the figure when bbox_inches is 'tight'. If 'layout' use the - padding from the constrained or compressed layout engine; ignored + pad_inches : float, 4-tuple of floats, or 'layout', + default: :rc:`savefig.pad_inches`. Amount of padding in inches + around the figure when bbox_inches is 'tight'. If 'layout' use the + padding from the constrained or compressed layout engine; ignored if one of those engines is not in use. bbox_extra_artists : list of `~matplotlib.artist.Artist`, optional