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

Skip to content

Commit fb60d34

Browse files
committed
FIX: add subplot_mosaic axes in the order the user gave them to us
The order the Axes are added to the Figure (and hence the order they are in the returned dictionary and fig.axes) is now based on the first time we see the key if the layout were recursively unraveled as a c-style array. Closes #19736
1 parent 5288e0c commit fb60d34

File tree

2 files changed

+55
-22
lines changed

2 files changed

+55
-22
lines changed

lib/matplotlib/figure.py

Lines changed: 38 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1785,11 +1785,12 @@ def _identify_keys_and_nested(layout):
17851785
17861786
Returns
17871787
-------
1788-
unique_ids : set
1788+
unique_ids : tuple
17891789
The unique non-sub layout entries in this layout
17901790
nested : dict[tuple[int, int]], 2D object array
17911791
"""
1792-
unique_ids = set()
1792+
# make sure we preserve the user supplied order
1793+
unique_ids = cbook._OrderedSet()
17931794
nested = {}
17941795
for j, row in enumerate(layout):
17951796
for k, v in enumerate(row):
@@ -1800,7 +1801,7 @@ def _identify_keys_and_nested(layout):
18001801
else:
18011802
unique_ids.add(v)
18021803

1803-
return unique_ids, nested
1804+
return tuple(unique_ids), nested
18041805

18051806
def _do_layout(gs, layout, unique_ids, nested):
18061807
"""
@@ -1811,7 +1812,7 @@ def _do_layout(gs, layout, unique_ids, nested):
18111812
gs : GridSpec
18121813
layout : 2D object array
18131814
The input converted to a 2D numpy array for this level.
1814-
unique_ids : set
1815+
unique_ids : tuple
18151816
The identified scalar labels at this level of nesting.
18161817
nested : dict[tuple[int, int]], 2D object array
18171818
The identified nested layouts, if any.
@@ -1824,6 +1825,8 @@ def _do_layout(gs, layout, unique_ids, nested):
18241825
rows, cols = layout.shape
18251826
output = dict()
18261827

1828+
this_level = dict()
1829+
18271830
# create the Axes at this level of nesting
18281831
for name in unique_ids:
18291832
indx = np.argwhere(layout == name)
@@ -1836,26 +1839,39 @@ def _do_layout(gs, layout, unique_ids, nested):
18361839
f"While trying to layout\n{layout!r}\n"
18371840
f"we found that the label {name!r} specifies a "
18381841
"non-rectangular or non-contiguous area.")
1842+
this_level[(start_row, start_col)] = (name, slc, 'axes')
18391843

1840-
ax = self.add_subplot(
1841-
gs[slc], **{'label': str(name), **subplot_kw}
1842-
)
1843-
output[name] = ax
1844-
1845-
# do any sub-layouts
18461844
for (j, k), nested_layout in nested.items():
1847-
rows, cols = nested_layout.shape
1848-
nested_output = _do_layout(
1849-
gs[j, k].subgridspec(rows, cols, **gridspec_kw),
1850-
nested_layout,
1851-
*_identify_keys_and_nested(nested_layout)
1852-
)
1853-
overlap = set(output) & set(nested_output)
1854-
if overlap:
1855-
raise ValueError(f"There are duplicate keys {overlap} "
1856-
f"between the outer layout\n{layout!r}\n"
1857-
f"and the nested layout\n{nested_layout}")
1858-
output.update(nested_output)
1845+
this_level[(j, k)] = (None, nested_layout, 'nested')
1846+
1847+
for key in sorted(this_level):
1848+
name, arg, method = this_level[key]
1849+
if method == 'axes':
1850+
slc = arg
1851+
if name in output:
1852+
raise ValueError(f"There are duplicate keys {name} "
1853+
f"in the layout\n{layout!r}")
1854+
ax = self.add_subplot(
1855+
gs[slc], **{'label': str(name), **subplot_kw}
1856+
)
1857+
output[name] = ax
1858+
elif method == 'nested':
1859+
nested_layout = arg
1860+
j, k = key
1861+
rows, cols = nested_layout.shape
1862+
nested_output = _do_layout(
1863+
gs[j, k].subgridspec(rows, cols, **gridspec_kw),
1864+
nested_layout,
1865+
*_identify_keys_and_nested(nested_layout)
1866+
)
1867+
overlap = set(output) & set(nested_output)
1868+
if overlap:
1869+
raise ValueError(
1870+
f"There are duplicate keys {overlap} "
1871+
f"between the outer layout\n{layout!r}\n"
1872+
f"and the nested layout\n{nested_layout}"
1873+
)
1874+
output.update(nested_output)
18591875
return output
18601876

18611877
layout = _make_array(layout)

lib/matplotlib/tests/test_figure.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -861,6 +861,23 @@ def test_hashable_keys(self, fig_test, fig_ref):
861861
fig_test.subplot_mosaic([[object(), object()]])
862862
fig_ref.subplot_mosaic([["A", "B"]])
863863

864+
@pytest.mark.parametrize('str_pattern',
865+
['abc', 'cab', 'bca', 'cba', 'acb', 'bac'])
866+
def test_user_order(self, str_pattern):
867+
fig = plt.figure()
868+
ax_dict = fig.subplot_mosaic(str_pattern)
869+
assert list(str_pattern) == list(ax_dict)
870+
assert list(fig.axes) == list(ax_dict.values())
871+
872+
def test_nested_user_order(self):
873+
layout = [["A", [["B", "C"], ["D", "E"]]],
874+
["F", "G"]]
875+
876+
fig = plt.figure()
877+
ax_dict = fig.subplot_mosaic(layout)
878+
assert list(ax_dict) == list("ABCDEFG")
879+
assert list(fig.axes) == list(ax_dict.values())
880+
864881

865882
def test_reused_gridspec():
866883
"""Test that these all use the same gridspec"""

0 commit comments

Comments
 (0)