Generic indices recipes#
The generic index API lets you compute any climate indicator by combining a
reducer function (e.g. count_occurrences, sum, average) with a
threshold (e.g. "> 25 degC").
See also
Thresholds and Operators Reference — full table of operators and threshold types.
Quick-start reference#
Threshold mini-cheat-sheet#
Threshold string |
Meaning |
|---|---|
|
Fixed scalar: strictly above 25 °C |
|
Fixed scalar: at least 1 mm/day |
|
Day-of-year percentile (temperature indices): 90th per-calendar-day percentile |
|
Period percentile (precip indices): 75th percentile of the whole period |
|
Bounded (AND): value must satisfy both conditions simultaneously |
|
Bounded (OR): value must satisfy at least one condition |
See Thresholds and Operators Reference for threshold_min_value, per-grid-cell thresholds,
and all available operators.
Imports and in-memory sample data#
All examples below that use in-memory data share the same setup:
import numpy as np
import pandas as pd
import xarray as xr
import icclim
from icclim import build_threshold
# 5 years of daily data, single grid cell
time = pd.date_range("2000-01-01", periods=365 * 5, freq="D")
# Temperature: 30 °C everywhere (300+ K)
tas = xr.DataArray(
np.full(len(time), 303.15), # 30 °C in K
coords={"time": time},
dims=["time"],
attrs={"units": "K"},
)
# Precipitation: alternating 5 mm/day and 0.5 mm/day
pr_vals = np.where(np.arange(len(time)) % 2 == 0, 5e-5, 5e-6)
pr = xr.DataArray(
pr_vals,
coords={"time": time},
dims=["time"],
attrs={"units": "kg m-2 s-1"},
)
For file-based examples, set:
data = "netcdf_files/gridded.1991-2010.nc"
Count occurrences#
Count days per year when temperature exceeds a fixed threshold:
# In-memory example: count days when tas > 25 °C
result = icclim.count_occurrences(
in_files=tas,
var_name="tas",
threshold="> 25 degC",
).compute()
print(result.count_occurrences)
Count days when both temperature AND precipitation exceed their respective thresholds (multivariable index):
okay_temp = build_threshold(">= 20 degC") & build_threshold("<= 30 degC")
some_rain = build_threshold("> 3 mm/day")
result = icclim.count_occurrences(
in_files={
"tas": {"study": tas, "thresholds": okay_temp},
"pr": {"study": pr, "thresholds": some_rain},
}
).compute()
Using a day-of-year percentile threshold (equivalent to TX99p):
tx99p = icclim.count_occurrences(
in_files=tas, var_name="tas", threshold=">= 99 doy_per"
).count_occurrences.compute()
Using out_unit="%" to get the result as a fraction of days:
result_pct = icclim.count_occurrences(
in_files=tas, var_name="tas",
threshold="> 25 degC", out_unit="%",
).count_occurrences.compute()
File-based example:
result_file = icclim.count_occurrences(
in_files=data, var_name="tasmax", threshold=">= 99 doy_per"
).count_occurrences.compute()
Sum#
Sum of precipitation values above 4 mm/day per year:
# In-memory example
rain_sum = icclim.sum(
in_files=pr, var_name="pr", threshold="> 4 mm/day"
).sum.compute()
File-based:
rain_sum_file = icclim.sum(
in_files=data, var_name="precip", threshold="> 4 mm/day"
).sum.compute()
Standard Deviation#
Interannual variability of daily temperature:
# In-memory example
tas_std = icclim.std(in_files=tas, var_name="tas").std.compute()
File-based:
tas_std_file = icclim.std(in_files=data, var_name="tas").std.compute()
Average#
Annual mean temperature:
# In-memory example
tas_avg = icclim.average(in_files=tas, var_name="tas").average.compute()
Mean of values above the 87th period percentile:
tas_hot_avg = icclim.average(
in_files=tas, var_name="tas", threshold="> 87 period_per"
).average.compute()
Monthly means (slice_mode="month"):
tas_monthly = icclim.average(
in_files=tas, var_name="tas", slice_mode="month"
).average.compute()
Maximum Consecutive Occurrences#
Longest dry spell per year (consecutive days when pr < 1 mm/day), equivalent to ECA&D’s CDD:
# In-memory example
dry_spell = icclim.max_consecutive_occurrence(
in_files=pr, var_name="pr", threshold="< 1 mm/day"
).max_consecutive_occurrence.compute()
Use run_index="last" to stamp the spell at its end date (Climdex convention):
dry_spell_last = icclim.max_consecutive_occurrence(
in_files=pr, var_name="pr",
threshold="< 1 mm/day", run_index="last"
).max_consecutive_occurrence.compute()
File-based:
CDD = icclim.max_consecutive_occurrence(
in_files=data, var_name="precip", threshold="< 1.3 mm/day"
).max_consecutive_occurrence.compute()
Sum of Spell Lengths#
Total duration of all heat spells per year where tasmax > 28 °C for at least 6 consecutive days (equivalent parameter to ECA&D’s WSDI):
# In-memory example: spell ≥ 3 consecutive days above 25 °C
spell_total = icclim.sum_of_spell_lengths(
in_files=tas,
var_name="tas",
threshold="> 25 degC",
min_spell_length=3,
).sum_of_spell_lengths.compute()
Combine a percentile threshold via a bounded string:
custom_wsdi = icclim.sum_of_spell_lengths(
in_files=data, var_name="tasmax", threshold="> 90 doy_per"
).sum_of_spell_lengths.compute()
run_index is also supported here ("first" or "last").
Excess#
Cumulative degree-days above a threshold (sum of value - threshold for each
exceedance day). Equivalent to ECA&D’s GD4 when threshold is 4 °C.
# In-memory example: degree-days above 25 °C
gd25 = icclim.excess(
in_files=tas, var_name="tas",
threshold="25 degC",
).excess.compute()
With a day-of-year percentile reference period:
jja_excess = icclim.excess(
in_files=data,
var_name="tmin",
threshold=build_threshold(
"22 doy_per",
base_period_time_range=["1991-01-01", "1995-12-31"],
),
slice_mode="jja",
).excess.compute()
Deficit#
Cumulative degree-days below a threshold (sum of threshold - value).
Equivalent to ECA&D’s HD17 when threshold is 17 °C.
# In-memory example: heating degree-days relative to 17 °C
hd17 = icclim.deficit(
in_files=tas, var_name="tas",
threshold="17 degC",
).deficit.compute()
File-based with the icclim.index entry point:
result = icclim.index(
in_files=data,
var_name=["tmin"],
index_name="deficit",
threshold=build_threshold("17 degC"),
).compute()
Fraction of Total#
Fraction of total precipitation contributed by days above the 75th period percentile (wet days only), equivalent to ECA&D’s R75pTOT:
# In-memory example
r75ptot = icclim.fraction_of_total(
in_files=pr,
var_name="pr",
threshold=build_threshold("> 75 period_per", threshold_min_value="1 mm/day"),
).fraction_of_total.compute()
# Return as mm instead of % using out_unit
r75ptot_mm = icclim.fraction_of_total(
in_files=pr,
var_name="pr",
threshold=build_threshold("> 75 period_per", threshold_min_value="1 mm/day"),
out_unit="mm",
).fraction_of_total.compute()
File-based:
result_frac = icclim.fraction_of_total(
in_files=data,
var_name=["precip"],
threshold=build_threshold("> 75 period_per", threshold_min_value="1 mm/day"),
).fraction_of_total.compute()
Maximum#
Annual maximum temperature:
# In-memory example
txx = icclim.maximum(in_files=tas, var_name="tas").maximum.compute()
Monthly maximum with event date:
txx_monthly = icclim.maximum(
in_files=tas, var_name="tas",
slice_mode="month", date_event=True,
).compute()
Minimum#
Annual minimum temperature:
# In-memory example
tnn = icclim.minimum(in_files=tas, var_name="tas").minimum.compute()
Monthly minimum:
tnn_monthly = icclim.minimum(
in_files=data, var_name="tas", slice_mode="month"
).minimum.compute()
Max of Rolling Sum#
Maximum 5-day accumulated precipitation per year (equivalent to ECA&D’s RX5day):
# In-memory example (5-day rolling window)
rx5day = icclim.max_of_rolling_sum(
in_files=pr,
var_name="pr",
rolling_window_width=5,
).max_of_rolling_sum.compute()
With a wet-day percentile filter:
max_rolling = icclim.max_of_rolling_sum(
in_files=data,
var_name="precip",
threshold=build_threshold(">= 50 period_per", threshold_min_value="1 mm/day"),
).max_of_rolling_sum.compute()
Min of Rolling Sum#
Minimum 5-day accumulated precipitation per year:
# In-memory example
min_rolling = icclim.min_of_rolling_sum(
in_files=pr, var_name="pr", rolling_window_width=5,
).min_of_rolling_sum.compute()
Max of Rolling Average#
Maximum 5-day rolling mean temperature:
# In-memory example
max_rolling_avg = icclim.max_of_rolling_average(
in_files=tas, var_name="tas", rolling_window_width=5,
).max_of_rolling_average.compute()
Min of Rolling Average#
Minimum 5-day rolling mean temperature:
# In-memory example
min_rolling_avg = icclim.min_of_rolling_average(
in_files=tas, var_name="tas", rolling_window_width=5,
).min_of_rolling_average.compute()
Mean of difference#
Mean daily difference between two variables (e.g. tasmax − tasmin), equivalent to ECA&D’s DTR:
# In-memory example: mean of (tasmax - tasmin)
tasmin = tas - 10 # artificial 10 °C spread
tasmin.attrs["units"] = "K"
dtr = icclim.mean_of_difference(
in_files=xr.Dataset({"tasmax": tas, "tasmin": tasmin}),
var_name=["tasmax", "tasmin"],
).mean_of_difference.compute()
File-based via icclim.index:
dtr_file = icclim.index(
in_files=data,
index_name="mean_of_difference",
var_name=["tmax", "tmin"],
).mean_of_difference.compute()
Difference of extremes#
Annual maximum of tasmax minus annual minimum of tasmin, equivalent to ECA&D’s ETR:
# In-memory example
tasmin = tas - 10
tasmin.attrs["units"] = "K"
etr = icclim.difference_of_extremes(
in_files=xr.Dataset({"tasmax": tas, "tasmin": tasmin}),
var_name=["tasmax", "tasmin"],
).difference_of_extremes.compute()
File-based:
etr_file = icclim.index(
in_files=data,
index_name="difference_of_extremes",
var_name=["tmax", "tmin"],
).difference_of_extremes.compute()
Difference of means#
Anomaly: mean of the study period minus mean of the reference period:
# In-memory example: anomaly relative to first year
anomaly = icclim.difference_of_means(
in_files=tas,
var_name="tas",
base_period_time_range=["2000-01-01", "2000-12-31"],
).difference_of_means.compute()
File-based:
anomaly_file = icclim.difference_of_means(
in_files=data,
var_name=["tas"],
base_period_time_range=["1991-01-01", "1995-12-31"],
).difference_of_means.compute()
Mean Of Absolute One Time Step Difference#
Mean day-to-day variability in the diurnal temperature range, equivalent to ECA&D’s
vDTR. The formula is: mean(|(tasmax[t+1] - tasmin[t+1]) - (tasmax[t] - tasmin[t])|)
# In-memory example
tasmin = tas - 10 + xr.DataArray(
np.random.default_rng(42).normal(0, 1, len(time)),
coords={"time": time}, dims=["time"], attrs={"units": "K"},
)
vdtr = icclim.mean_of_absolute_one_time_step_difference(
in_files=xr.Dataset({"tasmax": tas, "tasmin": tasmin}),
var_name=["tasmax", "tasmin"],
).mean_of_absolute_one_time_step_difference.compute()
File-based:
vdtr_file = icclim.mean_of_absolute_one_time_step_difference(
in_files=data,
var_name=["tmax", "tmin"],
).mean_of_absolute_one_time_step_difference.compute()