From 892bed67e58f9b1b6d7c24aec7737eb174086bb4 Mon Sep 17 00:00:00 2001 From: Thomas Nicholas Date: Wed, 12 Jul 2023 12:40:46 -0400 Subject: [PATCH 1/5] type hints --- xarray/core/variable.py | 40 ++++++++++++++++++++++++++++++++++------ 1 file changed, 34 insertions(+), 6 deletions(-) diff --git a/xarray/core/variable.py b/xarray/core/variable.py index 9271d0c4dbd..406c0178ba3 100644 --- a/xarray/core/variable.py +++ b/xarray/core/variable.py @@ -61,14 +61,17 @@ if TYPE_CHECKING: from xarray.core.parallelcompat import ChunkManagerEntrypoint from xarray.core.types import ( + CoarsenBoundaryOptions, Dims, ErrorOptionsWithWarn, PadModeOptions, PadReflectOptions, QuantileMethods, + SideOptions, T_Variable, ) + NON_NANOSECOND_WARNING = ( "Converting non-nanosecond precision {case} values to nanosecond precision. " "This behavior can eventually be relaxed in xarray, as it is an artifact from " @@ -2494,10 +2497,29 @@ def rolling_window( ) def coarsen( - self, windows, func, boundary="exact", side="left", keep_attrs=None, **kwargs + self, + windows: Mapping[Any, int], + func: str | Callable, + boundary: CoarsenBoundaryOptions = "exact", + side: SideOptions | Mapping[Any, SideOptions] = "left", + keep_attrs=None, + **kwargs, ): """ Apply reduction function. + + Parameters + ---------- + windows : mapping of hashable to int + A mapping from the name of the dimension to create the coarsened block along (e.g. `time`) to the size of + the coarsened block. + func : function or str name of function + Function to use to reduce the values of one block down along one or more axes. + boundary : {"exact", "trim", "pad"} + If 'exact', a ValueError will be raised if dimension size is not a + multiple of window size. If 'trim', the excess indexes are trimmed. + If 'pad', NA will be padded. + side : 'left' or 'right' or mapping from dimension to 'left' or 'right' """ windows = {k: v for k, v in windows.items() if k in self.dims} @@ -2514,12 +2536,18 @@ def coarsen( reshaped, axes = self.coarsen_reshape(windows, boundary, side) if isinstance(func, str): - name = func - func = getattr(duck_array_ops, name, None) - if func is None: - raise NameError(f"{name} is not a valid method.") + try: + callable_func = getattr(duck_array_ops, func) + except AttributeError: + raise NameError( + f"{func} is not a valid xarray reduction method, so cannot be used to coarsen" + ) + else: + callable_func = func - return self._replace(data=func(reshaped, axis=axes, **kwargs), attrs=_attrs) + return self._replace( + data=callable_func(reshaped, axis=axes, **kwargs), attrs=_attrs + ) def coarsen_reshape(self, windows, boundary, side): """ From 08dfcad8f308dc3ffef78d04a2a730c1ba73930c Mon Sep 17 00:00:00 2001 From: Thomas Nicholas Date: Wed, 12 Jul 2023 12:43:02 -0400 Subject: [PATCH 2/5] correct coarsen docstring --- xarray/core/rolling.py | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/xarray/core/rolling.py b/xarray/core/rolling.py index 916fabe42ac..a53025090ca 100644 --- a/xarray/core/rolling.py +++ b/xarray/core/rolling.py @@ -786,12 +786,13 @@ def construct( class Coarsen(CoarsenArithmetic, Generic[T_Xarray]): - """A object that implements the coarsen. + """An object that implements the coarsen operation. See Also -------- Dataset.coarsen DataArray.coarsen + Variable.coarsen """ __slots__ = ( @@ -814,21 +815,27 @@ def __init__( coord_func: str | Callable | Mapping[Any, str | Callable], ) -> None: """ - Moving window object. + Coarsening object. Parameters ---------- obj : Dataset or DataArray Object to window. windows : mapping of hashable to int - A mapping from the name of the dimension to create the rolling - exponential window along (e.g. `time`) to the size of the moving window. + A mapping from the name of the dimension to create the coarsened block along (e.g. `time`) to the size of + the coarsened block. boundary : {"exact", "trim", "pad"} If 'exact', a ValueError will be raised if dimension size is not a multiple of window size. If 'trim', the excess indexes are trimmed. If 'pad', NA will be padded. side : 'left' or 'right' or mapping from dimension to 'left' or 'right' - coord_func : function (name) or mapping from coordinate name to function (name). + coord_func : function, str name of function, or mapping from coordinate name to function or str name of func. + Function to use to reduce the coordinate values of one block down to a single new label. + + Can be specified as a custom function, either by passing a callable (e.g. ``np.max``) or passing a string + name of a reduction function supplied by xarray (e.g. ``'min'``). The advantage of specifying as a string is + automatic handling of NaNs and non-numpy array types. + Default is to use "mean" for all coarsened dimensions. Returns ------- From bed7f8d54c5b39fbd0e69bada375661589f62d3d Mon Sep 17 00:00:00 2001 From: Thomas Nicholas Date: Wed, 12 Jul 2023 12:58:37 -0400 Subject: [PATCH 3/5] add example of passing a callable --- doc/user-guide/computation.rst | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/doc/user-guide/computation.rst b/doc/user-guide/computation.rst index f8141f40321..ed01eeea913 100644 --- a/doc/user-guide/computation.rst +++ b/doc/user-guide/computation.rst @@ -460,9 +460,9 @@ and ``mean``, ``std`` and ``var`` return ``NaN``: Coarsen large arrays ==================== -:py:class:`DataArray` and :py:class:`Dataset` objects include a +:py:class:`DataArray` and :py:class:`Dataset` objects include :py:meth:`~xarray.DataArray.coarsen` and :py:meth:`~xarray.Dataset.coarsen` -methods. This supports block aggregation along multiple dimensions, +method. This supports block aggregation along multiple dimensions. .. ipython:: python @@ -475,8 +475,8 @@ methods. This supports block aggregation along multiple dimensions, ) da -In order to take a block mean for every 7 days along ``time`` dimension and -every 2 points along ``x`` dimension, +In order to take a block mean for every 7 days along the ``time`` dimension and +every 2 points along the ``x`` dimension, .. ipython:: python @@ -491,13 +491,20 @@ the excess entries or padding ``nan`` to insufficient entries, da.coarsen(time=30, x=2, boundary="trim").mean() -If you want to apply a specific function to coordinate, you can pass the -function or method name to ``coord_func`` option, +By default the coordinates will be replaced with the mean of the coordinate values in block. +If instead you want to apply a specific reduction function to the coordinate values, you can pass the +function or method name as a string via the ``coord_func`` keyword argument, .. ipython:: python da.coarsen(time=7, x=2, coord_func={"time": "min"}).mean() +Or you can pass any valid reduction function as a callable + +.. ipython:: python + + da.coarsen(time=7, x=2, coord_func={"time": np.ptp}).count() + You can also :ref:`use coarsen to reshape` without applying a computation. .. _compute.using_coordinates: From d568135ace9199e4366432381d1d2cce6e76a493 Mon Sep 17 00:00:00 2001 From: Thomas Nicholas Date: Wed, 12 Jul 2023 12:58:56 -0400 Subject: [PATCH 4/5] note the similarity to .reduce --- xarray/core/rolling.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/xarray/core/rolling.py b/xarray/core/rolling.py index a53025090ca..ea219a927fe 100644 --- a/xarray/core/rolling.py +++ b/xarray/core/rolling.py @@ -833,9 +833,9 @@ def __init__( Function to use to reduce the coordinate values of one block down to a single new label. Can be specified as a custom function, either by passing a callable (e.g. ``np.max``) or passing a string - name of a reduction function supplied by xarray (e.g. ``'min'``). The advantage of specifying as a string is - automatic handling of NaNs and non-numpy array types. - Default is to use "mean" for all coarsened dimensions. + name of a reduction function supplied by xarray (e.g. ``'min'``). If passed as a callable it should be a + valid argument to xarray's ``.reduce`` method. The advantage of specifying as a string is automatic handling + of NaNs and non-numpy array types. Default is to use "mean" for all coarsened dimensions. Returns ------- From 9b8da97e35f50accbeaf9035ecd3c4b009d0b038 Mon Sep 17 00:00:00 2001 From: Thomas Nicholas Date: Wed, 12 Jul 2023 13:03:18 -0400 Subject: [PATCH 5/5] whatsnew --- doc/whats-new.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/whats-new.rst b/doc/whats-new.rst index 59c7c048c3f..6bd67459787 100644 --- a/doc/whats-new.rst +++ b/doc/whats-new.rst @@ -51,6 +51,8 @@ Documentation - Added examples to docstrings of :py:meth:`Dataset.isel`, :py:meth:`Dataset.reduce`, :py:meth:`Dataset.argmin`, :py:meth:`Dataset.argmax` (:issue:`6793`, :pull:`7881`) By `Harshitha `_ . +- Documents that :py:meth:`DataArray.coarsen` accepts a callable as the reduction function. + (:pull:`7981`) By `Tom Nicholas `_. Internal Changes