diff --git a/pyproject.toml b/pyproject.toml index 5c50fa4..dbdbc00 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -38,24 +38,25 @@ rasterio = [ branch = true [tool.ruff] +# Black line length is 88, but black does not format comments. +line-length = 110 +select = [ + # pyflakes + "F", + # pycodestyle + "E", + "W", + # isort + "I", + # pydocstyle + "D" +] + +[tool.ruff.lint] ignore = [ # pydocstyle: Missing Docstrings - "D1", - # pydocstyle: numpy convention - "D107", - "D203", - "D205", - "D212", - "D213", - "D401", - "D402", - "D413", - "D415", - "D416", - "D417" + "D1" ] -# Black line length is 88, but black does not format comments. -line-length = 110 select = [ # pyflakes "F", diff --git a/src/earthkit/transforms/aggregate/climatology.py b/src/earthkit/transforms/aggregate/climatology.py index 363ef1d..f786cb5 100644 --- a/src/earthkit/transforms/aggregate/climatology.py +++ b/src/earthkit/transforms/aggregate/climatology.py @@ -17,8 +17,7 @@ def reduce( groupby_kwargs: dict = {}, **reduce_kwargs, ): - """ - Group data annually over a given `frequency` and reduce using the specified `how` method. + """Group data annually over a given `frequency` and reduce using the specified `how` method. Parameters ---------- @@ -40,6 +39,8 @@ def reduce( time_dim : str (optional) Name of the time dimension in the data object, default behaviour is to detect the time dimension from the input object + groupby_kwargs : dict + Any other kwargs that are accepted by `earthkit.transforms.aggregate.groupby_time` **reduce_kwargs : Any other kwargs that are accepted by `earthkit.transforms.aggregate.reduce` (except how) @@ -55,9 +56,8 @@ def reduce( return _reduce(grouped_data, how=how, dim=time_dim, **reduce_kwargs) -def mean(dataarray: xr.Dataset | xr.DataArray, *args, **kwargs) -> xr.Dataset | xr.DataArray: - """ - Calculate the climatological mean. +def mean(dataarray: xr.Dataset | xr.DataArray, *_args, **_kwargs) -> xr.Dataset | xr.DataArray: + """Calculate the climatological mean. Parameters ---------- @@ -80,13 +80,12 @@ def mean(dataarray: xr.Dataset | xr.DataArray, *args, **kwargs) -> xr.Dataset | ------- xr.DataArray """ - kwargs["how"] = "mean" - return reduce(dataarray, *args, **kwargs) + _kwargs["how"] = "mean" + return reduce(dataarray, *_args, **_kwargs) -def median(dataarray: xr.Dataset | xr.DataArray, **kwargs) -> xr.DataArray: - """ - Calculate the climatological median. +def median(dataarray: xr.Dataset | xr.DataArray, **_kwargs) -> xr.DataArray: + """Calculate the climatological median. Parameters ---------- @@ -109,13 +108,12 @@ def median(dataarray: xr.Dataset | xr.DataArray, **kwargs) -> xr.DataArray: ------- xr.DataArray """ - result = quantiles(dataarray, [0.5], **kwargs) + result = quantiles(dataarray, [0.5], **_kwargs) return result.isel(quantile=0) -def min(dataarray: xr.Dataset | xr.DataArray, *args, **kwargs) -> xr.Dataset | xr.DataArray: - """ - Calculate the climatological minimum. +def min(dataarray: xr.Dataset | xr.DataArray, *_args, **_kwargs) -> xr.Dataset | xr.DataArray: + """Calculate the climatological minimum. Parameters ---------- @@ -138,13 +136,12 @@ def min(dataarray: xr.Dataset | xr.DataArray, *args, **kwargs) -> xr.Dataset | x ------- xr.DataArray """ - kwargs["how"] = "max" - return reduce(dataarray, *args, **kwargs) + _kwargs["how"] = "max" + return reduce(dataarray, *_args, **_kwargs) -def max(dataarray: xr.Dataset | xr.DataArray, *args, **kwargs) -> xr.Dataset | xr.DataArray: - """ - Calculate the climatological maximum. +def max(dataarray: xr.Dataset | xr.DataArray, *_args, **_kwargs) -> xr.Dataset | xr.DataArray: + """Calculate the climatological maximum. Parameters ---------- @@ -167,13 +164,12 @@ def max(dataarray: xr.Dataset | xr.DataArray, *args, **kwargs) -> xr.Dataset | x ------- xr.DataArray """ - kwargs["how"] = "max" - return reduce(dataarray, *args, **kwargs) + _kwargs["how"] = "max" + return reduce(dataarray, *_args, **_kwargs) -def std(dataarray: xr.Dataset | xr.DataArray, *args, **kwargs) -> xr.Dataset | xr.DataArray: - """ - Calculate the climatological standard deviation. +def std(dataarray: xr.Dataset | xr.DataArray, *_args, **_kwargs) -> xr.Dataset | xr.DataArray: + """Calculate the climatological standard deviation. Parameters ---------- @@ -197,13 +193,12 @@ def std(dataarray: xr.Dataset | xr.DataArray, *args, **kwargs) -> xr.Dataset | x ------- xr.DataArray """ - kwargs["how"] = "std" - return reduce(dataarray, *args, **kwargs) + _kwargs["how"] = "std" + return reduce(dataarray, *_args, **_kwargs) -def daily_reduce(dataarray: xr.Dataset | xr.DataArray, *args, **kwargs) -> xr.Dataset | xr.DataArray: - """ - Reduce the data to the daily climatology of the provided "how" method. +def daily_reduce(dataarray: xr.Dataset | xr.DataArray, *_args, **_kwargs) -> xr.Dataset | xr.DataArray: + """Reduce the data to the daily climatology of the provided "how" method. Parameters ---------- @@ -230,13 +225,12 @@ def daily_reduce(dataarray: xr.Dataset | xr.DataArray, *args, **kwargs) -> xr.Da ------- xr.DataArray """ - kwargs["frequency"] = "dayofyear" - return reduce(dataarray, *args, **kwargs) + _kwargs["frequency"] = "dayofyear" + return reduce(dataarray, *_args, **_kwargs) -def daily_mean(dataarray: xr.Dataset | xr.DataArray, *args, **kwargs) -> xr.Dataset | xr.DataArray: - """ - Calculate the daily climatological mean. +def daily_mean(dataarray: xr.Dataset | xr.DataArray, *_args, **_kwargs) -> xr.Dataset | xr.DataArray: + """Calculate the daily climatological mean. Parameters ---------- @@ -257,13 +251,12 @@ def daily_mean(dataarray: xr.Dataset | xr.DataArray, *args, **kwargs) -> xr.Data ------- xr.DataArray """ - kwargs["how"] = "mean" - return daily_reduce(dataarray, *args, **kwargs) + _kwargs["how"] = "mean" + return daily_reduce(dataarray, *_args, **_kwargs) -def daily_median(dataarray: xr.Dataset | xr.DataArray, *args, **kwargs) -> xr.Dataset | xr.DataArray: - """ - Calculate the daily climatological median. +def daily_median(dataarray: xr.Dataset | xr.DataArray, *_args, **_kwargs) -> xr.Dataset | xr.DataArray: + """Calculate the daily climatological median. Parameters ---------- @@ -284,13 +277,12 @@ def daily_median(dataarray: xr.Dataset | xr.DataArray, *args, **kwargs) -> xr.Da ------- xr.DataArray """ - kwargs["how"] = "median" - return daily_reduce(dataarray, *args, **kwargs) + _kwargs["how"] = "median" + return daily_reduce(dataarray, *_args, **_kwargs) -def daily_min(dataarray: xr.Dataset | xr.DataArray, *args, **kwargs) -> xr.Dataset | xr.DataArray: - """ - Calculate the daily climatological min. +def daily_min(dataarray: xr.Dataset | xr.DataArray, *_args, **_kwargs) -> xr.Dataset | xr.DataArray: + """Calculate the daily climatological min. Parameters ---------- @@ -311,13 +303,12 @@ def daily_min(dataarray: xr.Dataset | xr.DataArray, *args, **kwargs) -> xr.Datas ------- xr.DataArray """ - kwargs["how"] = "min" - return daily_reduce(dataarray, *args, **kwargs) + _kwargs["how"] = "min" + return daily_reduce(dataarray, *_args, **_kwargs) -def daily_max(dataarray: xr.Dataset | xr.DataArray, *args, **kwargs) -> xr.Dataset | xr.DataArray: - """ - Calculate the daily climatological max. +def daily_max(dataarray: xr.Dataset | xr.DataArray, *_args, **_kwargs) -> xr.Dataset | xr.DataArray: + """Calculate the daily climatological max. Parameters ---------- @@ -338,13 +329,12 @@ def daily_max(dataarray: xr.Dataset | xr.DataArray, *args, **kwargs) -> xr.Datas ------- xr.DataArray """ - kwargs["how"] = "max" - return daily_reduce(dataarray, *args, **kwargs) + _kwargs["how"] = "max" + return daily_reduce(dataarray, *_args, **_kwargs) -def daily_std(dataarray: xr.Dataset | xr.DataArray, *args, **kwargs) -> xr.Dataset | xr.DataArray: - """ - Calculate the daily climatological standard deviation. +def daily_std(dataarray: xr.Dataset | xr.DataArray, *_args, **_kwargs) -> xr.Dataset | xr.DataArray: + """Calculate the daily climatological standard deviation. Parameters ---------- @@ -366,13 +356,12 @@ def daily_std(dataarray: xr.Dataset | xr.DataArray, *args, **kwargs) -> xr.Datas ------- xr.DataArray """ - kwargs["how"] = "std" - return daily_reduce(dataarray, *args, **kwargs) + _kwargs["how"] = "std" + return daily_reduce(dataarray, *_args, **_kwargs) -def monthly_reduce(dataarray: xr.Dataset | xr.DataArray, *args, **kwargs) -> xr.Dataset | xr.DataArray: - """ - Reduce the data to the monthly climatology of the provided "how" method. +def monthly_reduce(dataarray: xr.Dataset | xr.DataArray, *_args, **_kwargs) -> xr.Dataset | xr.DataArray: + """Reduce the data to the monthly climatology of the provided "how" method. Parameters ---------- @@ -399,13 +388,12 @@ def monthly_reduce(dataarray: xr.Dataset | xr.DataArray, *args, **kwargs) -> xr. ------- xr.DataArray """ - kwargs["frequency"] = "month" - return reduce(dataarray, *args, **kwargs) + _kwargs["frequency"] = "month" + return reduce(dataarray, *_args, **_kwargs) -def monthly_mean(dataarray: xr.Dataset | xr.DataArray, *args, **kwargs) -> xr.Dataset | xr.DataArray: - """ - Calculate the monthly climatological mean. +def monthly_mean(dataarray: xr.Dataset | xr.DataArray, *_args, **_kwargs) -> xr.Dataset | xr.DataArray: + """Calculate the monthly climatological mean. Parameters ---------- @@ -426,13 +414,12 @@ def monthly_mean(dataarray: xr.Dataset | xr.DataArray, *args, **kwargs) -> xr.Da ------- xr.DataArray """ - kwargs["how"] = "mean" - return monthly_reduce(dataarray, *args, **kwargs) + _kwargs["how"] = "mean" + return monthly_reduce(dataarray, *_args, **_kwargs) -def monthly_median(dataarray: xr.Dataset | xr.DataArray, *args, **kwargs) -> xr.Dataset | xr.DataArray: - """ - Calculate the monthly climatological median. +def monthly_median(dataarray: xr.Dataset | xr.DataArray, *_args, **_kwargs) -> xr.Dataset | xr.DataArray: + """Calculate the monthly climatological median. Parameters ---------- @@ -453,13 +440,12 @@ def monthly_median(dataarray: xr.Dataset | xr.DataArray, *args, **kwargs) -> xr. ------- xr.DataArray """ - kwargs["how"] = "median" - return monthly_reduce(dataarray, *args, **kwargs) + _kwargs["how"] = "median" + return monthly_reduce(dataarray, *_args, **_kwargs) -def monthly_min(dataarray: xr.Dataset | xr.DataArray, *args, **kwargs) -> xr.Dataset | xr.DataArray: - """ - Calculate the monthly climatological min. +def monthly_min(dataarray: xr.Dataset | xr.DataArray, *_args, **_kwargs) -> xr.Dataset | xr.DataArray: + """Calculate the monthly climatological min. Parameters ---------- @@ -480,13 +466,12 @@ def monthly_min(dataarray: xr.Dataset | xr.DataArray, *args, **kwargs) -> xr.Dat ------- xr.DataArray """ - kwargs["how"] = "min" - return monthly_reduce(dataarray, *args, **kwargs) + _kwargs["how"] = "min" + return monthly_reduce(dataarray, *_args, **_kwargs) -def monthly_max(dataarray: xr.Dataset | xr.DataArray, *args, **kwargs) -> xr.Dataset | xr.DataArray: - """ - Calculate the monthly climatological max. +def monthly_max(dataarray: xr.Dataset | xr.DataArray, *_args, **_kwargs) -> xr.Dataset | xr.DataArray: + """Calculate the monthly climatological max. Parameters ---------- @@ -507,13 +492,12 @@ def monthly_max(dataarray: xr.Dataset | xr.DataArray, *args, **kwargs) -> xr.Dat ------- xr.DataArray """ - kwargs["how"] = "max" - return monthly_reduce(dataarray, *args, **kwargs) + _kwargs["how"] = "max" + return monthly_reduce(dataarray, *_args, **_kwargs) -def monthly_std(dataarray: xr.Dataset | xr.DataArray, *args, **kwargs) -> xr.Dataset | xr.DataArray: - """ - Calculate the monthly climatological standard deviation. +def monthly_std(dataarray: xr.Dataset | xr.DataArray, *_args, **_kwargs) -> xr.Dataset | xr.DataArray: + """Calculate the monthly climatological standard deviation. Parameters ---------- @@ -535,8 +519,8 @@ def monthly_std(dataarray: xr.Dataset | xr.DataArray, *args, **kwargs) -> xr.Dat ------- xr.DataArray """ - kwargs["how"] = "std" - return monthly_reduce(dataarray, *args, **kwargs) + _kwargs["how"] = "std" + return monthly_reduce(dataarray, *_args, **_kwargs) @tools.time_dim_decorator @@ -549,8 +533,7 @@ def quantiles( groupby_kwargs: dict = {}, **reduce_kwargs, ) -> xr.DataArray: - """ - Calculate a set of climatological quantiles. + """Calculate a set of climatological quantiles. Parameters ---------- @@ -568,6 +551,8 @@ def quantiles( time_dim : str (optional) Name of the time dimension in the data object, default behaviour is to detect the time dimension from the input object + groupby_kwargs : dict + Any other kwargs that are accepted by `earthkit.transforms.aggregate.groupby_time` **reduce_kwargs : Any other kwargs that are accepted by `earthkit.transforms.aggregate.reduce` (except how) @@ -594,17 +579,16 @@ def quantiles( def percentiles( dataarray: xr.Dataset | xr.DataArray, p: float | list, - **kwargs, + **_kwargs, ) -> xr.DataArray: - """ - Calculate a set of climatological percentiles. + """Calculate a set of climatological percentiles. Parameters ---------- dataarray : xr.DataArray The DataArray over which to calculate the climatological percentiles. Must contain a `time` dimension. - percentiles : float | list + p : float | list The pecentile, or list of percentiles, to calculate the climatology. frequency : str (optional) Valid options are `day`, `week` and `month`. @@ -628,9 +612,9 @@ def percentiles( quantile_data = quantiles( dataarray, q, - **kwargs, + **_kwargs, ) - result = quantile_data.assign_coords(percentile=("quantile", percentiles)) + result = quantile_data.assign_coords(percentile=("quantile", p)) result = result.swap_dims({"quantile": "percentile"}) result = result.drop("quantile") return result @@ -639,10 +623,9 @@ def percentiles( def anomaly( dataarray: xr.Dataset | xr.DataArray, climatology: xr.Dataset | xr.DataArray, - **kwargs, + **_kwargs, ) -> xr.Dataset | xr.DataArray: - """ - Calculate the anomaly from a reference climatology. + """Calculate the anomaly from a reference climatology. Parameters ---------- @@ -673,11 +656,11 @@ def anomaly( if isinstance(dataarray, xr.Dataset): out_ds = xr.Dataset().assign_attrs(dataarray.attrs) for var in dataarray.data_vars: - out_da = _anomaly_dataarray(dataarray[var], climatology, **kwargs) + out_da = _anomaly_dataarray(dataarray[var], climatology, **_kwargs) out_ds[out_da.name] = out_da return out_ds else: - return _anomaly_dataarray(dataarray, climatology, **kwargs) + return _anomaly_dataarray(dataarray, climatology, **_kwargs) @tools.time_dim_decorator @@ -693,8 +676,7 @@ def _anomaly_dataarray( how_label: str | None = None, **reduce_kwargs, ) -> xr.DataArray: - """ - Calculate the anomaly from a reference climatology. + """Calculate the anomaly from a reference climatology. Parameters ---------- @@ -715,6 +697,12 @@ def _anomaly_dataarray( time dimension from the input object relative : bool (optional) Return the relative anomaly, i.e. the percentage change w.r.t the climatological period + climatology_how_tag : str (optional) + Tag to identify the climatology variable in the climatology dataset + how_label : str (optional) + Label to append to the variable name of the anomaly dataarray + groupby_kwargs : dict + Any other kwargs that are accepted by `earthkit.transforms.aggregate.groupby_time` **reduce_kwargs : Any other kwargs that are accepted by `earthkit.transforms.aggregate.climatology.mean` @@ -789,9 +777,8 @@ def update_anomaly_array(anomaly_array, original_array, var_name, name_tag, upda @tools.time_dim_decorator @tools.groupby_kwargs_decorator @tools.season_order_decorator -def relative_anomaly(dataarray: xr.Dataset | xr.DataArray, *args, **kwargs): - """ - Calculate the relative anomaly from a reference climatology, i.e. percentage change. +def relative_anomaly(dataarray: xr.Dataset | xr.DataArray, *_args, **_kwargs): + """Calculate the relative anomaly from a reference climatology, i.e. percentage change. Parameters ---------- @@ -820,21 +807,20 @@ def relative_anomaly(dataarray: xr.Dataset | xr.DataArray, *args, **kwargs): ------- xr.DataArray """ - anomaly_xarray = anomaly(dataarray, *args, relative=True, **kwargs) + anomaly_xarray = anomaly(dataarray, *_args, relative=True, **_kwargs) return anomaly_xarray def auto_anomaly( dataarray: xr.Dataset | xr.DataArray, - *args, + *_args, climatology_range: tuple | None = None, climatology_how: str = "mean", relative: bool = False, - **kwargs, + **_kwargs, ): - """ - Calculate the anomaly from a reference climatology. + """Calculate the anomaly from a reference climatology. Parameters ---------- @@ -872,9 +858,9 @@ def auto_anomaly( selection = dataarray.sel(time=slice(*climatology_range)) else: selection = dataarray - climatology = reduce(selection, *args, how=climatology_how, **kwargs) + climatology = reduce(selection, *_args, how=climatology_how, **_kwargs) - return anomaly(dataarray, climatology, *args, relative=relative, **kwargs) + return anomaly(dataarray, climatology, *_args, relative=relative, **_kwargs) # Alias easter eggs diff --git a/src/earthkit/transforms/aggregate/general.py b/src/earthkit/transforms/aggregate/general.py index 8b48583..d9f9fcc 100644 --- a/src/earthkit/transforms/aggregate/general.py +++ b/src/earthkit/transforms/aggregate/general.py @@ -28,8 +28,7 @@ def _reduce_dataarray( how_dropna=False, **kwargs, ): - """ - Reduce an xarray.dataarray or xarray.dataset using a specified `how` method. + """Reduce an xarray.dataarray or xarray.dataset using a specified `how` method. With the option to apply weights either directly or using a specified `weights` method. @@ -95,11 +94,10 @@ def _reduce_dataarray( def reduce( dataarray: xr.Dataset | xr.DataArray, - *args, + *_args, **kwargs, ): - """ - Reduce an xarray.dataarray or xarray.dataset using a specified `how` method. + """Reduce an xarray.dataarray or xarray.dataset using a specified `how` method. With the option to apply weights either directly or using a specified `weights` method. @@ -130,7 +128,7 @@ def reduce( """ # handle how as arg or kwarg - kwargs["how"] = args[0] if args else kwargs.get("how", "mean") + kwargs["how"] = _args[0] if _args else kwargs.get("how", "mean") out = _reduce_dataarray(dataarray, **kwargs) # Ensure any input attributes are preserved (maybe not necessary) if isinstance(dataarray, xr.Dataset): @@ -138,7 +136,7 @@ def reduce( return out -def rolling_reduce(dataarray: xr.Dataset | xr.DataArray, *args, **kwargs) -> xr.DataArray: +def rolling_reduce(dataarray: xr.Dataset | xr.DataArray, *_args, **kwargs) -> xr.DataArray: """Return reduced data using a moving window over which to apply the reduction. Parameters @@ -170,11 +168,11 @@ def rolling_reduce(dataarray: xr.Dataset | xr.DataArray, *args, **kwargs) -> xr. if isinstance(dataarray, (xr.Dataset)): out_ds = xr.Dataset().assign_attrs(dataarray.attrs) for var in dataarray.data_vars: - out_da = _rolling_reduce_dataarray(dataarray[var], *args, **kwargs) + out_da = _rolling_reduce_dataarray(dataarray[var], *_args, **kwargs) out_ds[out_da.name] = out_da return out_ds else: - return _rolling_reduce_dataarray(dataarray, *args, **kwargs) + return _rolling_reduce_dataarray(dataarray, *_args, **kwargs) def _rolling_reduce_dataarray( @@ -201,6 +199,8 @@ def _rolling_reduce_dataarray( how_dropna : str Determine if dimension is removed from the output when we have at least one NaN or all NaN. **how_dropna** can be 'None', 'any' or 'all'. Default is None. + chunk: bool + If True, the dataarray is chunked before the rolling operation. **kwargs : Any kwargs that are compatible with the select `how_reduce` method. @@ -235,7 +235,7 @@ def _rolling_reduce_dataarray( def _dropna(data, dims, how): - """Method for drop nan values.""" + """Drop nan values from data.""" if how in [None, "None", "none"]: return data @@ -256,8 +256,7 @@ def resample( how_label: str | None = None, **kwargs, ) -> xr.DataArray: - """ - Resample dataarray to a user-defined frequency using a user-defined "how" method. + """Resample dataarray to a user-defined frequency using a user-defined "how" method. Parameters ---------- @@ -266,12 +265,18 @@ def resample( frequency : str, int, float The frequency at which to resample the chosen dimension. The format must be applicable to the chosen dimension. - dim: str + time_dim: str The dimension to resample along, default is `time` how: str The reduction method for resampling, default is `mean` how_label : str Label to append to the name of the variable in the reduced object, default is nothing + skipna : bool + If True, exclude missing values (na values) from the reduction. + how_args : list + List of arguments to be passed to the reduction method. + how_kwargs : dict + Dictionary of keyword arguments to be passed to the reduction method. **kwargs Keyword arguments to be passed to :func:`resample`. Defaults have been set as: `{"skipna": True}` diff --git a/src/earthkit/transforms/aggregate/spatial.py b/src/earthkit/transforms/aggregate/spatial.py index ecb99c6..fce2697 100644 --- a/src/earthkit/transforms/aggregate/spatial.py +++ b/src/earthkit/transforms/aggregate/spatial.py @@ -12,14 +12,17 @@ def _transform_from_latlon(lat, lon): - """ - Return an Affine transformation of input 1D arrays of lat and lon. + """Return an Affine transformation of input 1D arrays of lat and lon. This assumes that both lat and lon are regular and contiguous. Parameters ---------- - lat/lon : arrays or lists of latitude and longitude + lat : list + arrays or lists of latitude and longitude + + lon : list + arrays or lists of latitude and longitude """ from affine import Affine @@ -37,21 +40,25 @@ def rasterize( dtype: type = int, **kwargs, ) -> xr.DataArray: - """ - Rasterize a list of geometries onto the given xarray coordinates. + """Rasterize a list of geometries onto the given xarray coordinates. + This only works for regular and contiguous latitude and longitude grids. Parameters ---------- - shape_list (affine.Affine): List of geometries - coords (xarray.coords): Coordinates of dataarray to be masked - - lat_key/lon_key: name of the latitude/longitude variables in the coordinates object - - fill: value to fill points which are not within the shape_list, default is 0 - dtype: datatype of the returned mask, default is `int` - - kwargs: Any other kwargs accepted by rasterio.features.rasterize + shape_list : affine.Affine + List of geometries + coords : xarray.coords + Coordinates of dataarray to be masked + lat_key : + name of the latitude variables in the coordinates object + lon_key : + name of the longitude variables in the coordinates object + dtype: + datatype of the returned mask, default is `int` + + kwargs: + Any other kwargs accepted by rasterio.features.rasterize Returns ------- @@ -68,22 +75,25 @@ def rasterize( return xr.DataArray(raster, coords=spatial_coords, dims=(lat_key, lon_key)) -def mask_contains_points(shape_list, coords, lat_key="lat", lon_key="lon", **kwargs) -> xr.DataArray: - """ - Return a mask array for the spatial points of data that lie within shapes in shape_list. +def mask_contains_points(shape_list, coords, lat_key="lat", lon_key="lon", **_kwargs) -> xr.DataArray: + """Return a mask array for the spatial points of data that lie within shapes in shape_list. + Function uses matplotlib.Path so can accept a list of points, this is much faster than shapely. It was initially included for use with irregular data but has been constructed to also accept regular data and return in the same format as the rasterize function. Parameters ---------- - shape_list (affine.Affine): List of geometries - coords (xarray.coords): Coordinates of dataarray to be masked - - lat_key/lon_key: name of the latitude/longitude variables in the coordinates object - - fill: value to fill points which are not within the shape_list, default is 0 - dtype: datatype of the returned mask, default is `int` + shape_list : + List of geometries + coords : xarray.coords + Coordinates of dataarray to be masked + lat_key: + name of the latitude variables in the coordinates object + lon_key: + name of the longitude variables in the coordinates object + dtype: + datatype of the returned mask, default is `int` Returns ------- @@ -147,13 +157,13 @@ def _geopandas_to_shape_list(geodataframe): def _array_mask_iterator(mask_arrays): - """Method which iterates over mask arrays.""" + """Iterate over mask arrays.""" for mask_array in mask_arrays: yield mask_array > 0 def _shape_mask_iterator(shapes, target, regular=True, **kwargs): - """Method which iterates over shape mask methods.""" + """Iterate over shape mask methods.""" if isinstance(shapes, gpd.GeoDataFrame): shapes = _geopandas_to_shape_list(shapes) if regular: @@ -166,23 +176,24 @@ def _shape_mask_iterator(shapes, target, regular=True, **kwargs): def shapes_to_masks(shapes: gpd.GeoDataFrame | list[gpd.GeoDataFrame], target, regular=True, **kwargs): - """ - Method which creates a list of masked dataarrays, if possible use the shape_mask_iterator. + """Create a list of masked dataarrays, if possible use the shape_mask_iterator. Parameters ---------- - shapes (gpd.GeoDataFrame | list[gpd.GeoDataFrame]): A geodataframe or list of geodataframes - containing the polygons for masks - target (xarray.DataArray): A dataarray to to create a mask for, only the geospatial coordinates are used - - regular (bool): If True, data is on a regular grid so use rasterize method, - if False use mask_contains_points - all_touched (optional): + shapes : + A geodataframe or list of geodataframes containing the polygons for masks + target : + A dataarray to to create a mask for, only the geospatial coordinates are used + + regular : + If True, data is on a regular grid so use rasterize method, if False use mask_contains_points + all_touched : If True, all pixels touched by geometries will be considered in, if False, only pixels whose center is within. Default is False. Only valid for regular data. - kwargs: kwargs accepted by the masking methods, rasterize or mask_contains_points + kwargs: + kwargs accepted by the masking methods, rasterize or mask_contains_points Returns ------- @@ -201,24 +212,27 @@ def shapes_to_masks(shapes: gpd.GeoDataFrame | list[gpd.GeoDataFrame], target, r def shapes_to_mask(shapes, target, regular=True, **kwargs): - """ - Method which creates a single masked dataarray based on all features in shapes, - if possible use the shape_mask_iterator. + """Create a single masked dataarray based on all features in shapes. + + If possible use the shape_mask_iterator. Parameters ---------- - shapes (gpd.GeoDataFrame | list[gpd.GeoDataFrame]): A geodataframe or list of geodataframes - containing the polygons for masks - target (xarray.DataArray): A dataarray to to create a mask for, only the geospatial coordinates are used + shapes : + A geodataframe or list of geodataframes containing the polygons for masks + target : + A dataarray to to create a mask for, only the geospatial coordinates are used - regular (bool): If True, data is on a regular grid so use rasterize method, + regular : + If True, data is on a regular grid so use rasterize method, if False use mask_contains_points - all_touched (optional): + all_touched : If True, all pixels touched by geometries will be considered in, if False, only pixels whose center is within. Default is False. Only valid for regular data. - kwargs: kwargs accepted by the masking methods, rasterize or mask_contains_points + kwargs: + kwargs accepted by the masking methods, rasterize or mask_contains_points Returns ------- @@ -264,14 +278,14 @@ def get_mask_dim_index( def masks( dataarray: xr.Dataset | xr.DataArray, geodataframe: gpd.geodataframe.GeoDataFrame, - *args, - **kwargs, + *_args, + **_kwargs, ): logger.warning( "earthkit.transforms.aggregate.spatial.masks is deprecated, " "please use earthkit.transforms.aggregate.spatial.mask instead." ) - return mask(dataarray, geodataframe, *args, **kwargs) + return mask(dataarray, geodataframe, *_args, **_kwargs) def mask( @@ -284,8 +298,7 @@ def mask( union_geometries: bool = False, **mask_kwargs, ) -> xr.Dataset | xr.DataArray: - """ - Apply multiple shape masks to some gridded data. + """Apply multiple shape masks to some gridded data. Each feature in shape is treated as an individual mask to apply to data. The data provided is returned with an additional dimension equal in @@ -299,22 +312,26 @@ def mask( Xarray data object (must have geospatial coordinates). geodataframe : Geopandas Dataframe containing the polygons for aggregations - mask_dim (optional): + mask_dim : dimension that will be created to accomodate the masked arrays, default is the index of the geodataframe - all_touched (optional): + all_touched : If True, all pixels touched by geometries will be considered in, if False, only pixels whose center is within. Default is False. Only valid for regular data. - lat_key/lon_key (optional): - key for latitude/longitude variable, default behaviour is to detect variable keys. - chunk : (optional) bool + lat_key : + key for latitude variable, default behaviour is to detect variable keys. + lon_key : + key for longitude variable, default behaviour is to detect variable keys. + chunk : bool Boolean to indicate whether to use chunking, default = `True`. This is advised as spatial.masks can create large results. If you are working with small arrays, or you have implemented you own chunking rules you may wish to disable it. - union_geometries : (optional) bool + union_geometries : bool Boolean to indicate whether to union all geometries before masking. Default is `False`, which will apply each geometry in the geodataframe as a separate mask. + mask_kwargs : + Any kwargs to pass into the mask method Returns ------- @@ -358,11 +375,10 @@ def reduce( dataarray: xr.Dataset | xr.DataArray, geodataframe: gpd.GeoDataFrame | None = None, mask_arrays: xr.DataArray | list[xr.DataArray] | None = None, - *args, + *_args, **kwargs, ) -> xr.Dataset | xr.DataArray: - """ - Apply a shape object to an xarray.DataArray object using the specified 'how' method. + """Apply a shape object to an xarray.DataArray object using the specified 'how' method. Geospatial coordinates are reduced to a dimension representing the list of features in the shape object. @@ -372,32 +388,35 @@ def reduce( Xarray data object (must have geospatial coordinates). geodataframe : Geopandas Dataframe containing the polygons for aggregations - how (optional): + mask_arrays : + precomputed mask array[s], if provided this will be used instead of creating a new mask. + They must be on the same spatial grid as the dataarray. + how : method used to apply mask. Default='mean', which calls np.nanmean - weights (optional): + weights : Provide weights for aggregation, also accepts recognised keys for weights, e.g. 'latitude' - lat_key/lon_key (optional): + lat_key/lon_key : key for latitude/longitude variable, default behaviour is to detect variable keys. - extra_reduce_dims (optional): + extra_reduce_dims : any additional dimensions to aggregate over when reducing over spatial dimensions - mask_dim (optional): + mask_dim : dimension that will be created after the reduction of the spatial dimensions, default is the index of the dataframe - all_touched (optional): + all_touched : If True, all pixels touched by geometries will be considered in, if False, only pixels whose center is within. Default is False. Only valid for regular data. - mask_kwargs (optional): + mask_kwargs : Any kwargs to pass into the mask method - mask_arrays (optional): + mask_arrays : precomputed mask array[s], if provided this will be used instead of creating a new mask. They must be on the same spatial grid as the dataarray. - return_as (optional): + return_as : what format to return the data object, `pandas` or `xarray`. Work In Progress - how_label (optional): + how_label : label to append to variable name in returned object, default is not to append - kwargs (optional): + kwargs : kwargs recognised by the how function Returns @@ -415,7 +434,7 @@ def reduce( out_ds = xr.Dataset().assign_attrs(dataarray.attrs) for var in dataarray.data_vars: out_da = _reduce_dataarray( - dataarray[var], geodataframe=geodataframe, mask_arrays=mask_arrays, *args, **kwargs + dataarray[var], geodataframe=geodataframe, mask_arrays=mask_arrays, *_args, **kwargs ) out_ds[out_da.name] = out_da return out_ds @@ -427,11 +446,11 @@ def reduce( if geodataframe is not None: out = geodataframe for var in dataarray.data_vars: - out = _reduce_dataarray(dataarray[var], geodataframe=out, *args, **kwargs) + out = _reduce_dataarray(dataarray[var], geodataframe=out, *_args, **kwargs) else: out = None for var in dataarray.data_vars: - _out = _reduce_dataarray(dataarray[var], mask_arrays=mask_arrays, *args, **kwargs) + _out = _reduce_dataarray(dataarray[var], mask_arrays=mask_arrays, *_args, **kwargs) if out is None: out = _out else: @@ -441,7 +460,7 @@ def reduce( raise TypeError("Return as type not recognised or incompatible with inputs") else: return _reduce_dataarray( - dataarray, geodataframe=geodataframe, mask_arrays=mask_arrays, *args, **kwargs + dataarray, geodataframe=geodataframe, mask_arrays=mask_arrays, *_args, **kwargs ) @@ -463,8 +482,7 @@ def _reduce_dataarray( return_geometry_as_coord: bool = False, **reduce_kwargs, ) -> xr.DataArray | pd.DataFrame: - """ - Reduce an xarray.DataArray object over its geospatial dimensions using the specified 'how' method. + """Reduce an xarray.DataArray object over its geospatial dimensions using the specified 'how' method. If a geodataframe is provided the DataArray is reduced over each feature in the geodataframe. Geospatial coordinates are reduced to a dimension representing the list of features in the shape object. @@ -473,30 +491,41 @@ def _reduce_dataarray( ---------- dataarray : Xarray data object (must have geospatial coordinates). - geodataframe (optional): + geodataframe : Geopandas Dataframe containing the polygons for aggregations - how (optional): + mask_arrays : + precomputed mask array[s], if provided this will be used instead of creating a new mask. + They must be on the same spatial grid as the dataarray. + how : method used to apply mask. Default='mean', which calls np.nanmean - weights (optional): + weights : Provide weights for aggregation, also accepts recognised keys for weights, e.g. 'latitude' - lat_key/lon_key (optional): - key for latitude/longitude variable, default behaviour is to detect variable keys. - extra_reduce_dims (optional): + lat_key : + key for latitude variable, default behaviour is to detect variable keys. + lon_key : + key for longitude variable, default behaviour is to detect variable keys. + extra_reduce_dims : any additional dimensions to aggregate over when reducing over spatial dimensions - mask_dim (optional): + mask_dim : dimension that will be created after the reduction of the spatial dimensions, default = `"index"` - return_as (optional): + return_as : what format to return the data object, `"pandas"` or `"xarray"`. Work In Progress - how_label (optional): + how_label : label to append to variable name in returned object, default is `how` - mask_kwargs (optional): + mask_kwargs : Any kwargs to pass into the mask method - reduce_kwargs (optional): + reduce_kwargs : kwargs recognised by the how function - return_geometry_as_coord (optional): + return_geometry_as_coord : include the geometries as a coordinate in the returned xarray object. WARNING: geometries are not serialisable objects, therefore this xarray will not be saveable as netCDF. + all_touched : + If True, all pixels touched by geometries will be considered in, + if False, only pixels whose center is within. Default is False. + Only valid for regular data. + squeeze : + If True, squeeze the output xarray object, default is True Returns ------- diff --git a/src/earthkit/transforms/aggregate/temporal.py b/src/earthkit/transforms/aggregate/temporal.py index 6d0b215..05a4c29 100644 --- a/src/earthkit/transforms/aggregate/temporal.py +++ b/src/earthkit/transforms/aggregate/temporal.py @@ -19,8 +19,7 @@ def standardise_time( target_format: str = "%Y-%m-%d %H:%M:%S", time_dim: str | None = None, ) -> xr.Dataset | xr.DataArray: - """ - Convert time coordinates to a standard format using the Gregorian calendar. + """Convert time coordinates to a standard format using the Gregorian calendar. This function is helpful when combining data from different sources with different time standards or calendars - for example, when combining data @@ -38,6 +37,11 @@ def standardise_time( example, "%Y-%m-%d" will reduce to daily resolution - or to fix elements of the datetime object - for example, "%Y-%m-15" would reduce to monthly resolution and fix the date to the 15th of each month. + time_dim : str, optional + Name of the time dimension, or coordinate, in the xarray object to use for the calculation, + default behaviour is to deduce time dimension from + attributes of coordinates, then fall back to `"time"`. + If you do not want to aggregate along the time dimension use earthkit.transforms.aggregate.reduce Returns ------- @@ -71,12 +75,11 @@ def standardise_time( @tools.time_dim_decorator def reduce( dataarray: xr.Dataset | xr.DataArray, - *args, + *_args, time_dim: str | None = None, **kwargs, ) -> xr.Dataset | xr.DataArray: - """ - Reduce an xarray.dataarray or xarray.dataset along the time/date dimension using a specified `how` method. + """Reduce an xarray.dataarray/dataset along the time/date dimension using a specified `how` method. With the option to apply weights either directly or using a specified `weights` method. @@ -113,23 +116,22 @@ def reduce( """ if "frequency" in kwargs: - return resample(dataarray, *args, time_dim=time_dim, **kwargs) + return resample(dataarray, *_args, time_dim=time_dim, **kwargs) reduce_dims = tools.ensure_list(kwargs.get("dim", [])) if time_dim is not None and time_dim not in reduce_dims: reduce_dims.append(time_dim) kwargs["dim"] = reduce_dims - return _reduce(dataarray, *args, **kwargs) + return _reduce(dataarray, *_args, **kwargs) def mean( dataarray: xr.Dataset | xr.DataArray, - *args, + *_args, **kwargs, ): - """ - Calculate the mean of an xarray.dataarray or xarray.dataset along the time/date dimension. + """Calculate the mean of an xarray.dataarray or xarray.dataset along the time/date dimension. With the option to apply weights either directly or using a specified `weights` method. @@ -160,16 +162,15 @@ def mean( """ kwargs["how"] = "mean" - return reduce(dataarray, *args, **kwargs) + return reduce(dataarray, *_args, **kwargs) def median( dataarray: xr.Dataset | xr.DataArray, - *args, + *_args, **kwargs, ): - """ - Calculate the median of an xarray.dataarray or xarray.dataset along the time/date dimension. + """Calculate the median of an xarray.dataarray or xarray.dataset along the time/date dimension. With the option to apply weights either directly or using a specified `weights` method. @@ -200,16 +201,15 @@ def median( """ kwargs["how"] = "median" - return reduce(dataarray, *args, **kwargs) + return reduce(dataarray, *_args, **kwargs) def min( dataarray: xr.Dataset | xr.DataArray, - *args, + *_args, **kwargs, ): - """ - Calculate the mn of an xarray.dataarray or xarray.dataset along the time/date dimension. + """Calculate the mn of an xarray.dataarray or xarray.dataset along the time/date dimension. With the option to apply weights either directly or using a specified `weights` method. @@ -240,16 +240,15 @@ def min( """ kwargs["how"] = "min" - return reduce(dataarray, *args, **kwargs) + return reduce(dataarray, *_args, **kwargs) def max( dataarray: xr.Dataset | xr.DataArray, - *args, + *_args, **kwargs, ): - """ - Calculate the max of an xarray.dataarray or xarray.dataset along the time/date dimension. + """Calculate the max of an xarray.dataarray or xarray.dataset along the time/date dimension. With the option to apply weights either directly or using a specified `weights` method. @@ -280,16 +279,15 @@ def max( """ kwargs["how"] = "max" - return reduce(dataarray, *args, **kwargs) + return reduce(dataarray, *_args, **kwargs) def std( dataarray: xr.Dataset | xr.DataArray, - *args, + *_args, **kwargs, ) -> xr.Dataset | xr.DataArray: - """ - Calculate the standard deviation of an xarray.dataarray or xarray.dataset along the time/date dimension. + """Calculate the standard deviation of an xarray.dataarray/dataset along the time/date dimension. With the option to apply weights either directly or using a specified `weights` method. @@ -320,16 +318,15 @@ def std( """ kwargs["how"] = "std" - return reduce(dataarray, *args, **kwargs) + return reduce(dataarray, *_args, **kwargs) def sum( dataarray: xr.Dataset | xr.DataArray, - *args, + *_args, **kwargs, ) -> xr.Dataset | xr.DataArray: - """ - Calculate the standard deviation of an xarray.dataarray or xarray.dataset along the time/date dimension. + """Calculate the standard deviation of an xarray.dataarray/dataset along the time/date dimension. With the option to apply weights either directly or using a specified `weights` method. @@ -361,7 +358,7 @@ def sum( """ kwargs["how"] = "sum" - return reduce(dataarray, *args, **kwargs) + return reduce(dataarray, *_args, **kwargs) @tools.time_dim_decorator @@ -371,8 +368,7 @@ def daily_reduce( time_dim: str | None = None, **kwargs, ) -> xr.Dataset | xr.DataArray: - """ - Group data by day and reduce using the given how method. + """Group data by day and reduce using the given how method. Parameters ---------- @@ -442,9 +438,8 @@ def daily_reduce( return red_array -def daily_mean(dataarray: xr.Dataset | xr.DataArray, *args, **kwargs) -> xr.Dataset | xr.DataArray: - """ - Return the daily mean of the datacube. +def daily_mean(dataarray: xr.Dataset | xr.DataArray, *_args, **kwargs) -> xr.Dataset | xr.DataArray: + """Return the daily mean of the datacube. Parameters ---------- @@ -469,12 +464,11 @@ def daily_mean(dataarray: xr.Dataset | xr.DataArray, *args, **kwargs) -> xr.Data xr.DataArray | xr.Dataset A dataarray reduced to daily mean values """ - return daily_reduce(dataarray, *args, how="mean", **kwargs) + return daily_reduce(dataarray, *_args, how="mean", **kwargs) -def daily_median(dataarray: xr.Dataset | xr.DataArray, *args, **kwargs): - """ - Return the daily median of the datacube. +def daily_median(dataarray: xr.Dataset | xr.DataArray, *_args, **kwargs): + """Return the daily median of the datacube. Parameters ---------- @@ -499,12 +493,11 @@ def daily_median(dataarray: xr.Dataset | xr.DataArray, *args, **kwargs): xr.DataArray | xr.Dataset A dataarray reduced to daily median values """ - return daily_reduce(dataarray, *args, how="median", **kwargs) + return daily_reduce(dataarray, *_args, how="median", **kwargs) -def daily_max(dataarray: xr.Dataset | xr.DataArray, *args, **kwargs): - """ - Calculate the daily maximum. +def daily_max(dataarray: xr.Dataset | xr.DataArray, *_args, **kwargs): + """Calculate the daily maximum. Parameters ---------- @@ -529,12 +522,11 @@ def daily_max(dataarray: xr.Dataset | xr.DataArray, *args, **kwargs): xr.DataArray | xr.Dataset A dataarray reduced to daily max values """ - return daily_reduce(dataarray, *args, how="max", **kwargs) + return daily_reduce(dataarray, *_args, how="max", **kwargs) -def daily_min(dataarray: xr.Dataset | xr.DataArray, *args, **kwargs): - """ - Calculate the daily minimum. +def daily_min(dataarray: xr.Dataset | xr.DataArray, *_args, **kwargs): + """Calculate the daily minimum. Parameters ---------- @@ -559,12 +551,11 @@ def daily_min(dataarray: xr.Dataset | xr.DataArray, *args, **kwargs): xr.DataArray | xr.Dataset A dataarray reduced to daily min values """ - return daily_reduce(dataarray, *args, how="min", **kwargs) + return daily_reduce(dataarray, *_args, how="min", **kwargs) -def daily_std(dataarray: xr.Dataset | xr.DataArray, *args, **kwargs): - """ - Calculate the daily standard deviation. +def daily_std(dataarray: xr.Dataset | xr.DataArray, *_args, **kwargs): + """Calculate the daily standard deviation. Parameters ---------- @@ -589,12 +580,11 @@ def daily_std(dataarray: xr.Dataset | xr.DataArray, *args, **kwargs): xr.DataArray | xr.Dataset A dataarray reduced to daily standard deviation values """ - return daily_reduce(dataarray, *args, how="std", **kwargs) + return daily_reduce(dataarray, *_args, how="std", **kwargs) -def daily_sum(dataarray: xr.Dataset | xr.DataArray, *args, **kwargs): - """ - Calculate the daily sum (accumulation). +def daily_sum(dataarray: xr.Dataset | xr.DataArray, *_args, **kwargs): + """Calculate the daily sum (accumulation). Parameters ---------- @@ -619,7 +609,7 @@ def daily_sum(dataarray: xr.Dataset | xr.DataArray, *args, **kwargs): xr.DataArray | xr.Dataset A dataarray reduced to daily sum values """ - return daily_reduce(dataarray, *args, how="sum", **kwargs) + return daily_reduce(dataarray, *_args, how="sum", **kwargs) @tools.time_dim_decorator @@ -629,8 +619,7 @@ def monthly_reduce( time_dim: str | None = None, **kwargs, ): - """ - Group data by day and reduce using the given how method. + """Group data by day and reduce using the given how method. Parameters ---------- @@ -708,11 +697,10 @@ def monthly_reduce( def monthly_mean( dataarray: xr.Dataset | xr.DataArray, - *args, + *_args, **kwargs, ): - """ - Calculate the monthly mean. + """Calculate the monthly mean. Parameters ---------- @@ -737,16 +725,15 @@ def monthly_mean( xr.DataArray | xr.Dataset A dataarray reduced to monthly mean values """ - return monthly_reduce(dataarray, *args, how="mean", **kwargs) + return monthly_reduce(dataarray, *_args, how="mean", **kwargs) def monthly_median( dataarray: xr.Dataset | xr.DataArray, - *args, + *_args, **kwargs, ): - """ - Calculate the monthly median. + """Calculate the monthly median. Parameters ---------- @@ -771,16 +758,15 @@ def monthly_median( xr.DataArray | xr.Dataset A dataarray reduced to monthly median values """ - return monthly_reduce(dataarray, *args, how="median", **kwargs) + return monthly_reduce(dataarray, *_args, how="median", **kwargs) def monthly_min( dataarray: xr.Dataset | xr.DataArray, - *args, + *_args, **kwargs, ): - """ - Calculate the monthly min. + """Calculate the monthly min. Parameters ---------- @@ -805,16 +791,15 @@ def monthly_min( xr.DataArray | xr.Dataset A dataarray reduced to monthly minimum values """ - return monthly_reduce(dataarray, *args, how="min", **kwargs) + return monthly_reduce(dataarray, *_args, how="min", **kwargs) def monthly_max( dataarray: xr.Dataset | xr.DataArray, - *args, + *_args, **kwargs, ): - """ - Calculate the monthly max. + """Calculate the monthly max. Parameters ---------- @@ -839,16 +824,15 @@ def monthly_max( xr.DataArray | xr.Dataset A dataarray reduced to monthly maximum values """ - return monthly_reduce(dataarray, *args, how="max", **kwargs) + return monthly_reduce(dataarray, *_args, how="max", **kwargs) def monthly_std( dataarray: xr.Dataset | xr.DataArray, - *args, + *_args, **kwargs, ): - """ - Calculate the monthly standard deviation. + """Calculate the monthly standard deviation. Parameters ---------- @@ -873,16 +857,15 @@ def monthly_std( xr.DataArray | xr.Dataset A dataarray reduced to monthly standard deviation values """ - return monthly_reduce(dataarray, *args, how="std", **kwargs) + return monthly_reduce(dataarray, *_args, how="std", **kwargs) def monthly_sum( dataarray: xr.Dataset | xr.DataArray, - *args, + *_args, **kwargs, ): - """ - Calculate the monthly sum/accumulation along the time dimension. + """Calculate the monthly sum/accumulation along the time dimension. Parameters ---------- @@ -907,7 +890,7 @@ def monthly_sum( xr.DataArray | xr.Dataset A dataarray reduced to monthly sum values """ - return monthly_reduce(dataarray, *args, how="sum", **kwargs) + return monthly_reduce(dataarray, *_args, how="sum", **kwargs) @tools.time_dim_decorator diff --git a/src/earthkit/transforms/tools.py b/src/earthkit/transforms/tools.py index 15a5081..73282e3 100644 --- a/src/earthkit/transforms/tools.py +++ b/src/earthkit/transforms/tools.py @@ -107,17 +107,21 @@ def wrapper(*args, **kwargs): def nanaverage(data, weights=None, **kwargs): - """A merge of the functionality of np.nanmean and np.average. + """Calculate the average of data ignoring nan-values. Parameters ---------- data : numpy array - weights: Weights to apply to the data for averaging. - Weights will be normalised and must correspond to the - shape of the numpy data array and axis/axes that is/are - averaged over. - axis: axis/axes to compute the nanaverage over. - kwargs: any other np.nansum kwargs + Data to average. + weights: + Weights to apply to the data for averaging. + Weights will be normalised and must correspond to the + shape of the numpy data array and axis/axes that is/are + averaged over. + axis: + axis/axes to compute the nanaverage over. + kwargs: + any other np.nansum kwargs Returns ------- @@ -215,8 +219,7 @@ def standard_weights(dataarray: xr.DataArray, weights: str, **kwargs): def latitude_weights(dataarray: xr.DataArray, lat_key: str | None = None): - """ - xarray.DataArray wrapper for latitude_weights. + """xarray.DataArray wrapper for latitude_weights. Detects the spatial dimensions latitude must be a coordinate of the dataarray. """