Skip to content

Commit e051583

Browse files
authored
Merge pull request matplotlib#25960 from rcomer/subfigure-spacing
FIX: wspace and hspace in subfigures without layout engine
2 parents a63ff73 + 5d9c630 commit e051583

File tree

2 files changed

+40
-3
lines changed

2 files changed

+40
-3
lines changed

lib/matplotlib/figure.py

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1553,8 +1553,9 @@ def subfigures(self, nrows=1, ncols=1, squeeze=True,
15531553
wspace, hspace : float, default: None
15541554
The amount of width/height reserved for space between subfigures,
15551555
expressed as a fraction of the average subfigure width/height.
1556-
If not given, the values will be inferred from a figure or
1557-
rcParams when necessary.
1556+
If not given, the values will be inferred from rcParams if using
1557+
constrained layout (see `~.ConstrainedLayoutEngine`), or zero if
1558+
not using a layout engine.
15581559
15591560
width_ratios : array-like of length *ncols*, optional
15601561
Defines the relative widths of the columns. Each column gets a
@@ -1569,13 +1570,24 @@ def subfigures(self, nrows=1, ncols=1, squeeze=True,
15691570
gs = GridSpec(nrows=nrows, ncols=ncols, figure=self,
15701571
wspace=wspace, hspace=hspace,
15711572
width_ratios=width_ratios,
1572-
height_ratios=height_ratios)
1573+
height_ratios=height_ratios,
1574+
left=0, right=1, bottom=0, top=1)
15731575

15741576
sfarr = np.empty((nrows, ncols), dtype=object)
15751577
for i in range(ncols):
15761578
for j in range(nrows):
15771579
sfarr[j, i] = self.add_subfigure(gs[j, i], **kwargs)
15781580

1581+
if self.get_layout_engine() is None and (wspace is not None or
1582+
hspace is not None):
1583+
# Gridspec wspace and hspace is ignored on subfigure instantiation,
1584+
# and no space is left. So need to account for it here if required.
1585+
bottoms, tops, lefts, rights = gs.get_grid_positions(self)
1586+
for sfrow, bottom, top in zip(sfarr, bottoms, tops):
1587+
for sf, left, right in zip(sfrow, lefts, rights):
1588+
bbox = Bbox.from_extents(left, bottom, right, top)
1589+
sf._redo_transform_rel_fig(bbox=bbox)
1590+
15791591
if squeeze:
15801592
# Discarding unneeded dimensions that equal 1. If we only have one
15811593
# subfigure, just return it instead of a 1-element array.

lib/matplotlib/tests/test_figure.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1449,6 +1449,31 @@ def test_subfigure_pdf():
14491449
fig.savefig(buffer, format='pdf')
14501450

14511451

1452+
def test_subfigures_wspace_hspace():
1453+
sub_figs = plt.figure().subfigures(2, 3, hspace=0.5, wspace=1/6.)
1454+
1455+
w = 640
1456+
h = 480
1457+
1458+
np.testing.assert_allclose(sub_figs[0, 0].bbox.min, [0., h * 0.6])
1459+
np.testing.assert_allclose(sub_figs[0, 0].bbox.max, [w * 0.3, h])
1460+
1461+
np.testing.assert_allclose(sub_figs[0, 1].bbox.min, [w * 0.35, h * 0.6])
1462+
np.testing.assert_allclose(sub_figs[0, 1].bbox.max, [w * 0.65, h])
1463+
1464+
np.testing.assert_allclose(sub_figs[0, 2].bbox.min, [w * 0.7, h * 0.6])
1465+
np.testing.assert_allclose(sub_figs[0, 2].bbox.max, [w, h])
1466+
1467+
np.testing.assert_allclose(sub_figs[1, 0].bbox.min, [0, 0])
1468+
np.testing.assert_allclose(sub_figs[1, 0].bbox.max, [w * 0.3, h * 0.4])
1469+
1470+
np.testing.assert_allclose(sub_figs[1, 1].bbox.min, [w * 0.35, 0])
1471+
np.testing.assert_allclose(sub_figs[1, 1].bbox.max, [w * 0.65, h * 0.4])
1472+
1473+
np.testing.assert_allclose(sub_figs[1, 2].bbox.min, [w * 0.7, 0])
1474+
np.testing.assert_allclose(sub_figs[1, 2].bbox.max, [w, h * 0.4])
1475+
1476+
14521477
def test_add_subplot_kwargs():
14531478
# fig.add_subplot() always creates new axes, even if axes kwargs differ.
14541479
fig = plt.figure()

0 commit comments

Comments
 (0)