Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit b02334b

Browse files
authored
Merge pull request #23191 from jklymak/enh-add-wr-hr
ENH: add width_ratios and height_ratios to subplots
2 parents d2f87e8 + 8d9ca90 commit b02334b

File tree

5 files changed

+138
-19
lines changed

5 files changed

+138
-19
lines changed
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
``subplots``, ``subplot_mosaic`` accept *height_ratios* and *width_ratios* arguments
2+
------------------------------------------------------------------------------------
3+
4+
The relative width and height of columns and rows in `~.Figure.subplots` and
5+
`~.Figure.subplot_mosaic` can be controlled by passing *height_ratios* and
6+
*width_ratios* keyword arguments to the methods. Previously, this required
7+
passing the ratios in *gridspec_kws* arguments.

lib/matplotlib/figure.py

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -764,7 +764,8 @@ def _add_axes_internal(self, ax, key):
764764
return ax
765765

766766
def subplots(self, nrows=1, ncols=1, *, sharex=False, sharey=False,
767-
squeeze=True, subplot_kw=None, gridspec_kw=None):
767+
squeeze=True, width_ratios=None, height_ratios=None,
768+
subplot_kw=None, gridspec_kw=None):
768769
"""
769770
Add a set of subplots to this figure.
770771
@@ -807,6 +808,18 @@ def subplots(self, nrows=1, ncols=1, *, sharex=False, sharey=False,
807808
is always a 2D array containing Axes instances, even if it ends
808809
up being 1x1.
809810
811+
width_ratios : array-like of length *ncols*, optional
812+
Defines the relative widths of the columns. Each column gets a
813+
relative width of ``width_ratios[i] / sum(width_ratios)``.
814+
If not given, all columns will have the same width. Equivalent
815+
to ``gridspec_kw={'width_ratios': [...]}``.
816+
817+
height_ratios : array-like of length *nrows*, optional
818+
Defines the relative heights of the rows. Each row gets a
819+
relative height of ``height_ratios[i] / sum(height_ratios)``.
820+
If not given, all rows will have the same height. Equivalent
821+
to ``gridspec_kw={'height_ratios': [...]}``.
822+
810823
subplot_kw : dict, optional
811824
Dict with keywords passed to the `.Figure.add_subplot` call used to
812825
create each subplot.
@@ -871,6 +884,17 @@ def subplots(self, nrows=1, ncols=1, *, sharex=False, sharey=False,
871884
"""
872885
if gridspec_kw is None:
873886
gridspec_kw = {}
887+
if height_ratios is not None:
888+
if 'height_ratios' in gridspec_kw:
889+
raise ValueError("'height_ratios' must not be defined both as "
890+
"parameter and as key in 'gridspec_kw'")
891+
gridspec_kw['height_ratios'] = height_ratios
892+
if width_ratios is not None:
893+
if 'width_ratios' in gridspec_kw:
894+
raise ValueError("'width_ratios' must not be defined both as "
895+
"parameter and as key in 'gridspec_kw'")
896+
gridspec_kw['width_ratios'] = width_ratios
897+
874898
gs = self.add_gridspec(nrows, ncols, figure=self, **gridspec_kw)
875899
axs = gs.subplots(sharex=sharex, sharey=sharey, squeeze=squeeze,
876900
subplot_kw=subplot_kw)
@@ -1683,7 +1707,8 @@ def _normalize_grid_string(layout):
16831707
return [list(ln) for ln in layout.strip('\n').split('\n')]
16841708

16851709
def subplot_mosaic(self, mosaic, *, sharex=False, sharey=False,
1686-
subplot_kw=None, gridspec_kw=None, empty_sentinel='.'):
1710+
width_ratios=None, height_ratios=None,
1711+
empty_sentinel='.', subplot_kw=None, gridspec_kw=None):
16871712
"""
16881713
Build a layout of Axes based on ASCII art or nested lists.
16891714
@@ -1739,6 +1764,18 @@ def subplot_mosaic(self, mosaic, *, sharex=False, sharey=False,
17391764
units behave as for `subplots`. If False, each subplot's x- or
17401765
y-axis will be independent.
17411766
1767+
width_ratios : array-like of length *ncols*, optional
1768+
Defines the relative widths of the columns. Each column gets a
1769+
relative width of ``width_ratios[i] / sum(width_ratios)``.
1770+
If not given, all columns will have the same width. Equivalent
1771+
to ``gridspec_kw={'width_ratios': [...]}``.
1772+
1773+
height_ratios : array-like of length *nrows*, optional
1774+
Defines the relative heights of the rows. Each row gets a
1775+
relative height of ``height_ratios[i] / sum(height_ratios)``.
1776+
If not given, all rows will have the same height. Equivalent
1777+
to ``gridspec_kw={'height_ratios': [...]}``.
1778+
17421779
subplot_kw : dict, optional
17431780
Dictionary with keywords passed to the `.Figure.add_subplot` call
17441781
used to create each subplot.
@@ -1763,6 +1800,17 @@ def subplot_mosaic(self, mosaic, *, sharex=False, sharey=False,
17631800
"""
17641801
subplot_kw = subplot_kw or {}
17651802
gridspec_kw = gridspec_kw or {}
1803+
if height_ratios is not None:
1804+
if 'height_ratios' in gridspec_kw:
1805+
raise ValueError("'height_ratios' must not be defined both as "
1806+
"parameter and as key in 'gridspec_kw'")
1807+
gridspec_kw['height_ratios'] = height_ratios
1808+
if width_ratios is not None:
1809+
if 'width_ratios' in gridspec_kw:
1810+
raise ValueError("'width_ratios' must not be defined both as "
1811+
"parameter and as key in 'gridspec_kw'")
1812+
gridspec_kw['width_ratios'] = width_ratios
1813+
17661814
# special-case string input
17671815
if isinstance(mosaic, str):
17681816
mosaic = self._normalize_grid_string(mosaic)

