@@ -1791,11 +1791,12 @@ def _identify_keys_and_nested(layout):
1791
1791
1792
1792
Returns
1793
1793
-------
1794
- unique_ids : set
1794
+ unique_ids : tuple
1795
1795
The unique non-sub layout entries in this layout
1796
1796
nested : dict[tuple[int, int]], 2D object array
1797
1797
"""
1798
- unique_ids = set ()
1798
+ # make sure we preserve the user supplied order
1799
+ unique_ids = cbook ._OrderedSet ()
1799
1800
nested = {}
1800
1801
for j , row in enumerate (layout ):
1801
1802
for k , v in enumerate (row ):
@@ -1806,7 +1807,7 @@ def _identify_keys_and_nested(layout):
1806
1807
else :
1807
1808
unique_ids .add (v )
1808
1809
1809
- return unique_ids , nested
1810
+ return tuple ( unique_ids ) , nested
1810
1811
1811
1812
def _do_layout (gs , layout , unique_ids , nested ):
1812
1813
"""
@@ -1817,7 +1818,7 @@ def _do_layout(gs, layout, unique_ids, nested):
1817
1818
gs : GridSpec
1818
1819
layout : 2D object array
1819
1820
The input converted to a 2D numpy array for this level.
1820
- unique_ids : set
1821
+ unique_ids : tuple
1821
1822
The identified scalar labels at this level of nesting.
1822
1823
nested : dict[tuple[int, int]], 2D object array
1823
1824
The identified nested layouts, if any.
@@ -1830,38 +1831,74 @@ def _do_layout(gs, layout, unique_ids, nested):
1830
1831
rows , cols = layout .shape
1831
1832
output = dict ()
1832
1833
1833
- # create the Axes at this level of nesting
1834
+ # we need to merge together the Axes at this level and the axes
1835
+ # in the (recursively) nested sub-layouts so that we can add
1836
+ # them to the figure in the "natural" order if you were to
1837
+ # ravel in c-order all of the Axes that will be created
1838
+ #
1839
+ # This will stash the upper left index of each object (axes or
1840
+ # nested layout) at this level
1841
+ this_level = dict ()
1842
+
1843
+ # go through the unique keys,
1834
1844
for name in unique_ids :
1845
+ # sort out where each axes starts/ends
1835
1846
indx = np .argwhere (layout == name )
1836
1847
start_row , start_col = np .min (indx , axis = 0 )
1837
1848
end_row , end_col = np .max (indx , axis = 0 ) + 1
1849
+ # and construct the slice object
1838
1850
slc = (slice (start_row , end_row ), slice (start_col , end_col ))
1839
-
1851
+ # some light error checking
1840
1852
if (layout [slc ] != name ).any ():
1841
1853
raise ValueError (
1842
1854
f"While trying to layout\n { layout !r} \n "
1843
1855
f"we found that the label { name !r} specifies a "
1844
1856
"non-rectangular or non-contiguous area." )
1857
+ # and stash this slice for later
1858
+ this_level [(start_row , start_col )] = (name , slc , 'axes' )
1845
1859
1846
- ax = self .add_subplot (
1847
- gs [slc ], ** {'label' : str (name ), ** subplot_kw }
1848
- )
1849
- output [name ] = ax
1850
-
1851
- # do any sub-layouts
1860
+ # do the same thing for the nested layouts (simpler because these
1861
+ # can not be spans yet!)
1852
1862
for (j , k ), nested_layout in nested .items ():
1853
- rows , cols = nested_layout .shape
1854
- nested_output = _do_layout (
1855
- gs [j , k ].subgridspec (rows , cols , ** gridspec_kw ),
1856
- nested_layout ,
1857
- * _identify_keys_and_nested (nested_layout )
1858
- )
1859
- overlap = set (output ) & set (nested_output )
1860
- if overlap :
1861
- raise ValueError (f"There are duplicate keys { overlap } "
1862
- f"between the outer layout\n { layout !r} \n "
1863
- f"and the nested layout\n { nested_layout } " )
1864
- output .update (nested_output )
1863
+ this_level [(j , k )] = (None , nested_layout , 'nested' )
1864
+
1865
+ # now go through the things in this level and add them
1866
+ # in order left-to-right top-to-bottom
1867
+ for key in sorted (this_level ):
1868
+ name , arg , method = this_level [key ]
1869
+ # we are doing some hokey function dispatch here based
1870
+ # on the 'method' string stashed above to sort out if this
1871
+ # element is an axes or a nested layout.
1872
+ if method == 'axes' :
1873
+ slc = arg
1874
+ # add a single axes
1875
+ if name in output :
1876
+ raise ValueError (f"There are duplicate keys { name } "
1877
+ f"in the layout\n { layout !r} " )
1878
+ ax = self .add_subplot (
1879
+ gs [slc ], ** {'label' : str (name ), ** subplot_kw }
1880
+ )
1881
+ output [name ] = ax
1882
+ elif method == 'nested' :
1883
+ nested_layout = arg
1884
+ j , k = key
1885
+ # recursively add the nested layout
1886
+ rows , cols = nested_layout .shape
1887
+ nested_output = _do_layout (
1888
+ gs [j , k ].subgridspec (rows , cols , ** gridspec_kw ),
1889
+ nested_layout ,
1890
+ * _identify_keys_and_nested (nested_layout )
1891
+ )
1892
+ overlap = set (output ) & set (nested_output )
1893
+ if overlap :
1894
+ raise ValueError (
1895
+ f"There are duplicate keys { overlap } "
1896
+ f"between the outer layout\n { layout !r} \n "
1897
+ f"and the nested layout\n { nested_layout } "
1898
+ )
1899
+ output .update (nested_output )
1900
+ else :
1901
+ raise RuntimeError ("This should never happen" )
1865
1902
return output
1866
1903
1867
1904
layout = _make_array (layout )
0 commit comments