From 9fc747e6050e2b496e11293b4b12e1ba62b325fd Mon Sep 17 00:00:00 2001 From: Elliott Sales de Andrade Date: Tue, 30 Mar 2021 16:19:48 -0400 Subject: [PATCH] Backport PR #19805: Fix suptitle out of layout --- lib/matplotlib/_constrained_layout.py | 21 ++++++++++-------- lib/matplotlib/figure.py | 13 ++++++----- .../bbox_inches_tight_suptile_non_default.png | Bin 0 -> 12170 bytes lib/matplotlib/tests/test_bbox_tight.py | 8 +++++++ 4 files changed, 28 insertions(+), 14 deletions(-) create mode 100644 lib/matplotlib/tests/baseline_images/test_bbox_tight/bbox_inches_tight_suptile_non_default.png diff --git a/lib/matplotlib/_constrained_layout.py b/lib/matplotlib/_constrained_layout.py index 58bb0ccabf95..245679394bc2 100644 --- a/lib/matplotlib/_constrained_layout.py +++ b/lib/matplotlib/_constrained_layout.py @@ -291,21 +291,24 @@ def _make_margin_suptitles(fig, renderer, *, w_pad=0, h_pad=0): if fig._suptitle is not None and fig._suptitle.get_in_layout(): p = fig._suptitle.get_position() - fig._suptitle.set_position((p[0], 1 - h_pad_local)) - bbox = inv_trans_fig(fig._suptitle.get_tightbbox(renderer)) - fig._layoutgrid.edit_margin_min('top', bbox.height + 2.0 * h_pad) + if getattr(fig._suptitle, '_autopos', False): + fig._suptitle.set_position((p[0], 1 - h_pad_local)) + bbox = inv_trans_fig(fig._suptitle.get_tightbbox(renderer)) + fig._layoutgrid.edit_margin_min('top', bbox.height + 2 * h_pad) if fig._supxlabel is not None and fig._supxlabel.get_in_layout(): p = fig._supxlabel.get_position() - fig._supxlabel.set_position((p[0], h_pad_local)) - bbox = inv_trans_fig(fig._supxlabel.get_tightbbox(renderer)) - fig._layoutgrid.edit_margin_min('bottom', bbox.height + 2.0 * h_pad) + if getattr(fig._supxlabel, '_autopos', False): + fig._supxlabel.set_position((p[0], h_pad_local)) + bbox = inv_trans_fig(fig._supxlabel.get_tightbbox(renderer)) + fig._layoutgrid.edit_margin_min('bottom', bbox.height + 2 * h_pad) if fig._supylabel is not None and fig._supxlabel.get_in_layout(): p = fig._supylabel.get_position() - fig._supylabel.set_position((w_pad_local, p[1])) - bbox = inv_trans_fig(fig._supylabel.get_tightbbox(renderer)) - fig._layoutgrid.edit_margin_min('left', bbox.width + 2.0 * w_pad) + if getattr(fig._supylabel, '_autopos', False): + fig._supylabel.set_position((w_pad_local, p[1])) + bbox = inv_trans_fig(fig._supylabel.get_tightbbox(renderer)) + fig._layoutgrid.edit_margin_min('left', bbox.width + 2 * w_pad) def _match_submerged_margins(fig): diff --git a/lib/matplotlib/figure.py b/lib/matplotlib/figure.py index f9f4b6c663b1..b2a578ab0eee 100644 --- a/lib/matplotlib/figure.py +++ b/lib/matplotlib/figure.py @@ -369,11 +369,15 @@ def _suplabels(self, t, info, **kwargs): Additional kwargs are `matplotlib.text.Text` properties. """ - manual_position = ('x' in kwargs or 'y' in kwargs) suplab = getattr(self, info['name']) - x = kwargs.pop('x', info['x0']) - y = kwargs.pop('y', info['y0']) + x = kwargs.pop('x', None) + y = kwargs.pop('y', None) + autopos = x is None and y is None + if x is None: + x = info['x0'] + if y is None: + y = info['y0'] if 'horizontalalignment' not in kwargs and 'ha' not in kwargs: kwargs['horizontalalignment'] = info['ha'] @@ -396,8 +400,7 @@ def _suplabels(self, t, info, **kwargs): sup.remove() else: suplab = sup - if manual_position: - suplab.set_in_layout(False) + suplab._autopos = autopos setattr(self, info['name'], suplab) self.stale = True return suplab diff --git a/lib/matplotlib/tests/baseline_images/test_bbox_tight/bbox_inches_tight_suptile_non_default.png b/lib/matplotlib/tests/baseline_images/test_bbox_tight/bbox_inches_tight_suptile_non_default.png new file mode 100644 index 0000000000000000000000000000000000000000..453ea566804d95f070709b939c25437c069f4810 GIT binary patch literal 12170 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 QJwBK-8amjlQ&$517p5We_W%F@ literal 0 HcmV?d00001 diff --git a/lib/matplotlib/tests/test_bbox_tight.py b/lib/matplotlib/tests/test_bbox_tight.py index f50b272209ea..c018db5eaa01 100644 --- a/lib/matplotlib/tests/test_bbox_tight.py +++ b/lib/matplotlib/tests/test_bbox_tight.py @@ -61,6 +61,14 @@ def y_formatter(y, pos): plt.xlabel('X axis') +@image_comparison(['bbox_inches_tight_suptile_non_default.png'], + remove_text=False, savefig_kwarg={'bbox_inches': 'tight'}, + tol=0.1) # large tolerance because only testing clipping. +def test_bbox_inches_tight_suptitle_non_default(): + fig, ax = plt.subplots() + fig.suptitle('Booo', x=0.5, y=1.1) + + @image_comparison(['bbox_inches_tight_clipping'], remove_text=True, savefig_kwarg={'bbox_inches': 'tight'}) def test_bbox_inches_tight_clipping():