Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adapt to xclim 0.40 #248

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all 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: 2 additions & 1 deletion icclim/generic_indices/threshold.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
from xclim.core.calendar import build_climatology_bounds, percentile_doy, resample_doy
from xclim.core.units import convert_units_to, str2pint
from xclim.core.units import units as xc_units
from xclim.core.utils import PercentileDataArray, calc_perc
from xclim.core.utils import calc_perc

from icclim.generic_indices.threshold_templates import (
EN_THRESHOLD_TEMPLATE,
Expand All @@ -37,6 +37,7 @@
QuantileInterpolationRegistry,
)
from icclim.pre_processing.input_parsing import (
PercentileDataArray,
build_reference_da,
find_standard_vars,
get_name_of_first_var,
Expand Down
64 changes: 63 additions & 1 deletion icclim/pre_processing/input_parsing.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
from xarray.core.dataarray import DataArray
from xarray.core.dataset import Dataset
from xclim.core.units import convert_units_to
from xclim.core.utils import PercentileDataArray

from icclim.generic_indices.standard_variable import (
StandardVariable,
Expand All @@ -26,6 +25,69 @@
DEFAULT_INPUT_FREQUENCY = "days"


class PercentileDataArray(xr.DataArray):
"""Wrap xarray DataArray for percentiles values."""

__slots__ = ()

@classmethod
def is_compatible(cls, source: xr.DataArray) -> bool:
"""Evaluate whether PecentileDataArray is conformant with expected fields.

A PercentileDataArray must have climatology_bounds attributes and either a
quantile or percentiles coordinate, the window is not mandatory.
"""
return (
isinstance(source, xr.DataArray)
and source.attrs.get("climatology_bounds", None) is not None
and ("quantile" in source.coords or "percentiles" in source.coords)
)

@classmethod
def from_da(
cls, source: xr.DataArray, climatology_bounds: list[str] = None
) -> PercentileDataArray:
"""Create a PercentileDataArray from a xarray.DataArray.

Parameters
----------
source : xr.DataArray
A DataArray with its content containing percentiles values.
It must also have a coordinate variable percentiles or quantile.
climatology_bounds : list[str]
Optional. A List of size two which contains the period on which the
percentiles were computed. See
`xclim.core.calendar.build_climatology_bounds`
to build this list from a DataArray.

Returns
-------
PercentileDataArray
The initial `source` DataArray but wrap by PercentileDataArray class.
The data is unchanged and only climatology_bounds attributes is overridden
if q new value is given in inputs.
"""
if (
climatology_bounds is None
and source.attrs.get("climatology_bounds", None) is None
):
raise ValueError("PercentileDataArray needs a climatology_bounds.")
per = cls(source)
# handle case where da was created with `quantile()` method
if "quantile" in source.coords:
per = per.rename({"quantile": "percentiles"})
per.coords["percentiles"] = per.coords["percentiles"] * 100
clim_bounds = source.attrs.get("climatology_bounds", climatology_bounds)
per.attrs["climatology_bounds"] = clim_bounds
if "percentiles" in per.coords:
return per
raise ValueError(
f"DataArray {source.name} could not be turned into"
f" PercentileDataArray. The DataArray must have a"
f" 'percentiles' coordinate variable."
)


def guess_var_names(
ds: Dataset,
var_names: str | Sequence[str] | None,
Expand Down
2 changes: 1 addition & 1 deletion icclim/tests/test_input_parsing.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@
import pandas as pd
import pytest
import xarray as xr
from xclim.core.utils import PercentileDataArray

from icclim.ecad.ecad_indices import EcadIndexRegistry
from icclim.icclim_exceptions import InvalidIcclimArgumentError
from icclim.models.constants import UNITS_KEY
from icclim.pre_processing.input_parsing import (
PercentileDataArray,
guess_var_names,
read_dataset,
update_to_standard_coords,
Expand Down
2 changes: 2 additions & 0 deletions icclim/tests/test_threshold.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
from icclim.models.constants import UNITS_KEY
from icclim.models.logical_link import LogicalLinkRegistry
from icclim.models.operator import OperatorRegistry
from icclim.pre_processing.input_parsing import PercentileDataArray


def test_value_error():
Expand Down Expand Up @@ -295,6 +296,7 @@ def test_threshold_min_value__number_from_file(self):

def test_build_percentile_threshold__from_file(self):
doys = percentile_doy(self.data)
doys = PercentileDataArray.from_da(doys)
doys.to_netcdf(path=self.IN_FILE_PATH)
res = build_threshold(operator=">=", value=self.IN_FILE_PATH)
assert isinstance(res, PercentileThreshold)
Expand Down