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