The hardware and bandwidth for this mirror is donated by dogado GmbH, the Webhosting and Full Service-Cloud Provider. Check out our Wordpress Tutorial.
If you wish to report a bug, or if you are interested in having us mirror your free-software or open-source project, please feel free to contact us at mirror[@]dogado.de.
A technical working paper for this package can be found here.
An R package for computing climate indices from daily weather observations. Takes vectors of temperature, precipitation, humidity, and wind data and returns tidy data frames: no file wrangling, no class coercion, no API calls.
Standardised summary statistics that compress daily weather observations into measures like frost-day counts, growing-season length, drought severity, and heat-index exceedances. The definitions come from international bodies (WMO ETCCDI 27, ET-SCI extensions) and from individual research communities (SPI / SPEI for drought, Huglin / Winkler for viticulture).
You bring the data, climatekit does the maths. If you
already have a CSV:
library(climatekit)
weather <- read.csv("my_weather_station.csv")
ck_frost_days(weather$tmin, weather$date)If you don’t have data yet, pair with readnoaa
for free NOAA daily observations from 100,000+ stations. No API key:
install.packages("readnoaa") # or devtools::install_github("charlescoverdale/readnoaa")
library(readnoaa)
library(climatekit)
# Step 1: Find a station near you
noaa_nearby(lat = 51.5, lon = -0.1, radius_km = 25)
#> station name latitude longitude distance_km
#> UKE00105915 LONDON WEATHER CENTRE 51.517 -0.117 1.4
# Step 2: Download daily data
weather <- noaa_daily("UKE00105915", "2020-01-01", "2024-12-31",
datatypes = c("TMAX", "TMIN", "PRCP"))
# Step 3: Compute indices
ck_frost_days(weather$tmin, weather$date, period = "annual")
ck_spi(weather$prcp, weather$date, scale = 3)
ck_heating_degree_days((weather$tmax + weather$tmin) / 2, weather$date)| Region | Source | Coverage | Access |
|---|---|---|---|
| Global | NOAA GHCNd | 100,000+ stations worldwide | Free, no key. Use readnoaa |
| Global | ERA5 reanalysis | Gridded, 0.25° resolution, 1940–present | Free, requires CDS account |
| UK | Met Office MIDAS | ~1,000 UK stations, daily | Free via CEDA, requires registration |
| Europe | ECA&D | 20,000+ stations across Europe | Free download |
| US | ACIS (RCC) | All US cooperative & ASOS stations | Free, no key |
| Australia | Bureau of Meteorology | All BoM stations, daily | Free download |
R has the methods scattered across packages with incompatible interfaces:
| Package | Coverage | Limitation |
|---|---|---|
ClimInd |
Multi-family climate indices | Returns raw vectors with no metadata, dates, or units |
climdex.pcic (archived from CRAN, 2023) |
27 ETCCDI core indices | Requires a custom climdexInput S4 object |
SPEI |
SPI + SPEI drought indices | Single-purpose |
heatwaveR |
Marine + atmospheric heatwaves | Single-purpose |
weathermetrics |
Unit conversions + heat index | No climate indices |
climatekit replaces these with a single interface:
vectors in, tidy data frames out, 50+ indices spanning temperature,
precipitation, drought, agroclimatic, and comfort categories.
library(climatekit)
ck_frost_days(tmin, dates) # data.frame
ck_spi(precip, dates, scale = 3) # data.frame
ck_growing_degree_days(tavg, dates, base = 10) # data.frame
ck_huglin(tmin, tmax, dates, lat = 45) # data.frameinstall.packages("climatekit")
# Or install the development version from GitHub
# install.packages("devtools")
devtools::install_github("charlescoverdale/climatekit")The full ETCCDI core set (Alexander et al. 2006; Zhang et al. 2011)
is implemented. ck_etccdi_27() returns an audit table
mapping every code to its climatekit function.
| Code | Function | Description |
|---|---|---|
| FD | ck_frost_days() |
Days where Tmin < 0 °C |
| ID | ck_ice_days() |
Days where Tmax < 0 °C |
| SU | ck_summer_days() |
Days where Tmax > 25 °C |
| TR | ck_tropical_nights() |
Days where Tmin > 20 °C |
| TXx | ck_txx() |
Annual / monthly max of Tmax |
| TNx | ck_tnx() |
Annual / monthly max of Tmin (warmest night) |
| TXn | ck_txn() |
Annual / monthly min of Tmax (coldest day) |
| TNn | ck_tnn() |
Annual / monthly min of Tmin (coldest night) |
| DTR | ck_diurnal_range() |
Mean daily temperature range |
| GSL | ck_growing_season() |
Growing season length |
| TX10p | ck_tx10p() |
% cool days (calendar-day base, optional Zhang 2005 bootstrap) |
| TN10p | ck_tn10p() |
% cool nights (calendar-day base, optional bootstrap) |
| TX90p | ck_tx90p() |
% warm days (calendar-day base, optional bootstrap) |
| TN90p | ck_tn90p() |
% warm nights (calendar-day base, optional bootstrap) |
| WSDI | ck_wsdi() |
Warm spell duration index |
| CSDI | ck_csdi() |
Cold spell duration index |
| RX1day | ck_max_1day_precip() |
Max 1-day precipitation |
| RX5day | ck_max_5day_precip() |
Max 5-day precipitation |
| SDII | ck_precip_intensity() |
Simple daily intensity index |
| R10mm | ck_heavy_precip() (default 10) |
Days with precip >= 10 mm |
| R20mm | ck_very_heavy_precip() (default 20) |
Days with precip >= 20 mm |
| Rnnmm | ck_heavy_precip(threshold = nn) |
Days with precip >= nn mm |
| CDD | ck_dry_days() |
Max consecutive dry days |
| CWD | ck_wet_days() |
Max consecutive wet days |
| R95p | ck_r95p() |
Total precip on very-wet days |
| R99p | ck_r99p() |
Total precip on extremely-wet days |
| PRCPTOT | ck_total_precip() |
Annual wet-day precip total |
Period of >= 3 consecutive days with TX above the calendar-day 90th percentile, plus cold-wave duals (TN below 10th percentile).
| Code | Function | Description |
|---|---|---|
| HWN | ck_hwn() |
Number of distinct heatwave events |
| HWF | ck_hwf() |
Total days inside heatwave events |
| HWD | ck_hwd() |
Longest heatwave duration |
| HWM | ck_hwm(mode = "excess" / "absolute") |
Mean magnitude across event days |
| HWA | ck_hwa(mode = "excess" / "absolute") |
Peak magnitude across event days |
| CWN | ck_cwn() |
Cold-wave number |
| CWF | ck_cwf() |
Cold-wave frequency |
| CWD | ck_cwd() |
Cold-wave duration (note: ETCCDI also uses “CWD” for consecutive wet
days, which is ck_wet_days) |
| CWM | ck_cwm() |
Cold-wave magnitude |
| CWA | ck_cwa() |
Cold-wave amplitude |
| EHF | ck_ehf() |
Excess Heat Factor (Nairn & Fawcett 2013) |
| Function | Description |
|---|---|
ck_spi(distribution = "gamma" / "pearsonIII") |
Standardized Precipitation Index |
ck_spei(distribution = "log-logistic" / "gev") |
Standardized Precipitation-Evapotranspiration Index |
ck_pet() |
Reference evapotranspiration (Hargreaves) |
ck_pet_pm() |
Reference evapotranspiration (FAO-56 Penman-Monteith) |
| Function | Description |
|---|---|
ck_huglin(lat) |
Huglin heliothermal index (viticulture) |
ck_winkler() |
Winkler index (wine region classification) |
ck_branas(lat) |
Branas hydrothermal index (disease pressure) |
ck_first_frost(lat) |
First autumn frost date (NH or SH) |
ck_last_frost(lat) |
Last spring frost date (NH or SH) |
ck_growing_degree_days() |
Accumulated GDD above base |
ck_heating_degree_days() |
Heating degree days |
ck_cooling_degree_days() |
Cooling degree days |
ck_warm_spell() |
Warm-spell days (series-quantile, simpler variant of WSDI) |
ck_wind_chill() |
Wind chill (Environment Canada / NWS) |
ck_heat_index() |
Heat index (Rothfusz / NWS) |
ck_humidex() |
Canadian humidex |
ck_fire_danger() |
Simplified fire-danger proxy (use cffdrs for full
FWI) |
| Function | Description |
|---|---|
ck_etccdi_27() |
Canonical ETCCDI 27 audit table |
ck_catalogue() |
Full implementation catalogue |
ck_browse(sector, standard, search) |
Filter the catalogue |
ck_compute(data, index, ...) |
Dispatch any index by name |
ck_available(), ck_metadata() |
Lightweight index lookups (all 54 indices) |
ck_convert_temp() |
Celsius / Fahrenheit / Kelvin |
ck_apply_grid(x, fun, dates, ...) |
Apply any function over a terra::SpatRaster |
ck_from_netcdf(path, var) |
Thin reader for netCDF input |
library(climatekit)
# Daily minimum temperatures for a year
dates <- as.Date("2024-01-01") + 0:364
set.seed(42)
tmin <- sin(seq(0, 2 * pi, length.out = 365)) * 15 + 2
# Annual frost days
ck_frost_days(tmin, dates)
#> period value index unit
#> 2024-01-01 132 frost_days days
# Monthly breakdown
ck_frost_days(tmin, dates, period = "monthly")
#> period value index unit
#> 2024-01-01 25 frost_days days
#> 2024-02-01 17 frost_days days
#> 2024-03-01 4 frost_days days
#> ...# Heating degree days: cumulative warmth deficit below the base (default 18C).
tavg <- sin(seq(0, 2 * pi, length.out = 365)) * 12 + 10
ck_heating_degree_days(tavg, dates, period = "monthly")
#> period value index unit
#> 2024-01-01 481.10 heating_degree_days degree-days
#> 2024-02-01 378.49 heating_degree_days degree-days
#> 2024-03-01 244.53 heating_degree_days degree-days
#> ...
# Cooling degree days for air conditioning demand
ck_cooling_degree_days(tavg, dates, base = 22)# SPI standardises rolling-window precipitation totals to N(0, 1).
# Values below -1 = moderate, -1.5 = severe, -2 = extreme drought.
dates_long <- seq(as.Date("2015-01-01"), as.Date("2024-12-31"), by = "day")
set.seed(42)
precip <- rgamma(length(dates_long), shape = 2, rate = 0.5)
spi <- ck_spi(precip, dates_long, scale = 3)
head(spi)
#> period value index unit
#> 2015-03-01 -0.2891577 spi dimensionless
#> 2015-04-01 0.4458927 spi dimensionless
#> ...
# SPEI adds evapotranspiration to capture temperature-driven drought
pet <- ck_pet(tmin, tmax, lat = 51.5, dates = dates)# The Huglin heliothermal index classifies grape-growing potential:
# < 1500: too cool for viticulture
# 1500-1800: cool climate (Champagne, Mosel)
# 1800-2100: temperate (Burgundy, Oregon)
# 2100-2400: warm (Bordeaux, Napa)
# > 2400: hot (Barossa, Southern Spain)
dates_gs <- seq(as.Date("2024-04-01"), as.Date("2024-09-30"), by = "day")
set.seed(42)
tmin_gs <- rnorm(length(dates_gs), mean = 12, sd = 3)
tmax_gs <- tmin_gs + runif(length(dates_gs), 8, 15)
ck_huglin(tmin_gs, tmax_gs, dates_gs, lat = 45)
#> period value index unit
#> 2024-01-01 2129.284 huglin degree-days
# Winkler index (wine region classification)
tavg_gs <- (tmin_gs + tmax_gs) / 2
ck_winkler(tavg_gs, dates_gs)dates_year <- as.Date("2024-01-01") + 0:364
set.seed(42)
tmin_year <- -10 + seq_along(dates_year) * 0.08 + rnorm(365, sd = 4)
ck_last_frost(tmin_year, dates_year)
#> period value date index unit
#> 2024-01-01 120 2024-04-29 last_frost day of year
ck_first_frost(tmin_year, dates_year)# Heat index = apparent temperature from T + RH. Above ~40C is dangerous.
ck_heat_index(tavg = c(30, 33, 36, 39), humidity = c(60, 65, 70, 75))
#> value index unit
#> 32.94844 heat_index °C
#> 38.67052 heat_index °C
#> 47.57163 heat_index °C
#> 60.56858 heat_index °C
# Wind chill for cold conditions
ck_wind_chill(tavg = c(-5, -10, -15), wind_speed = c(20, 30, 40))
# Fire weather risk
ck_fire_danger(tavg = 35, humidity = 15, wind_speed = 30, precip = 0)# Inside the reference period, each year biases its own threshold.
# bootstrap = TRUE applies Zhang (2005) leave-one-out resampling.
ck_tx10p(tmax, dates, ref_start = 1961L, ref_end = 1990L, bootstrap = TRUE)# EHF: 3-day mean anomaly above the 95th percentile + acclimatisation.
# Australian BoM operational metric; positive EHF = heatwave conditions.
ck_ehf(tmax, tmin, dates, ref_start = 1961L, ref_end = 1990L, stat = "max")
ck_ehf(tmax, tmin, dates, stat = "n_positive") # heatwave-condition day count
ck_ehf(tmax, tmin, dates, stat = "sum_positive") # severity-weighted total# ck_pet() is Hargreaves (Tmin / Tmax / lat). ck_pet_pm() is FAO-56
# Penman-Monteith with optional humidity, wind, Rs, and elevation.
ck_pet_pm(tmin, tmax, lat = 45, dates = dates,
elev = 200, wind = 2.5,
rh_min = rh_min, rh_max = rh_max)# ck_compute() dispatches on a string index name. Useful in loops or apps.
weather <- data.frame(
dates = as.Date("2024-01-01") + 0:364,
tmin = sin(seq(0, 2 * pi, length.out = 365)) * 15 + 2,
tmax = sin(seq(0, 2 * pi, length.out = 365)) * 15 + 12,
precip = rgamma(365, shape = 0.5, rate = 0.2)
)
# Compute any index by name
ck_compute(weather, "frost_days")
ck_compute(weather, "total_precip", period = "monthly")
# See all available indices
ck_available()
#> index category unit
#> frost_days temperature days
#> ice_days temperature days
#> summer_days temperature days
#> tropical_nights temperature days
#> ...| Package | Description |
|---|---|
readnoaa |
NOAA weather and climate data (pairs with climatekit for data acquisition) |
carbondata |
Carbon market data (EU/UK ETS, voluntary registries) |
cer |
Clean Energy Regulator data (Australia) |
aemo |
Australian Energy Market Operator data |
climdex.pcicclimdex.pcic was the standard R implementation of the
canonical ETCCDI 27 until it was archived from CRAN in 2023.
climatekit covers the same set with a simpler
interface:
# climdex.pcic
ci <- climdexInput.raw(tmax, tmin, prec, ..., base.range = c(1961, 1990))
fd <- climdex.fd(ci) # named numeric vector
# climatekit
fd <- ck_frost_days(tmin, dates) # tidy data frameSee
vignette("climdex-migration", package = "climatekit") for
the full function-name crosswalk and interface-shift notes.
citation("climatekit")For academic use, also cite Alexander et al. (2006) and Zhang et
al. (2011) (canonical ETCCDI), and Zhang et al. (2005) if you use the
in-base bootstrap. inst/CITATION and
CITATION.cff carry the bibentries.
Please report bugs or requests at https://github.com/charlescoverdale/climatekit/issues.
r, r-package, climate-indices, etccdi, climate-extremes, temperature-extremes, precipitation-extremes, heatwave, cold-wave, drought, spi, spei, evapotranspiration, penman-monteith, frost-days, growing-degree-days, climate-change, climatology
These binaries (installable software) and packages are in development.
They may not be fully stable and should be used with caution. We make no claims about them.
Health stats visible at Monitor.