lib/matplotlib/pyplot.py

Lines changed: 36 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1323,6 +1323,7 @@ def subplot(*args, **kwargs):
13231323

13241324

13251325
def subplots(nrows=1, ncols=1, *, sharex=False, sharey=False, squeeze=True,
1326+
width_ratios=None, height_ratios=None,
13261327
subplot_kw=None, gridspec_kw=None, **fig_kw):
13271328
"""
13281329
Create a figure and a set of subplots.
@@ -1368,6 +1369,18 @@ def subplots(nrows=1, ncols=1, *, sharex=False, sharey=False, squeeze=True,
13681369
always a 2D array containing Axes instances, even if it ends up
13691370
being 1x1.
13701371
1372+
width_ratios : array-like of length *ncols*, optional
1373+
Defines the relative widths of the columns. Each column gets a
1374+
relative width of ``width_ratios[i] / sum(width_ratios)``.
1375+
If not given, all columns will have the same width. Equivalent
1376+
to ``gridspec_kw={'width_ratios': [...]}``.
1377+
1378+
height_ratios : array-like of length *nrows*, optional
1379+
Defines the relative heights of the rows. Each row gets a
1380+
relative height of ``height_ratios[i] / sum(height_ratios)``.
1381+
If not given, all rows will have the same height. Convenience
1382+
for ``gridspec_kw={'height_ratios': [...]}``.
1383+
13711384
subplot_kw : dict, optional
13721385
Dict with keywords passed to the
13731386
`~matplotlib.figure.Figure.add_subplot` call used to create each
@@ -1458,13 +1471,14 @@ def subplots(nrows=1, ncols=1, *, sharex=False, sharey=False, squeeze=True,
14581471
fig = figure(**fig_kw)
14591472
axs = fig.subplots(nrows=nrows, ncols=ncols, sharex=sharex, sharey=sharey,
14601473
squeeze=squeeze, subplot_kw=subplot_kw,
1461-
gridspec_kw=gridspec_kw)
1474+
gridspec_kw=gridspec_kw, height_ratios=height_ratios,
1475+
width_ratios=width_ratios)
14621476
return fig, axs
14631477

14641478

14651479
def subplot_mosaic(mosaic, *, sharex=False, sharey=False,
1466-
subplot_kw=None, gridspec_kw=None, empty_sentinel='.',
1467-
**fig_kw):
1480+
width_ratios=None, height_ratios=None, empty_sentinel='.',
1481+
subplot_kw=None, gridspec_kw=None, **fig_kw):
14681482
"""
14691483
Build a layout of Axes based on ASCII art or nested lists.
14701484
@@ -1515,20 +1529,32 @@ def subplot_mosaic(mosaic, *, sharex=False, sharey=False,
15151529
behave as for `subplots`. If False, each subplot's x- or y-axis will
15161530
be independent.
15171531
1518-
subplot_kw : dict, optional
1519-
Dictionary with keywords passed to the `.Figure.add_subplot` call
1520-
used to create each subplot.
1532+
width_ratios : array-like of length *ncols*, optional
1533+
Defines the relative widths of the columns. Each column gets a
1534+
relative width of ``width_ratios[i] / sum(width_ratios)``.
1535+
If not given, all columns will have the same width. Convenience
1536+
for ``gridspec_kw={'width_ratios': [...]}``.
15211537
1522-
gridspec_kw : dict, optional
1523-
Dictionary with keywords passed to the `.GridSpec` constructor used
1524-
to create the grid the subplots are placed on.
1538+
height_ratios : array-like of length *nrows*, optional
1539+
Defines the relative heights of the rows. Each row gets a
1540+
relative height of ``height_ratios[i] / sum(height_ratios)``.
1541+
If not given, all rows will have the same height. Convenience
1542+
for ``gridspec_kw={'height_ratios': [...]}``.
15251543
15261544
empty_sentinel : object, optional
15271545
Entry in the layout to mean "leave this space empty". Defaults
15281546
to ``'.'``. Note, if *layout* is a string, it is processed via
15291547
`inspect.cleandoc` to remove leading white space, which may
15301548
interfere with using white-space as the empty sentinel.
15311549
1550+
subplot_kw : dict, optional
1551+
Dictionary with keywords passed to the `.Figure.add_subplot` call
1552+
used to create each subplot.
1553+
1554+
gridspec_kw : dict, optional
1555+
Dictionary with keywords passed to the `.GridSpec` constructor used
1556+
to create the grid the subplots are placed on.
1557+
15321558
**fig_kw
15331559
All additional keyword arguments are passed to the
15341560
`.pyplot.figure` call.
@@ -1547,6 +1573,7 @@ def subplot_mosaic(mosaic, *, sharex=False, sharey=False,
15471573
fig = figure(**fig_kw)
15481574
ax_dict = fig.subplot_mosaic(
15491575
mosaic, sharex=sharex, sharey=sharey,
1576+
height_ratios=height_ratios, width_ratios=width_ratios,
15501577
subplot_kw=subplot_kw, gridspec_kw=gridspec_kw,
15511578
empty_sentinel=empty_sentinel
15521579
)

lib/matplotlib/tests/test_subplots.py

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import pytest
55

66
import matplotlib.pyplot as plt
7-
from matplotlib.testing.decorators import image_comparison
7+
from matplotlib.testing.decorators import check_figures_equal, image_comparison
88
import matplotlib.axes as maxes
99

1010

@@ -212,3 +212,42 @@ def test_dont_mutate_kwargs():
212212
def test_subplot_factory_reapplication():
213213
assert maxes.subplot_class_factory(maxes.Axes) is maxes.Subplot
214214
assert maxes.subplot_class_factory(maxes.Subplot) is maxes.Subplot
215+
216+
217+
@pytest.mark.parametrize("width_ratios", [None, [1, 3, 2]])
218+
@pytest.mark.parametrize("height_ratios", [None, [1, 2]])
219+
@check_figures_equal(extensions=['png'])
220+
def test_width_and_height_ratios(fig_test, fig_ref,
221+
height_ratios, width_ratios):
222+
fig_test.subplots(2, 3, height_ratios=height_ratios,
223+
width_ratios=width_ratios)
224+
fig_ref.subplots(2, 3, gridspec_kw={
225+
'height_ratios': height_ratios,
226+
'width_ratios': width_ratios})
227+
228+
229+
@pytest.mark.parametrize("width_ratios", [None, [1, 3, 2]])
230+
@pytest.mark.parametrize("height_ratios", [None, [1, 2]])
231+
@check_figures_equal(extensions=['png'])
232+
def test_width_and_height_ratios_mosaic(fig_test, fig_ref,
233+
height_ratios, width_ratios):
234+
mosaic_spec = [['A', 'B', 'B'], ['A', 'C', 'D']]
235+
fig_test.subplot_mosaic(mosaic_spec, height_ratios=height_ratios,
236+
width_ratios=width_ratios)
237+
fig_ref.subplot_mosaic(mosaic_spec, gridspec_kw={
238+
'height_ratios': height_ratios,
239+
'width_ratios': width_ratios})
240+
241+
242+
@pytest.mark.parametrize('method,args', [
243+
('subplots', (2, 3)),
244+
('subplot_mosaic', ('abc;def', ))
245+
]
246+
)
247+
def test_ratio_overlapping_kws(method, args):
248+
with pytest.raises(ValueError, match='height_ratios'):
249+
getattr(plt, method)(*args, height_ratios=[1, 2],
250+
gridspec_kw={'height_ratios': [1, 2]})
251+
with pytest.raises(ValueError, match='width_ratios'):
252+
getattr(plt, method)(*args, width_ratios=[1, 2, 3],
253+
gridspec_kw={'width_ratios': [1, 2, 3]})

tutorials/provisional/mosaic.py

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -219,12 +219,10 @@ def identify_axes(ax_dict, fontsize=48):
219219
bAc
220220
.d.
221221
""",
222-
gridspec_kw={
223-
# set the height ratios between the rows
224-
"height_ratios": [1, 3.5, 1],
225-
# set the width ratios between the columns
226-
"width_ratios": [1, 3.5, 1],
227-
},
222+
# set the height ratios between the rows
223+
height_ratios=[1, 3.5, 1],
224+
# set the width ratios between the columns
225+
width_ratios=[1, 3.5, 1],
228226
)
229227
identify_axes(axd)
230228

@@ -301,7 +299,7 @@ def identify_axes(ax_dict, fontsize=48):
301299
["main", "BLANK"],
302300
],
303301
empty_sentinel="BLANK",
304-
gridspec_kw={"width_ratios": [2, 1]},
302+
width_ratios=[2, 1],
305303
)
306304
identify_axes(axd)
307305

0 commit comments

Comments
 (0)