Skip to content

Commit e8a284f

Browse files
authored
Allow ellipsis to be used in stack (#3826)
* allow ellipsis to be used in stack * doc fix * support ellipsis only as part of an iterable * docs * whatsnew * docstring, whatsnew * docstring, whatsnew * add passing a partial list of dims * more wording changes * improvement from @dcherian
1 parent 5548c1e commit e8a284f

File tree

6 files changed

+39
-4
lines changed

6 files changed

+39
-4
lines changed

doc/reshaping.rst

+8
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,13 @@ implemented :py:meth:`~xarray.DataArray.stack` and
109109
stacked
110110
stacked.unstack('z')
111111
112+
As elsewhere in xarray, an ellipsis (`...`) can be used to represent all unlisted dimensions:
113+
114+
.. ipython:: python
115+
116+
stacked = array.stack(z=[..., "x"])
117+
stacked
118+
112119
These methods are modeled on the :py:class:`pandas.DataFrame` methods of the
113120
same name, although in xarray they always create new dimensions rather than
114121
adding to the existing index or columns.
@@ -164,6 +171,7 @@ like this:
164171
'b': ('x', [6, 7])},
165172
coords={'y': ['u', 'v', 'w']}
166173
)
174+
data
167175
stacked = data.to_stacked_array("z", sample_dims=['x'])
168176
stacked
169177
unstacked = stacked.to_unstacked_dataset("z")

doc/whats-new.rst

+8-2
Original file line numberDiff line numberDiff line change
@@ -39,13 +39,19 @@ New Features
3939
By `Justus Magin <https://github.com/keewis>`_.
4040
- :py:meth:`Dataset.groupby` and :py:meth:`DataArray.groupby` now raise a
4141
`TypeError` on multiple string arguments. Receiving multiple string arguments
42-
often means a user is attempting to pass multiple dimensions to group over
43-
and should instead pass a list.
42+
often means a user is attempting to pass multiple dimensions as separate
43+
arguments and should instead pass a single list of dimensions.
44+
(:pull:`3802`)
4445
By `Maximilian Roos <https://github.com/max-sixty>`_
4546
- The new ``Dataset._repr_html_`` and ``DataArray._repr_html_`` (introduced
4647
in 0.14.1) is now on by default. To disable, use
4748
``xarray.set_options(display_style="text")``.
4849
By `Julia Signell <https://github.com/jsignell>`_.
50+
- An ellipsis (``...``) is now supported in the ``dims`` argument of
51+
:py:meth:`Dataset.stack` and :py:meth:`DataArray.stack`, meaning all
52+
unlisted dimensions, similar to its meaning in :py:meth:`DataArray.transpose`.
53+
(:pull:`3826`)
54+
By `Maximilian Roos <https://github.com/max-sixty>`_
4955
- :py:meth:`Dataset.where` and :py:meth:`DataArray.where` accept a lambda as a
5056
first argument, which is then called on the input; replicating pandas' behavior.
5157
By `Maximilian Roos <https://github.com/max-sixty>`_.

xarray/core/dataarray.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -1709,7 +1709,9 @@ def stack(
17091709
----------
17101710
dimensions : Mapping of the form new_name=(dim1, dim2, ...)
17111711
Names of new dimensions, and the existing dimensions that they
1712-
replace.
1712+
replace. An ellipsis (`...`) will be replaced by all unlisted dimensions.
1713+
Passing a list containing an ellipsis (`stacked_dim=[...]`) will stack over
1714+
all dimensions.
17131715
**dimensions_kwargs:
17141716
The keyword arguments form of ``dimensions``.
17151717
One of dimensions or dimensions_kwargs must be provided.

xarray/core/dataset.py

+6-1
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@
8787
decode_numpy_dict_values,
8888
either_dict_or_kwargs,
8989
hashable,
90+
infix_dims,
9091
is_dict_like,
9192
is_scalar,
9293
maybe_wrap_array,
@@ -3262,6 +3263,8 @@ def reorder_levels(
32623263
return self._replace(variables, indexes=indexes)
32633264

32643265
def _stack_once(self, dims, new_dim):
3266+
if ... in dims:
3267+
dims = list(infix_dims(dims, self.dims))
32653268
variables = {}
32663269
for name, var in self.variables.items():
32673270
if name not in dims:
@@ -3304,7 +3307,9 @@ def stack(
33043307
----------
33053308
dimensions : Mapping of the form new_name=(dim1, dim2, ...)
33063309
Names of new dimensions, and the existing dimensions that they
3307-
replace.
3310+
replace. An ellipsis (`...`) will be replaced by all unlisted dimensions.
3311+
Passing a list containing an ellipsis (`stacked_dim=[...]`) will stack over
3312+
all dimensions.
33083313
**dimensions_kwargs:
33093314
The keyword arguments form of ``dimensions``.
33103315
One of dimensions or dimensions_kwargs must be provided.

xarray/tests/test_dataarray.py

+3
Original file line numberDiff line numberDiff line change
@@ -2040,6 +2040,9 @@ def test_stack_unstack(self):
20402040
actual = orig.stack(z=["x", "y"]).unstack("z").drop_vars(["x", "y"])
20412041
assert_identical(orig, actual)
20422042

2043+
actual = orig.stack(z=[...]).unstack("z").drop_vars(["x", "y"])
2044+
assert_identical(orig, actual)
2045+
20432046
dims = ["a", "b", "c", "d", "e"]
20442047
orig = xr.DataArray(np.random.rand(1, 2, 3, 2, 1), dims=dims)
20452048
stacked = orig.stack(ab=["a", "b"], cd=["c", "d"])

xarray/tests/test_dataset.py

+11
Original file line numberDiff line numberDiff line change
@@ -2879,6 +2879,17 @@ def test_stack(self):
28792879
actual = ds.stack(z=["x", "y"])
28802880
assert_identical(expected, actual)
28812881

2882+
actual = ds.stack(z=[...])
2883+
assert_identical(expected, actual)
2884+
2885+
# non list dims with ellipsis
2886+
actual = ds.stack(z=(...,))
2887+
assert_identical(expected, actual)
2888+
2889+
# ellipsis with given dim
2890+
actual = ds.stack(z=[..., "y"])
2891+
assert_identical(expected, actual)
2892+
28822893
exp_index = pd.MultiIndex.from_product([["a", "b"], [0, 1]], names=["y", "x"])
28832894
expected = Dataset(
28842895
{"a": ("z", [0, 1, 0, 1]), "b": ("z", [0, 2, 1, 3]), "z": exp_index}

0 commit comments

Comments
 (0)