Calculating basic climatic indices with data from easyclimate
Source:vignettes/climatic-indices.Rmd
climatic-indices.Rmd
First, let’s download daily climatic data for a specific location and store it in a dataframe.
library(easyclimate)
library(tidyr)
library(dplyr)
coords <- matrix(c(-5.36, 37.40), ncol = 2)
daily <- get_daily_climate(coords,
period = 2001:2005,
climatic_var = c("Prcp","Tmin","Tmax"))
Here we calculate the daily mean temperature:
daily <- daily |>
mutate(Tmean = (Tmin + Tmax) / 2, #Daily mean temperature
date = as.Date(date),
month = format(date, format = "%m"),
year = format(date, format = "%Y"))
Average climatic values per site or time period
To calculate average temperatures by site or time period we can use
group_by
and summarise
from
dplyr
, or by
and aggregate
from
base R:
daily |>
group_by(ID_coords) |>
summarise(Tmin.site = mean(Tmin),
Tmean.site = mean(Tmean),
Tmax.site = mean(Tmax))
## # A tibble: 1 × 4
## ID_coords Tmin.site Tmean.site Tmax.site
## <dbl> <dbl> <dbl> <dbl>
## 1 1 11.9 18.4 24.9
daily |>
group_by(year) |>
summarise(Tmin.year = mean(Tmin),
Tmean.year = mean(Tmean),
Tmax.year = mean(Tmax)) |>
kable(digits = 1)
year | Tmin.year | Tmean.year | Tmax.year |
---|---|---|---|
2001 | 12.2 | 18.5 | 24.8 |
2002 | 12.0 | 18.3 | 24.6 |
2003 | 12.5 | 18.7 | 24.9 |
2004 | 11.7 | 18.3 | 24.8 |
2005 | 11.3 | 18.3 | 25.3 |
daily |>
group_by(month) |>
summarise(Tmin.month = mean(Tmin),
Tmean.month = mean(Tmean),
Tmax.month = mean(Tmax)) |>
kable(digits = 1)
month | Tmin.month | Tmean.month | Tmax.month |
---|---|---|---|
01 | 4.7 | 10.3 | 15.9 |
02 | 4.8 | 11.0 | 17.2 |
03 | 8.8 | 14.5 | 20.3 |
04 | 9.8 | 16.4 | 23.0 |
05 | 12.9 | 19.9 | 27.0 |
06 | 17.6 | 25.6 | 33.5 |
07 | 18.9 | 27.1 | 35.3 |
08 | 19.8 | 27.5 | 35.3 |
09 | 17.2 | 24.0 | 30.8 |
10 | 14.1 | 19.5 | 25.0 |
11 | 8.2 | 13.6 | 18.9 |
12 | 6.2 | 11.1 | 16.1 |
Similarly, you can calculate accumulated precipitation over different time periods:
year | sumPrec |
---|---|
2001 | 568 |
2002 | 564 |
2003 | 643 |
2004 | 373 |
2005 | 261 |
daily |>
group_by(year, month) |>
summarise(sumPrec = sum(Prcp)) |>
pivot_wider(names_from = month, values_from = sumPrec) |>
kable(digits = 0)
year | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
---|---|---|---|---|---|---|---|---|---|---|---|---|
2001 | 136 | 17 | 123 | 3 | 44 | 0 | 0 | 0 | 36 | 76 | 65 | 68 |
2002 | 31 | 9 | 101 | 53 | 14 | 3 | 0 | 0 | 80 | 32 | 141 | 100 |
2003 | 69 | 68 | 43 | 62 | 3 | 0 | 0 | 0 | 30 | 195 | 77 | 96 |
2004 | 10 | 80 | 63 | 40 | 61 | 0 | 0 | 2 | 2 | 70 | 9 | 37 |
2005 | 0 | 58 | 22 | 20 | 18 | 0 | 0 | 0 | 0 | 103 | 14 | 27 |
Climatic anomalies
Sometimes it can be useful to calculate the deviation of climate values from a reference value. For example, if we consider as the reference the mean value for the period 2001-2005, we can calculate the deviations per site and year as follows:
daily |>
group_by(ID_coords, year) |>
summarise(avgTm = mean(Tmean)) |>
group_by(ID_coords) |>
mutate(refTm = mean(avgTm)) |> #Reference mean temperature
mutate(devTm = avgTm - refTm) |>
kable(digits = 1)
ID_coords | year | avgTm | refTm | devTm |
---|---|---|---|---|
1 | 2001 | 18.5 | 18.4 | 0.1 |
1 | 2002 | 18.3 | 18.4 | -0.1 |
1 | 2003 | 18.7 | 18.4 | 0.3 |
1 | 2004 | 18.3 | 18.4 | -0.2 |
1 | 2005 | 18.3 | 18.4 | -0.1 |
daily |>
group_by(ID_coords, year) |>
summarise(sumPrec = sum(Prcp)) |>
group_by(ID_coords) |>
mutate(refPrec = mean(sumPrec)) |> #Reference precipitation
mutate(devPrec =sumPrec - refPrec) |>
kable(digits = 0)
ID_coords | year | sumPrec | refPrec | devPrec |
---|---|---|---|---|
1 | 2001 | 568 | 482 | 86 |
1 | 2002 | 564 | 482 | 82 |
1 | 2003 | 643 | 482 | 161 |
1 | 2004 | 373 | 482 | -109 |
1 | 2005 | 261 | 482 | -221 |
Climatic events
Having daily values allows us to calculate climatic indices such as the number of consecutive days above a given temperature (e.g. heat waves or growing degree days), the number of spring frosts or the number of consecutive days without rain.
Let’s start with an example on heat waves, or number of days with maximum temperatures above a given threshold:
threshold <- 32
daily |>
mutate(ID_coords = as.factor(ID_coords),
year = factor(year)) |>
group_by(ID_coords, year) |>
mutate(event = ifelse(Tmax >= threshold, 1, 0), # NAs will be 0
start = c(1, diff(event) != 0),
run = cumsum(start)) |>
filter(event == 1) |>
group_by(run, .add = TRUE) |>
mutate(length = n()) |>
group_by(ID_coords, year) |>
summarise(max_heatwave = max(length), # longest heatwave per year (in days)
mean_heatwave = mean(length), # average length of heatwaves per year
n_heatwave = n()) |> # No. of events per year
kable(digits = 1)
ID_coords | year | max_heatwave | mean_heatwave | n_heatwave |
---|---|---|---|---|
1 | 2001 | 28 | 14.6 | 94 |
1 | 2002 | 13 | 8.1 | 74 |
1 | 2003 | 31 | 14.3 | 97 |
1 | 2004 | 30 | 15.5 | 99 |
1 | 2005 | 27 | 15.0 | 93 |
To calculate the number of days with spring frosts (minimum
temperatures below 0) we can use the next code:
spring.months <- c("03","04","05") # March to May
daily |>
mutate(ID_coords = as.factor(ID_coords),
year = factor(year)) |>
filter(month %in% spring.months) |>
mutate(event = ifelse(Tmin < 0, 1, 0)) |> # NAs will be 0
group_by(ID_coords, year) |>
mutate(n_frost = sum(event)) |> # No. of days with minimum temperature < 0 per year
filter(event == 1) |>
group_by(ID_coords, year, n_frost) |>
summarise(Tmin_frost_avg = mean(Tmin)/100) |> # Mean minimum temperature of frost days
ungroup() |>
complete(ID_coords, year, fill = list(n_frost = 0, Tmin_frost_avg = NA)) |>
kable()
ID_coords | year | n_frost | Tmin_frost_avg |
---|---|---|---|
1 | 2001 | 0 | NA |
1 | 2002 | 0 | NA |
1 | 2003 | 0 | NA |
1 | 2004 | 1 | -0.0050 |
1 | 2005 | 1 | -0.0021 |
A dry periods can be defined as a specific number of consecutive
days with no precipitation.
threshold <- 30 #threshold in days to count extreme long events of no-rain
daily %>%
mutate(event = ifelse(Prcp < 0.01, 1, 0), # NAs will be 0
start = c(1, diff(event) != 0)) |>
group_by(ID_coords, year) |>
mutate(run = cumsum(start)) |>
filter(event == 1) |>
group_by(ID_coords, year, run) |>
summarise(length = n()) |>
ungroup(run) |>
summarise(max_days_norain = max(length), # Maximum length of periods of consecutive days without rain per year
mean_days_norain = mean(length),
nextreme_events = sum(length > threshold)) %>% # No. of events per year
ungroup() |>
complete(ID_coords, year,
fill = list(max_days_norain = NA, mean_days_norain = NA, nevents = 0)) |>
kable(digits = 1)
ID_coords | year | max_days_norain | mean_days_norain | nextreme_events |
---|---|---|---|---|
1 | 2001 | 124 | 10.5 | 2 |
1 | 2002 | 102 | 9.9 | 1 |
1 | 2003 | 146 | 8.9 | 1 |
1 | 2004 | 87 | 12.0 | 2 |
1 | 2005 | 132 | 17.3 | 3 |
Using ClimInd in combination with easyclimate
The package climInd
can be used to calculate multiple climatic indices from data obtained
through easyclimate
. For example:
Number of days with maximum temperature > 32ºC in summer
(June-August):
library(ClimInd)
Tmax <- as.vector(daily$Tmax)
names(Tmax) <- as.character(format(daily$date, format = "%m/%d/%Y"))
d32(Tmax)
## 2001 2002 2003 2004 2005
## 77 64 72 75 76
Growing degree days:
Tmean <- as.vector(daily$Tmean)
names(Tmean) <- as.character(format(daily$date, format = "%m/%d/%Y"))
gd4(data = Tmean, time.scale = "year")
## 2001 2002 2003 2004 2005
## 5304.165 5211.840 5371.645 5218.365 5234.140
Growing season length:
gsl(data = Tmean, time.scale = "year")
## 2001 2002 2003 2004 2005
## 365 365 365 366 365
Heavy precipitation days:
Prec <- as.vector(daily$Prcp)
names(Prec) <- as.character(format(daily$date, format = "%m/%d/%Y"))
d50mm(data = Prec, time.scale = "month")
## Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
## 2001 0 0 0 0 0 0 0 0 0 0 0 0
## 2002 0 0 0 0 0 0 0 0 0 0 0 0
## 2003 0 0 0 0 0 0 0 0 0 0 0 0
## 2004 0 0 0 0 0 0 0 0 0 0 0 0
## 2005 0 0 0 0 0 0 0 0 0 0 0 0
Learn more
To learn more about downloading daily climatic data, please consult this vignette for point coordinates, or this other if you need to extract data for several polygons or a region.