Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions doc/whats-new.rst
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ Deprecations
Bug Fixes
~~~~~~~~~

- Treat a full ``MultiIndex`` key with tuple-valued levels as scalar selection,
so ``.sel`` no longer preserves a length-1 dimension for nested tuple keys
that identify a single row (:issue:`11341`).
- Fix a major performance regression in :py:meth:`Coordinates.to_index` (and
consequently :py:meth:`Dataset.to_dataframe`) caused by converting the cached
code ndarrays into Python lists (:issue:`11305`).
Expand Down
11 changes: 8 additions & 3 deletions xarray/core/indexes.py
Original file line number Diff line number Diff line change
Expand Up @@ -1366,10 +1366,15 @@ def sel(self, labels, method=None, tolerance=None) -> IndexSelResult:
indexer = _query_slice(self.index, label, coord_name)

elif isinstance(label, tuple):
if _is_nested_tuple(label):
if len(label) == self.index.nlevels:
try:
indexer = self.index.get_loc(label)
except (KeyError, TypeError, pd.errors.InvalidIndexError):
if not _is_nested_tuple(label):
raise
indexer = self.index.get_locs(label)
elif _is_nested_tuple(label):
indexer = self.index.get_locs(label)
elif len(label) == self.index.nlevels:
indexer = self.index.get_loc(label)
else:
levels = [self.index.names[i] for i in range(len(label))]
indexer, new_index = self.index.get_loc_level(label, level=levels)
Expand Down
14 changes: 14 additions & 0 deletions xarray/tests/test_dataarray.py
Original file line number Diff line number Diff line change
Expand Up @@ -1463,6 +1463,20 @@ def test_sel(

assert_identical(mdata.sel(x={"one": "a", "two": 1}), mdata.sel(one="a", two=1))

def test_selection_multiindex_nested_tuple_level_value(self) -> None:
level_0 = pd.Index(
[(1, 1), (1, 1), (2, 2), (3, 3)], name="a", tupleize_cols=False
)
level_1 = pd.Index([1, 2, 10, 20], name="b")
midx = pd.MultiIndex.from_arrays([level_0, level_1])
coords = Coordinates.from_pandas_multiindex(midx, "index")
data = DataArray(np.arange(4), dims=("index",), coords=coords)

actual = data.sel(index=((1, 1), 2))
expected = data.isel(index=1)

assert_identical(actual, expected)

def test_selection_multiindex_remove_unused(self) -> None:
# GH2619. For MultiIndex, we need to call remove_unused.
ds = xr.DataArray(
Expand Down
Loading