diff --git a/lib/matplotlib/figure.py b/lib/matplotlib/figure.py index dab2bc4a5ab7..a1068afc078d 100644 --- a/lib/matplotlib/figure.py +++ b/lib/matplotlib/figure.py @@ -2274,17 +2274,30 @@ def _redo_transform_rel_fig(self, bbox=None): return # need to figure out *where* this subplotspec is. gs = self._subplotspec.get_gridspec() - wr = np.asarray(gs.get_width_ratios()) - hr = np.asarray(gs.get_height_ratios()) - dx = wr[self._subplotspec.colspan].sum() / wr.sum() - dy = hr[self._subplotspec.rowspan].sum() / hr.sum() - x0 = wr[:self._subplotspec.colspan.start].sum() / wr.sum() - y0 = 1 - hr[:self._subplotspec.rowspan.stop].sum() / hr.sum() + wspace = gs.wspace if gs.wspace is not None else 0.0 + hspace = gs.hspace if gs.hspace is not None else 0.0 + + subplotpars = SubplotParams( + left=0, right=1, bottom=0, top=1, wspace=wspace, hspace=hspace) + dummy_fig = type("_SubplotParamFig", (), {})() + dummy_fig.subplotpars = subplotpars + + fig_bottoms, fig_tops, fig_lefts, fig_rights = gs.get_grid_positions( + dummy_fig) + + col_span = self._subplotspec.colspan + row_span = self._subplotspec.rowspan + + x0 = fig_lefts[col_span.start] + x1 = fig_rights[col_span.stop - 1] + y0 = fig_bottoms[row_span.stop - 1] + y1 = fig_tops[row_span.start] + if self.bbox_relative is None: - self.bbox_relative = Bbox.from_bounds(x0, y0, dx, dy) + self.bbox_relative = Bbox.from_extents(x0, y0, x1, y1) else: self.bbox_relative.p0 = (x0, y0) - self.bbox_relative.p1 = (x0 + dx, y0 + dy) + self.bbox_relative.p1 = (x1, y1) def get_constrained_layout(self): """ diff --git a/lib/matplotlib/tests/test_figure.py b/lib/matplotlib/tests/test_figure.py index 474331bf9149..124c52c2e8e4 100644 --- a/lib/matplotlib/tests/test_figure.py +++ b/lib/matplotlib/tests/test_figure.py @@ -302,6 +302,60 @@ def test_suptitle_subfigures(): assert sf2.get_facecolor() == (1.0, 1.0, 1.0, 1.0) +def test_subfigures_wspace_spacing(): + fig = plt.figure() + try: + left, right = fig.subfigures(1, 2, wspace=0.2) + + expected_gap = 0.2 / (2 + 0.2 * (2 - 1)) + gap = right.bbox_relative.x0 - left.bbox_relative.x1 + + assert gap == pytest.approx(expected_gap) + assert left.bbox_relative.width == pytest.approx(right.bbox_relative.width) + finally: + plt.close(fig) + + +def test_subfigures_hspace_spacing(): + fig = plt.figure() + try: + top, bottom = fig.subfigures(2, 1, hspace=0.3) + + expected_gap = 0.3 / (2 + 0.3 * (2 - 1)) + gap = top.bbox_relative.y0 - bottom.bbox_relative.y1 + + assert gap == pytest.approx(expected_gap) + assert top.bbox_relative.height == pytest.approx(bottom.bbox_relative.height) + finally: + plt.close(fig) + + +def test_subfigures_default_spacing_none(): + fig = plt.figure() + try: + left, right = fig.subfigures(1, 2) + + gap = right.bbox_relative.x0 - left.bbox_relative.x1 + + assert gap == pytest.approx(0.0) + finally: + plt.close(fig) + + +def test_nested_subfigures_inherit_spacing(): + fig = plt.figure() + try: + left, _ = fig.subfigures(1, 2, wspace=0.1) + top, bottom = left.subfigures(2, 1, hspace=0.25) + + expected_gap = 0.25 / (2 + 0.25 * (2 - 1)) + gap = top.bbox_relative.y0 - bottom.bbox_relative.y1 + + assert gap == pytest.approx(expected_gap) + finally: + plt.close(fig) + + def test_get_suptitle_supxlabel_supylabel(): fig, ax = plt.subplots() assert fig.get_suptitle() == ""