diff --git a/xarray/core/coordinates.py b/xarray/core/coordinates.py index 28cbc5b7622..0886e07b41b 100644 --- a/xarray/core/coordinates.py +++ b/xarray/core/coordinates.py @@ -24,6 +24,7 @@ from xarray.core.types import DataVars, Self, T_DataArray, T_Xarray from xarray.core.utils import ( Frozen, + FrozenMappingWarningOnValuesAccess, ReprObject, either_dict_or_kwargs, emit_user_level_warning, @@ -111,12 +112,13 @@ def to_dataset(self) -> Dataset: raise NotImplementedError() def to_index(self, ordered_dims: Sequence[Hashable] | None = None) -> pd.Index: - """Convert all index coordinates into a :py:class:`pandas.Index`. + """Convert all index dimension coordinates into a :py:class:`pandas.Index`. Parameters ---------- ordered_dims : sequence of hashable, optional - Possibly reordered version of this object's dimensions indicating + Possibly reordered version of this object's dimensions (or the full dimensions + of it's corresponding Dataset, DataArray or DataTree object) indicating the order in which dimensions should appear on the result. Returns @@ -124,14 +126,14 @@ def to_index(self, ordered_dims: Sequence[Hashable] | None = None) -> pd.Index: pandas.Index Index subclass corresponding to the outer-product of all dimension coordinates. This will be a MultiIndex if this object is has more - than more dimension. + than one dimension. """ if ordered_dims is None: - ordered_dims = list(self.dims) - elif set(ordered_dims) != set(self.dims): + ordered_dims = list(self._data.dims) + elif set(ordered_dims) != set(self._data.dims): raise ValueError( "ordered_dims must match dims, but does not: " - f"{ordered_dims} vs {self.dims}" + f"{ordered_dims} vs {tuple(self._data.dims)}" ) if len(ordered_dims) == 0: @@ -741,8 +743,8 @@ def _names(self) -> set[Hashable]: @property def dims(self) -> Frozen[Hashable, int]: - # deliberately display all dims, not just those on coordinate variables - see https://github.com/pydata/xarray/issues/9466 - return self._data.dims + dims = calculate_dimensions(self.variables) + return FrozenMappingWarningOnValuesAccess(dims) @property def dtypes(self) -> Frozen[Hashable, np.dtype]: @@ -851,8 +853,8 @@ def _names(self) -> set[Hashable]: @property def dims(self) -> Frozen[Hashable, int]: - # deliberately display all dims, not just those on coordinate variables - see https://github.com/pydata/xarray/issues/9466 - return Frozen(self._data.dims) + dims = calculate_dimensions(self.variables) + return FrozenMappingWarningOnValuesAccess(dims) @property def dtypes(self) -> Frozen[Hashable, np.dtype]: @@ -942,7 +944,8 @@ def __init__(self, dataarray: T_DataArray) -> None: @property def dims(self) -> tuple[Hashable, ...]: - return self._data.dims + dims = calculate_dimensions(self._data._coords) + return tuple(dims) @property def dtypes(self) -> Frozen[Hashable, np.dtype]: @@ -967,7 +970,9 @@ def _update_coords( self, coords: dict[Hashable, Variable], indexes: dict[Hashable, Index] ) -> None: validate_dataarray_coords( - self._data.shape, Coordinates._construct_direct(coords, indexes), self.dims + self._data.shape, + Coordinates._construct_direct(coords, indexes), + self._data.dims, ) self._data._coords = coords diff --git a/xarray/tests/test_dataarray.py b/xarray/tests/test_dataarray.py index 71c11626e1e..333f397d95d 100644 --- a/xarray/tests/test_dataarray.py +++ b/xarray/tests/test_dataarray.py @@ -1522,6 +1522,12 @@ def test_coords(self) -> None: self.mda["level_1"] = ("x", np.arange(4)) self.mda.coords["level_1"] = ("x", np.arange(4)) + def test_coords_dims(self) -> None: + da = DataArray( + [[1.0, 2.0], [3.0, 4.0]], coords={"a": ("x", [0, 1])}, dims=("x", "y") + ) + assert da.coords.dims == ("x",) + def test_coords_to_index(self) -> None: da = DataArray(np.zeros((2, 3)), [("x", [1, 2]), ("y", list("abc"))]) diff --git a/xarray/tests/test_dataset.py b/xarray/tests/test_dataset.py index 8e4b09fbfeb..f456f8e83b0 100644 --- a/xarray/tests/test_dataset.py +++ b/xarray/tests/test_dataset.py @@ -892,6 +892,11 @@ def test_coords_properties(self) -> None: "b": np.dtype("int64"), } + def test_coords_dims(self) -> None: + # https://github.com/pydata/xarray/issues/9466 + ds_no_coord = Dataset(data_vars={"a": ("x", [0, 1])}) + assert not len(ds_no_coord.coords.dims) + def test_coords_modify(self) -> None: data = Dataset( { diff --git a/xarray/tests/test_datatree.py b/xarray/tests/test_datatree.py index 2bf079a7cbd..186233a00a2 100644 --- a/xarray/tests/test_datatree.py +++ b/xarray/tests/test_datatree.py @@ -666,6 +666,18 @@ def test_properties(self) -> None: "b": np.dtype("int64"), } + def test_dims(self) -> None: + # https://github.com/pydata/xarray/issues/9466 + ds = Dataset( + data_vars={ + "foo": (["x", "y"], np.random.randn(2, 3)), + }, + ) + dt = DataTree(dataset=ds) + dt["child"] = DataTree() + + assert not len(dt.coords.dims) + def test_modify(self) -> None: ds = Dataset( data_vars={