From 3ef69444330c33ebdc510107768758cdeefd0137 Mon Sep 17 00:00:00 2001 From: Jody Klymak Date: Thu, 12 Apr 2018 09:01:45 -0700 Subject: [PATCH] FIX: constrained_layout and repeated calls to suptitle FIX: make suptitle be in CL only if placed automatically FIX: suptitle needed an artist as well FIX: revert change to signature so we can test if kwargs used fix CL tests --- lib/matplotlib/_constrained_layout.py | 2 +- lib/matplotlib/figure.py | 36 ++++++++++------- .../tests/test_constrainedlayout.py | 40 +++++++++++++++++++ 3 files changed, 63 insertions(+), 15 deletions(-) diff --git a/lib/matplotlib/_constrained_layout.py b/lib/matplotlib/_constrained_layout.py index 2faf40c3b6bc..fa0ae537ef74 100644 --- a/lib/matplotlib/_constrained_layout.py +++ b/lib/matplotlib/_constrained_layout.py @@ -235,7 +235,7 @@ def do_constrained_layout(fig, renderer, h_pad, w_pad, ax._poslayoutbox.constrain_left_margin(0, strength='weak') # do layout for suptitle. - if fig._suptitle is not None: + if fig._suptitle is not None and fig._suptitle._layoutbox is not None: sup = fig._suptitle bbox = invTransFig(sup.get_window_extent(renderer=renderer)) height = bbox.y1 - bbox.y0 diff --git a/lib/matplotlib/figure.py b/lib/matplotlib/figure.py index e2fca38313a2..b97655e8fb39 100644 --- a/lib/matplotlib/figure.py +++ b/lib/matplotlib/figure.py @@ -678,7 +678,7 @@ def get_window_extent(self, *args, **kwargs): """ return self.bbox - def suptitle(self, t, *, x=.5, y=.98, **kwargs): + def suptitle(self, t, **kwargs): """ Add a centered title to the figure. @@ -732,6 +732,11 @@ def suptitle(self, t, *, x=.5, y=.98, **kwargs): >>> fig.suptitle('This is the figure title', fontsize=12) """ + manual_position = ('x' in kwargs or 'y' in kwargs) + + x = kwargs.pop('x', 0.5) + y = kwargs.pop('y', 0.98) + if ('horizontalalignment' not in kwargs) and ('ha' not in kwargs): kwargs['horizontalalignment'] = 'center' if ('verticalalignment' not in kwargs) and ('va' not in kwargs): @@ -751,19 +756,22 @@ def suptitle(self, t, *, x=.5, y=.98, **kwargs): sup.remove() else: self._suptitle = sup - if self._layoutbox is not None: - # assign a layout box to the suptitle... - figlb = self._layoutbox - self._suptitle._layoutbox = layoutbox.LayoutBox( - parent=figlb, - name=figlb.name+'.suptitle') - for child in figlb.children: - if not (child == self._suptitle._layoutbox): - w_pad, h_pad, wspace, hspace = \ - self.get_constrained_layout_pads( - relative=True) - layoutbox.vstack([self._suptitle._layoutbox, child], - padding=h_pad*2., strength='required') + self._suptitle._layoutbox = None + if self._layoutbox is not None and not manual_position: + w_pad, h_pad, wspace, hspace = \ + self.get_constrained_layout_pads(relative=True) + figlb = self._layoutbox + self._suptitle._layoutbox = layoutbox.LayoutBox( + parent=figlb, artist=self._suptitle, + name=figlb.name+'.suptitle') + # stack the suptitle on top of all the children. + # Some day this should be on top of all the children in the + # gridspec only. + for child in figlb.children: + if child is not self._suptitle._layoutbox: + layoutbox.vstack([self._suptitle._layoutbox, + child], + padding=h_pad*2., strength='required') self.stale = True return self._suptitle diff --git a/lib/matplotlib/tests/test_constrainedlayout.py b/lib/matplotlib/tests/test_constrainedlayout.py index 24160a8e664e..cb25d67756fa 100644 --- a/lib/matplotlib/tests/test_constrainedlayout.py +++ b/lib/matplotlib/tests/test_constrainedlayout.py @@ -344,3 +344,43 @@ def test_constrained_layout20(): ax = fig.add_axes([0, 0, 1, 1]) mesh = ax.pcolormesh(gx, gx, img) fig.colorbar(mesh) + + +def test_constrained_layout21(): + '#11035: repeated calls to suptitle should not alter the layout' + fig, ax = plt.subplots(constrained_layout=True) + + fig.suptitle("Suptitle0") + fig.canvas.draw() + extents0 = np.copy(ax.get_position().extents) + + fig.suptitle("Suptitle1") + fig.canvas.draw() + extents1 = np.copy(ax.get_position().extents) + + np.testing.assert_allclose(extents0, extents1) + + +def test_constrained_layout22(): + '#11035: suptitle should not be include in CL if manually positioned' + fig, ax = plt.subplots(constrained_layout=True) + + fig.canvas.draw() + extents0 = np.copy(ax.get_position().extents) + + fig.suptitle("Suptitle", y=0.5) + fig.canvas.draw() + extents1 = np.copy(ax.get_position().extents) + + np.testing.assert_allclose(extents0, extents1) + + +def test_constrained_layout23(): + ''' + Comment in #11035: suptitle used to cause an exception when + reusing a figure w/ CL with ``clear=True``. + ''' + + for i in range(2): + fig, ax = plt.subplots(num="123", constrained_layout=True, clear=True) + fig.suptitle("Suptitle{}".format(i))