Repository: matplotlib/matplotlib

Issue:
[Bug]: subfigures are added in column major order
### Bug summary

subplots() adds axes in row-major order, but subfigures() add subfigures in column-major order

### Code for reproduction

```Python
from pylab import *

f = figure()
f.subplots(3, 3)
for i, ax in enumerate(f.axes): ax.set_title(i)
savefig("/tmp/subplots.png")

f = figure()
f.subfigures(3, 3)
for i, sf in enumerate(f.subfigs): sf.suptitle(i)
savefig("/tmp/subfigures.png")
```


### Actual outcome

subplots
![subplots](https://github.com/matplotlib/matplotlib/assets/1322974/0f972af4-492c-4621-941b-440cd9dab208)

subfigures
![subfigures](https://github.com/matplotlib/matplotlib/assets/1322974/56b98e97-2b2c-476f-acd7-e9ebe2716ecb)


### Expected outcome

Subfigures are added in row-major axis, per standard numpy defaults.

### Additional information

In practice this should rarely matter, as the subfigures don't overlap so drawing order should be irrelevant... perhaps unless some artists are positioned beyond the subfigure edge and not clipped.

The behavior directly arises from the iteration in subfigures:
```python
        sfarr = np.empty((nrows, ncols), dtype=object)
        for i in range(ncols):
            for j in range(nrows):
                sfarr[j, i] = self.add_subfigure(gs[j, i], **kwargs)
```

### Operating system

macOS

### Matplotlib Version

3.10.0.dev233+ga833d99e46

### Matplotlib Backend

qtagg

### Python version

3.12

### Jupyter version

no

### Installation

git checkout


Discussion:
I am in favor of flipping `subfigures` to match `subplots`.   I think this is a case where we can not warn, but should just do it (and clearly document it).  I hope this won't bite too many people who are relying on the iteration order and get us out of explaining why it is different forever.
It should also be noted that subfigures as of 3.9 (I think) now respect z-order so you can move them up and down if you have to.



Patch:
diff --git a/doc/api/next_api_changes/behavior/28363-TS.rst b/doc/api/next_api_changes/behavior/28363-TS.rst
new file mode 100644
index 000000000000..2242f3929e04
--- /dev/null
+++ b/doc/api/next_api_changes/behavior/28363-TS.rst
@@ -0,0 +1,6 @@
+Subfigures
+~~~~~~~~~~
+
+`.Figure.subfigures` are now added in row-major order to be consistent with
+`.Figure.subplots`.  The return value of `~.Figure.subfigures` is not changed,
+but the order of ``fig.subfigs`` is.
diff --git a/doc/users/next_whats_new/subfigures_change_order.rst b/doc/users/next_whats_new/subfigures_change_order.rst
new file mode 100644
index 000000000000..49a018a3fd96
--- /dev/null
+++ b/doc/users/next_whats_new/subfigures_change_order.rst
@@ -0,0 +1,23 @@
+Subfigures are now added in row-major order
+-------------------------------------------
+
+``Figure.subfigures`` are now added in row-major order for API consistency.
+
+
+.. plot::
+    :include-source: true
+    :alt: Example of creating 3 by 3 subfigures.
+
+    import matplotlib.pyplot as plt
+
+    fig = plt.figure()
+    subfigs = fig.subfigures(3, 3)
+    x = np.linspace(0, 10, 100)
+
+    for i, sf in enumerate(fig.subfigs):
+        ax = sf.subplots()
+        ax.plot(x, np.sin(x + i), label=f'Subfigure {i+1}')
+        sf.suptitle(f'Subfigure {i+1}')
+        ax.set_xticks([])
+        ax.set_yticks([])
+    plt.show()
diff --git a/lib/matplotlib/figure.py b/lib/matplotlib/figure.py
index 0a0ff01a2571..0aa90e716b1c 100644
--- a/lib/matplotlib/figure.py
+++ b/lib/matplotlib/figure.py
@@ -1550,6 +1550,9 @@ def subfigures(self, nrows=1, ncols=1, squeeze=True,
         .. note::
             The *subfigure* concept is new in v3.4, and the API is still provisional.
 
+        .. versionchanged:: 3.10
+            subfigures are now added in row-major order.
+
         Parameters
         ----------
         nrows, ncols : int, default: 1
@@ -1583,9 +1586,9 @@ def subfigures(self, nrows=1, ncols=1, squeeze=True,
                       left=0, right=1, bottom=0, top=1)
 
         sfarr = np.empty((nrows, ncols), dtype=object)
-        for i in range(ncols):
-            for j in range(nrows):
-                sfarr[j, i] = self.add_subfigure(gs[j, i], **kwargs)
+        for i in range(nrows):
+            for j in range(ncols):
+                sfarr[i, j] = self.add_subfigure(gs[i, j], **kwargs)
 
         if self.get_layout_engine() is None and (wspace is not None or
                                                  hspace is not None):


Test patch:
diff --git a/lib/matplotlib/tests/test_figure.py b/lib/matplotlib/tests/test_figure.py
index 58aecd3dea8b..e8edcf61815d 100644
--- a/lib/matplotlib/tests/test_figure.py
+++ b/lib/matplotlib/tests/test_figure.py
@@ -1733,3 +1733,11 @@ def test_warn_colorbar_mismatch():
     subfig3_1.colorbar(im3_2)   # should not warn
     with pytest.warns(UserWarning, match="different Figure"):
         subfig3_1.colorbar(im4_1)
+
+
+def test_subfigure_row_order():
+    # Test that subfigures are drawn in row-major order.
+    fig = plt.figure()
+    sf_arr = fig.subfigures(4, 3)
+    for a, b in zip(sf_arr.ravel(), fig.subfigs):
+        assert a is b