From 2ca5856ad7a5029aa6003c64afc33015e2d25b8e Mon Sep 17 00:00:00 2001 From: Sam Levang Date: Wed, 20 Nov 2024 22:13:22 -0500 Subject: [PATCH 1/7] add as_array methods --- xarray/core/dataarray.py | 22 ++++++++++++++++++++++ xarray/core/dataset.py | 26 ++++++++++++++++++++++++++ xarray/namedarray/core.py | 4 ++++ xarray/tests/test_dataarray.py | 13 +++++++++++++ xarray/tests/test_dataset.py | 15 +++++++++++++++ 5 files changed, 80 insertions(+) diff --git a/xarray/core/dataarray.py b/xarray/core/dataarray.py index eae11c0c491..cbf41bc594c 100644 --- a/xarray/core/dataarray.py +++ b/xarray/core/dataarray.py @@ -844,6 +844,28 @@ def as_numpy(self) -> Self: coords = {k: v.as_numpy() for k, v in self._coords.items()} return self._replace(self.variable.as_numpy(), coords, indexes=self._indexes) + def as_array(self, asarray: Callable[[ArrayLike, ...], Any], **kwargs) -> Self: + """ + Coerces wrapped data into a specific array type. + + `asarray` should output an object that supports the Array API Standard. + This method does not convert index coordinates, which can't generally be + represented as arbitrary array types. + + Parameters + ---------- + asarray : Callable + Function that converts an array-like object to the desired array type. + For example, `cupy.asarray`, `jax.numpy.asarray`, or `sparse.COO.from_numpy`. + **kwargs : dict + Additional keyword arguments passed to the `asarray` function. + + Returns + ------- + DataArray + """ + return self._replace(self.variable.as_array(asarray, **kwargs)) + @property def _in_memory(self) -> bool: return self.variable._in_memory diff --git a/xarray/core/dataset.py b/xarray/core/dataset.py index e80ce5fa64a..4be135d2b45 100644 --- a/xarray/core/dataset.py +++ b/xarray/core/dataset.py @@ -1460,6 +1460,32 @@ def as_numpy(self) -> Self: numpy_variables = {k: v.as_numpy() for k, v in self.variables.items()} return self._replace(variables=numpy_variables) + def as_array(self, asarray: Callable[[ArrayLike, ...], Any], **kwargs) -> Self: + """ + Converts wrapped data into a specific array type. + + `asarray` should output an object that supports the Array API Standard. + This method does not convert index coordinates, which can't generally be + represented as arbitrary array types. + + Parameters + ---------- + asarray : Callable + Function that converts an array-like object to the desired array type. + For example, `cupy.asarray`, `jax.numpy.asarray`, or `sparse.COO.from_numpy`. + **kwargs : dict + Additional keyword arguments passed to the `asarray` function. + + Returns + ------- + Dataset + """ + array_variables = { + k: v.as_array(asarray, **kwargs) if k not in self._indexes else v + for k, v in self.variables.items() + } + return self._replace(variables=array_variables) + def _copy_listed(self, names: Iterable[Hashable]) -> Self: """Create a new Dataset with the listed variables from this dataset and the all relevant coordinates. Skips all validation. diff --git a/xarray/namedarray/core.py b/xarray/namedarray/core.py index 98d96c73e91..8ae17ebce13 100644 --- a/xarray/namedarray/core.py +++ b/xarray/namedarray/core.py @@ -860,6 +860,10 @@ def as_numpy(self) -> Self: """Coerces wrapped data into a numpy array, returning a Variable.""" return self._replace(data=self.to_numpy()) + def as_array(self, asarray: Callable[[ArrayLike, ...], Any], **kwargs) -> Self: + """Coerces wrapped data into a specific array type, returning a Variable.""" + return self._replace(data=asarray(self._data, **kwargs)) + def reduce( self, func: Callable[..., Any], diff --git a/xarray/tests/test_dataarray.py b/xarray/tests/test_dataarray.py index c8b438948de..6e1efe85185 100644 --- a/xarray/tests/test_dataarray.py +++ b/xarray/tests/test_dataarray.py @@ -39,6 +39,7 @@ from xarray.core.utils import is_scalar from xarray.testing import _assert_internal_invariants from xarray.tests import ( + DuckArrayWrapper, InaccessibleArray, ReturnItem, assert_allclose, @@ -7165,6 +7166,18 @@ def test_from_pint_wrapping_dask(self) -> None: np.testing.assert_equal(da.to_numpy(), arr) +def test_as_array() -> None: + da = xr.DataArray([1, 2, 3], dims=["x"], coords={"x": [4, 5, 6]}) + + def as_duck_array(arr): + return DuckArrayWrapper(arr) + + result = da.as_array(as_duck_array) + + assert isinstance(result.data, DuckArrayWrapper) + assert isinstance(result.x.data, np.ndarray) + + class TestStackEllipsis: # https://github.com/pydata/xarray/issues/6051 def test_result_as_expected(self) -> None: diff --git a/xarray/tests/test_dataset.py b/xarray/tests/test_dataset.py index 67d38aac0fe..13917e28225 100644 --- a/xarray/tests/test_dataset.py +++ b/xarray/tests/test_dataset.py @@ -7639,6 +7639,21 @@ def test_from_pint_wrapping_dask(self) -> None: assert_identical(result, expected) +def test_as_array() -> None: + ds = xr.Dataset( + {"a": ("x", [1, 2, 3])}, coords={"lat": ("x", [4, 5, 6]), "x": [7, 8, 9]} + ) + + def as_duck_array(arr): + return DuckArrayWrapper(arr) + + result = ds.as_array(as_duck_array) + + assert isinstance(result.a.data, DuckArrayWrapper) + assert isinstance(result.lat.data, DuckArrayWrapper) + assert isinstance(result.x.data, np.ndarray) + + def test_string_keys_typing() -> None: """Tests that string keys to `variables` are permitted by mypy""" From dfda3090a94a8ecbb4bc6658bc0c5eb66f77916b Mon Sep 17 00:00:00 2001 From: Sam Levang Date: Wed, 20 Nov 2024 23:58:38 -0500 Subject: [PATCH 2/7] fix mypy --- xarray/core/dataarray.py | 2 +- xarray/core/dataset.py | 2 +- xarray/namedarray/core.py | 6 +++++- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/xarray/core/dataarray.py b/xarray/core/dataarray.py index cbf41bc594c..ee470a272fa 100644 --- a/xarray/core/dataarray.py +++ b/xarray/core/dataarray.py @@ -844,7 +844,7 @@ def as_numpy(self) -> Self: coords = {k: v.as_numpy() for k, v in self._coords.items()} return self._replace(self.variable.as_numpy(), coords, indexes=self._indexes) - def as_array(self, asarray: Callable[[ArrayLike, ...], Any], **kwargs) -> Self: + def as_array(self, asarray: Callable, **kwargs) -> Self: """ Coerces wrapped data into a specific array type. diff --git a/xarray/core/dataset.py b/xarray/core/dataset.py index 4be135d2b45..3e716c7e941 100644 --- a/xarray/core/dataset.py +++ b/xarray/core/dataset.py @@ -1460,7 +1460,7 @@ def as_numpy(self) -> Self: numpy_variables = {k: v.as_numpy() for k, v in self.variables.items()} return self._replace(variables=numpy_variables) - def as_array(self, asarray: Callable[[ArrayLike, ...], Any], **kwargs) -> Self: + def as_array(self, asarray: Callable, **kwargs) -> Self: """ Converts wrapped data into a specific array type. diff --git a/xarray/namedarray/core.py b/xarray/namedarray/core.py index 8ae17ebce13..e80a15fdc3f 100644 --- a/xarray/namedarray/core.py +++ b/xarray/namedarray/core.py @@ -860,7 +860,11 @@ def as_numpy(self) -> Self: """Coerces wrapped data into a numpy array, returning a Variable.""" return self._replace(data=self.to_numpy()) - def as_array(self, asarray: Callable[[ArrayLike, ...], Any], **kwargs) -> Self: + def as_array( + self, + asarray: Callable[[duckarray[Any, _DType_co]], duckarray[Any, _DType_co]], + **kwargs: Any, + ) -> Self: """Coerces wrapped data into a specific array type, returning a Variable.""" return self._replace(data=asarray(self._data, **kwargs)) From 20aad9bcd220093dcb80c3f67dc61873e64306c9 Mon Sep 17 00:00:00 2001 From: Sam Levang Date: Thu, 21 Nov 2024 09:27:02 -0500 Subject: [PATCH 3/7] naming, add is_array_type --- xarray/core/dataarray.py | 22 +++++++++++++++++++--- xarray/core/dataset.py | 26 +++++++++++++++++++++++--- xarray/namedarray/core.py | 31 +++++++++++++++++++++++++++++-- xarray/tests/test_dataarray.py | 7 +++++-- xarray/tests/test_dataset.py | 7 +++++-- 5 files changed, 81 insertions(+), 12 deletions(-) diff --git a/xarray/core/dataarray.py b/xarray/core/dataarray.py index ee470a272fa..f9cd552fbcf 100644 --- a/xarray/core/dataarray.py +++ b/xarray/core/dataarray.py @@ -844,7 +844,7 @@ def as_numpy(self) -> Self: coords = {k: v.as_numpy() for k, v in self._coords.items()} return self._replace(self.variable.as_numpy(), coords, indexes=self._indexes) - def as_array(self, asarray: Callable, **kwargs) -> Self: + def as_array_type(self, asarray: Callable, **kwargs) -> Self: """ Coerces wrapped data into a specific array type. @@ -856,7 +856,8 @@ def as_array(self, asarray: Callable, **kwargs) -> Self: ---------- asarray : Callable Function that converts an array-like object to the desired array type. - For example, `cupy.asarray`, `jax.numpy.asarray`, or `sparse.COO.from_numpy`. + For example, `cupy.asarray`, `jax.numpy.asarray`, `sparse.COO.from_numpy`, + or any `from_dlpack` method. **kwargs : dict Additional keyword arguments passed to the `asarray` function. @@ -864,7 +865,22 @@ def as_array(self, asarray: Callable, **kwargs) -> Self: ------- DataArray """ - return self._replace(self.variable.as_array(asarray, **kwargs)) + return self._replace(self.variable.as_array_type(asarray, **kwargs)) + + def is_array_type(self, array_type: type) -> bool: + """ + Check if the wrapped data is of a specific array type. + + Parameters + ---------- + array_type : type + The array type to check for. + + Returns + ------- + bool + """ + return self.variable.is_array_type(array_type) @property def _in_memory(self) -> bool: diff --git a/xarray/core/dataset.py b/xarray/core/dataset.py index 3e716c7e941..c5dd0247d14 100644 --- a/xarray/core/dataset.py +++ b/xarray/core/dataset.py @@ -1460,7 +1460,7 @@ def as_numpy(self) -> Self: numpy_variables = {k: v.as_numpy() for k, v in self.variables.items()} return self._replace(variables=numpy_variables) - def as_array(self, asarray: Callable, **kwargs) -> Self: + def as_array_type(self, asarray: Callable, **kwargs) -> Self: """ Converts wrapped data into a specific array type. @@ -1472,7 +1472,8 @@ def as_array(self, asarray: Callable, **kwargs) -> Self: ---------- asarray : Callable Function that converts an array-like object to the desired array type. - For example, `cupy.asarray`, `jax.numpy.asarray`, or `sparse.COO.from_numpy`. + For example, `cupy.asarray`, `jax.numpy.asarray`, `sparse.COO.from_numpy`, + or any `from_dlpack` method. **kwargs : dict Additional keyword arguments passed to the `asarray` function. @@ -1481,11 +1482,30 @@ def as_array(self, asarray: Callable, **kwargs) -> Self: Dataset """ array_variables = { - k: v.as_array(asarray, **kwargs) if k not in self._indexes else v + k: v.as_array_type(asarray, **kwargs) if k not in self._indexes else v for k, v in self.variables.items() } return self._replace(variables=array_variables) + def is_array_type(self, array_type: type) -> bool: + """ + Check if all data variables and non-index coordinates are of a specific array type. + + Parameters + ---------- + array_type : type + The array type to check for. + + Returns + ------- + bool + """ + return all( + v.is_array_type(array_type) + for k, v in self.variables.items() + if k not in self._indexes + ) + def _copy_listed(self, names: Iterable[Hashable]) -> Self: """Create a new Dataset with the listed variables from this dataset and the all relevant coordinates. Skips all validation. diff --git a/xarray/namedarray/core.py b/xarray/namedarray/core.py index e80a15fdc3f..2558ecec9c7 100644 --- a/xarray/namedarray/core.py +++ b/xarray/namedarray/core.py @@ -860,14 +860,41 @@ def as_numpy(self) -> Self: """Coerces wrapped data into a numpy array, returning a Variable.""" return self._replace(data=self.to_numpy()) - def as_array( + def as_array_type( self, asarray: Callable[[duckarray[Any, _DType_co]], duckarray[Any, _DType_co]], **kwargs: Any, ) -> Self: - """Coerces wrapped data into a specific array type, returning a Variable.""" + """Converts wrapped data into a specific array type. + + Parameters + ---------- + asarray : callable + Function that converts the data into a specific array type. + **kwargs : dict + Additional keyword arguments passed on to `asarray`. + + Returns + ------- + array : NamedArray + Array with the same data, but converted into a specific array type + """ return self._replace(data=asarray(self._data, **kwargs)) + def is_array_type(self, array_type: type) -> bool: + """Check if the data is an instance of a specific array type. + + Parameters + ---------- + array_type : type + Array type to check against. + + Returns + ------- + is_array_type : bool + """ + return isinstance(self._data, array_type) + def reduce( self, func: Callable[..., Any], diff --git a/xarray/tests/test_dataarray.py b/xarray/tests/test_dataarray.py index 6e1efe85185..8bc63f3bf4b 100644 --- a/xarray/tests/test_dataarray.py +++ b/xarray/tests/test_dataarray.py @@ -7166,16 +7166,19 @@ def test_from_pint_wrapping_dask(self) -> None: np.testing.assert_equal(da.to_numpy(), arr) -def test_as_array() -> None: +def test_as_array_type_is_array_type() -> None: da = xr.DataArray([1, 2, 3], dims=["x"], coords={"x": [4, 5, 6]}) + assert da.is_array_type(np.ndarray) + def as_duck_array(arr): return DuckArrayWrapper(arr) - result = da.as_array(as_duck_array) + result = da.as_array_type(as_duck_array) assert isinstance(result.data, DuckArrayWrapper) assert isinstance(result.x.data, np.ndarray) + assert result.is_array_type(DuckArrayWrapper) class TestStackEllipsis: diff --git a/xarray/tests/test_dataset.py b/xarray/tests/test_dataset.py index 13917e28225..edca2a02c93 100644 --- a/xarray/tests/test_dataset.py +++ b/xarray/tests/test_dataset.py @@ -7639,19 +7639,22 @@ def test_from_pint_wrapping_dask(self) -> None: assert_identical(result, expected) -def test_as_array() -> None: +def test_as_array_type_is_array_type() -> None: ds = xr.Dataset( {"a": ("x", [1, 2, 3])}, coords={"lat": ("x", [4, 5, 6]), "x": [7, 8, 9]} ) + # lat is a PandasIndex here + assert ds.drop_vars("lat").is_array_type(np.ndarray) def as_duck_array(arr): return DuckArrayWrapper(arr) - result = ds.as_array(as_duck_array) + result = ds.as_array_type(as_duck_array) assert isinstance(result.a.data, DuckArrayWrapper) assert isinstance(result.lat.data, DuckArrayWrapper) assert isinstance(result.x.data, np.ndarray) + assert result.is_array_type(DuckArrayWrapper) def test_string_keys_typing() -> None: From 438ff7c8c4219ce5ee9c088253c985cc0851a9cb Mon Sep 17 00:00:00 2001 From: Sam Levang Date: Thu, 21 Nov 2024 09:31:45 -0500 Subject: [PATCH 4/7] add public doc and whats new --- doc/api.rst | 4 ++++ doc/whats-new.rst | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/doc/api.rst b/doc/api.rst index 85ef46ca6ba..7a596fdaa2d 100644 --- a/doc/api.rst +++ b/doc/api.rst @@ -117,6 +117,8 @@ Dataset contents Dataset.convert_calendar Dataset.interp_calendar Dataset.get_index + Dataset.as_array_type + Dataset.is_array_type Comparisons ----------- @@ -315,6 +317,8 @@ DataArray contents DataArray.get_index DataArray.astype DataArray.item + DataArray.as_array_type + DataArray.is_array_type Indexing -------- diff --git a/doc/whats-new.rst b/doc/whats-new.rst index 0da34df2c1a..03d69b17e93 100644 --- a/doc/whats-new.rst +++ b/doc/whats-new.rst @@ -85,6 +85,10 @@ New Features By `Sam Levang `_. - Speed up loading of large zarr stores using dask arrays. (:issue:`8902`) By `Deepak Cherian `_. +- Make more xarray methods fully compatible with duck array types, and introduce new + ``as_array_type`` and ``is_array_type`` methods for converting wrapped data to other + duck array types. (:issue:`7848`, :pull:`9798`). + By `Sam Levang `_. Breaking Changes ~~~~~~~~~~~~~~~~ From 24034ba011c63d02a5f8821c3671d2e7fd0e7cea Mon Sep 17 00:00:00 2001 From: Sam Levang Date: Mon, 25 Nov 2024 10:14:29 -0500 Subject: [PATCH 5/7] doc --- xarray/core/dataarray.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xarray/core/dataarray.py b/xarray/core/dataarray.py index f9cd552fbcf..06520676445 100644 --- a/xarray/core/dataarray.py +++ b/xarray/core/dataarray.py @@ -846,7 +846,7 @@ def as_numpy(self) -> Self: def as_array_type(self, asarray: Callable, **kwargs) -> Self: """ - Coerces wrapped data into a specific array type. + Converts wrapped data into a specific array type. `asarray` should output an object that supports the Array API Standard. This method does not convert index coordinates, which can't generally be From 945ffca02cf53cad0b4fbdd2d723b048ea071a7f Mon Sep 17 00:00:00 2001 From: Sam Levang Date: Thu, 21 Nov 2024 10:57:26 -0500 Subject: [PATCH 6/7] add support for chunked arrays in as_array_type --- xarray/core/dataarray.py | 2 ++ xarray/core/dataset.py | 2 ++ xarray/namedarray/core.py | 14 +++++++++++--- xarray/tests/test_dataarray.py | 19 +++++++++++++++---- xarray/tests/test_dataset.py | 24 ++++++++++++++++++++---- 5 files changed, 50 insertions(+), 11 deletions(-) diff --git a/xarray/core/dataarray.py b/xarray/core/dataarray.py index 06520676445..e45aaac5836 100644 --- a/xarray/core/dataarray.py +++ b/xarray/core/dataarray.py @@ -848,6 +848,8 @@ def as_array_type(self, asarray: Callable, **kwargs) -> Self: """ Converts wrapped data into a specific array type. + If the data is a chunked array, the conversion is applied to each block. + `asarray` should output an object that supports the Array API Standard. This method does not convert index coordinates, which can't generally be represented as arbitrary array types. diff --git a/xarray/core/dataset.py b/xarray/core/dataset.py index c5dd0247d14..bb794395621 100644 --- a/xarray/core/dataset.py +++ b/xarray/core/dataset.py @@ -1464,6 +1464,8 @@ def as_array_type(self, asarray: Callable, **kwargs) -> Self: """ Converts wrapped data into a specific array type. + If the data is a chunked array, the conversion is applied to each block. + `asarray` should output an object that supports the Array API Standard. This method does not convert index coordinates, which can't generally be represented as arbitrary array types. diff --git a/xarray/namedarray/core.py b/xarray/namedarray/core.py index 2558ecec9c7..ab4b3bc1820 100644 --- a/xarray/namedarray/core.py +++ b/xarray/namedarray/core.py @@ -40,8 +40,8 @@ _SupportsImag, _SupportsReal, ) -from xarray.namedarray.parallelcompat import guess_chunkmanager -from xarray.namedarray.pycompat import to_numpy +from xarray.namedarray.parallelcompat import get_chunked_array_type, guess_chunkmanager +from xarray.namedarray.pycompat import is_chunked_array, to_numpy from xarray.namedarray.utils import ( either_dict_or_kwargs, infix_dims, @@ -867,6 +867,8 @@ def as_array_type( ) -> Self: """Converts wrapped data into a specific array type. + If the data is a chunked array, the conversion is applied to each block. + Parameters ---------- asarray : callable @@ -879,7 +881,13 @@ def as_array_type( array : NamedArray Array with the same data, but converted into a specific array type """ - return self._replace(data=asarray(self._data, **kwargs)) + if is_chunked_array(self._data): + chunkmanager = get_chunked_array_type(self._data) + new_data = chunkmanager.map_blocks(asarray, self._data, **kwargs) + else: + new_data = asarray(self._data, **kwargs) + + return self._replace(data=new_data) def is_array_type(self, array_type: type) -> bool: """Check if the data is an instance of a specific array type. diff --git a/xarray/tests/test_dataarray.py b/xarray/tests/test_dataarray.py index 8bc63f3bf4b..b4af9d37e35 100644 --- a/xarray/tests/test_dataarray.py +++ b/xarray/tests/test_dataarray.py @@ -7171,16 +7171,27 @@ def test_as_array_type_is_array_type() -> None: assert da.is_array_type(np.ndarray) - def as_duck_array(arr): - return DuckArrayWrapper(arr) - - result = da.as_array_type(as_duck_array) + result = da.as_array_type(lambda x: DuckArrayWrapper(x)) assert isinstance(result.data, DuckArrayWrapper) assert isinstance(result.x.data, np.ndarray) assert result.is_array_type(DuckArrayWrapper) +@requires_dask +def test_as_array_type_dask() -> None: + import dask.array + + da = xr.DataArray([1, 2, 3], dims=["x"], coords={"x": [4, 5, 6]}).chunk() + + result = da.as_array_type(lambda x: DuckArrayWrapper(x)) + + assert isinstance(result.data, dask.array.Array) + assert isinstance(result.data._meta, DuckArrayWrapper) + assert isinstance(result.x.data, np.ndarray) + assert result.is_array_type(dask.array.Array) + + class TestStackEllipsis: # https://github.com/pydata/xarray/issues/6051 def test_result_as_expected(self) -> None: diff --git a/xarray/tests/test_dataset.py b/xarray/tests/test_dataset.py index edca2a02c93..b8dbcabf3ce 100644 --- a/xarray/tests/test_dataset.py +++ b/xarray/tests/test_dataset.py @@ -7646,10 +7646,7 @@ def test_as_array_type_is_array_type() -> None: # lat is a PandasIndex here assert ds.drop_vars("lat").is_array_type(np.ndarray) - def as_duck_array(arr): - return DuckArrayWrapper(arr) - - result = ds.as_array_type(as_duck_array) + result = ds.as_array_type(lambda x: DuckArrayWrapper(x)) assert isinstance(result.a.data, DuckArrayWrapper) assert isinstance(result.lat.data, DuckArrayWrapper) @@ -7657,6 +7654,25 @@ def as_duck_array(arr): assert result.is_array_type(DuckArrayWrapper) +@requires_dask +def test_as_array_type_dask() -> None: + import dask.array + + ds = xr.Dataset( + {"a": ("x", [1, 2, 3])}, coords={"lat": ("x", [4, 5, 6]), "x": [7, 8, 9]} + ).chunk() + + assert ds.is_array_type(dask.array.Array) + + result = ds.as_array_type(lambda x: DuckArrayWrapper(x)) + + assert isinstance(result.a.data, dask.array.Array) + assert isinstance(result.a.data._meta, DuckArrayWrapper) + assert isinstance(result.lat.data, dask.array.Array) + assert isinstance(result.lat.data._meta, DuckArrayWrapper) + assert isinstance(result.x.data, np.ndarray) + + def test_string_keys_typing() -> None: """Tests that string keys to `variables` are permitted by mypy""" From ad6c1387bd774a58d5b9621e5e32760e3e751524 Mon Sep 17 00:00:00 2001 From: Sam Levang Date: Mon, 25 Nov 2024 11:02:58 -0500 Subject: [PATCH 7/7] whats new --- doc/whats-new.rst | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/doc/whats-new.rst b/doc/whats-new.rst index 03d69b17e93..36a43d6824a 100644 --- a/doc/whats-new.rst +++ b/doc/whats-new.rst @@ -21,6 +21,9 @@ v.2024.11.1 (unreleased) New Features ~~~~~~~~~~~~ +- Add convenience methods ``as_array_type`` and ``is_array_type`` for converting wrapped + data to other duck array types. (:issue:`7848`, :pull:`9823`). + By `Sam Levang `_. Breaking changes @@ -85,10 +88,6 @@ New Features By `Sam Levang `_. - Speed up loading of large zarr stores using dask arrays. (:issue:`8902`) By `Deepak Cherian `_. -- Make more xarray methods fully compatible with duck array types, and introduce new - ``as_array_type`` and ``is_array_type`` methods for converting wrapped data to other - duck array types. (:issue:`7848`, :pull:`9798`). - By `Sam Levang `_. Breaking Changes ~~~~~~~~~~~~~~~~ pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy