Climate Normals

Steffi LaZerte

2020-09-01

Downloading Climate Normals

Climate Normals and Averages describe the average climate conditions specific to a particular location. These can be downloaded from Environment and Climate Change Canada using the normals_dl() function.

First we’ll load the weathercan package for downloading the data and the tidyr package for unnesting the data (see below).

library(weathercan)
library(tidyr)
library(dplyr)
library(naniar) # For exploring missing values

To download climate normals, we’ll first find the stations we’re interested in using the stations_search() function. We’ll use the normals_only = TRUE argument to filter to only stations with available climate normals.

stations_search("Winnipeg", normals_only = TRUE)
## # A tibble: 3 x 11
##   prov  station_name    station_id climate_id WMO_id TC_id   lat   lon  elev tz    normals
##   <chr> <chr>                <dbl> <chr>       <dbl> <chr> <dbl> <dbl> <dbl> <chr> <lgl>  
## 1 MB    WINNIPEG A CS        27174 502S001     71849 XWG    49.9 -97.2  239. Etc/… TRUE   
## 2 MB    WINNIPEG RICHA…       3698 5023222     71852 YWG    49.9 -97.2  239. Etc/… TRUE   
## 3 MB    WINNIPEG THE F…      28051 5023262     71579 XWN    49.9 -97.1  230  Etc/… TRUE

Let’s compare the climate normals from these three stations in Winnipeg, MB. Note that unlike the weather_dl() function, the normals_dl() function requires climate_id not station_id. By default the normals are downloaded for the years “1981-2010” (currently the only normals available).

n <- normals_dl(climate_ids = c("502S001", "5023222", "5023262"))
n
## # A tibble: 3 x 6
##   prov  station_name               climate_id meets_wmo normals            frost          
##   <chr> <chr>                      <chr>      <lgl>     <list>             <list>         
## 1 MB    WINNIPEG RICHARDSON INT'L… 5023222    TRUE      <tibble [13 × 197… <tibble [7 × 8…
## 2 MB    WINNIPEG A CS              502S001    FALSE     <tibble [13 × 25]> <tibble [0 × 0…
## 3 MB    WINNIPEG THE FORKS         5023262    FALSE     <tibble [13 × 53]> <tibble [0 × 0…

Because there are two different types of climate normals (weather measurements and first/last frost dates), the data are nested as two different datasets. We can see that the Airport (Richardson Int’l) has the most data with 197 average weather measurements as well as first/last frost dates. The other two weather stations have fewer weather measurements and no frost data available.

We can also see that only one of the three stations has data quality sufficient to meet the WMO standards for temperature and precipitation (i.e. both these measurements have code >= A). See the ECCC calculations document for more details.

To extract either data set we can use the unnest() function from the tidyr package.

normals <- unnest(n, normals)
frost <- unnest(n, frost)

Note that this extracts the measurements for all three stations (in the case of the normals data frame), but not all measurements are available for each station

normals
## # A tibble: 39 x 202
##    prov  station_name climate_id meets_wmo period temp_daily_aver… temp_daily_aver…
##    <chr> <chr>        <chr>      <lgl>     <fct>             <dbl> <chr>           
##  1 MB    WINNIPEG RI… 5023222    TRUE      Jan               -16.4 A               
##  2 MB    WINNIPEG RI… 5023222    TRUE      Feb               -13.2 A               
##  3 MB    WINNIPEG RI… 5023222    TRUE      Mar                -5.8 A               
##  4 MB    WINNIPEG RI… 5023222    TRUE      Apr                 4.4 A               
##  5 MB    WINNIPEG RI… 5023222    TRUE      May                11.6 A               
##  6 MB    WINNIPEG RI… 5023222    TRUE      Jun                17   A               
##  7 MB    WINNIPEG RI… 5023222    TRUE      Jul                19.7 A               
##  8 MB    WINNIPEG RI… 5023222    TRUE      Aug                18.8 A               
##  9 MB    WINNIPEG RI… 5023222    TRUE      Sep                12.7 A               
## 10 MB    WINNIPEG RI… 5023222    TRUE      Oct                 5   A               
## 11 MB    WINNIPEG RI… 5023222    TRUE      Nov                -4.9 A               
## 12 MB    WINNIPEG RI… 5023222    TRUE      Dec               -13.2 A               
## 13 MB    WINNIPEG RI… 5023222    TRUE      Year                3   A               
## 14 MB    WINNIPEG A … 502S001    FALSE     Jan                NA   <NA>            
## 15 MB    WINNIPEG A … 502S001    FALSE     Feb                NA   <NA>            
## 16 MB    WINNIPEG A … 502S001    FALSE     Mar                NA   <NA>            
## 17 MB    WINNIPEG A … 502S001    FALSE     Apr                NA   <NA>            
## 18 MB    WINNIPEG A … 502S001    FALSE     May                NA   <NA>            
## 19 MB    WINNIPEG A … 502S001    FALSE     Jun                NA   <NA>            
## 20 MB    WINNIPEG A … 502S001    FALSE     Jul                NA   <NA>            
## 21 MB    WINNIPEG A … 502S001    FALSE     Aug                NA   <NA>            
## 22 MB    WINNIPEG A … 502S001    FALSE     Sep                NA   <NA>            
## 23 MB    WINNIPEG A … 502S001    FALSE     Oct                NA   <NA>            
## 24 MB    WINNIPEG A … 502S001    FALSE     Nov                NA   <NA>            
## 25 MB    WINNIPEG A … 502S001    FALSE     Dec                NA   <NA>            
## 26 MB    WINNIPEG A … 502S001    FALSE     Year               NA   <NA>            
## 27 MB    WINNIPEG TH… 5023262    FALSE     Jan                NA   <NA>            
## 28 MB    WINNIPEG TH… 5023262    FALSE     Feb                NA   <NA>            
## 29 MB    WINNIPEG TH… 5023262    FALSE     Mar                NA   <NA>            
## 30 MB    WINNIPEG TH… 5023262    FALSE     Apr                NA   <NA>            
## 31 MB    WINNIPEG TH… 5023262    FALSE     May                NA   <NA>            
## 32 MB    WINNIPEG TH… 5023262    FALSE     Jun                NA   <NA>            
## 33 MB    WINNIPEG TH… 5023262    FALSE     Jul                NA   <NA>            
## 34 MB    WINNIPEG TH… 5023262    FALSE     Aug                NA   <NA>            
## 35 MB    WINNIPEG TH… 5023262    FALSE     Sep                NA   <NA>            
## 36 MB    WINNIPEG TH… 5023262    FALSE     Oct                NA   <NA>            
## 37 MB    WINNIPEG TH… 5023262    FALSE     Nov                NA   <NA>            
## 38 MB    WINNIPEG TH… 5023262    FALSE     Dec                NA   <NA>            
## 39 MB    WINNIPEG TH… 5023262    FALSE     Year               NA   <NA>            
## # … with 195 more variables

To visualize missing data we can use the gg_miss_var() function from the naniar package.

select(normals, -contains("_code")) %>%  # Remove '_code' columns
  gg_miss_var(facet = station_name)
suppressWarnings({select(normals, -contains("_code")) %>%  # Remove '_code' columns
    gg_miss_var(facet = station_name)})

Let’s take a look at the frost data.

if("normals" %in% names(frost)) frost <- select(frost, -normals) # tidyr v1
glimpse(frost)
## Rows: 7
## Columns: 12
## $ prov                                  <chr> "MB", "MB", "MB", "MB", "MB", "MB", "MB"
## $ station_name                          <chr> "WINNIPEG RICHARDSON INT'L A", "WINNIPEG …
## $ climate_id                            <chr> "5023222", "5023222", "5023222", "5023222…
## $ meets_wmo                             <lgl> TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE
## $ frost_code                            <chr> "A", "A", "A", "A", "A", "A", "A"
## $ date_first_fall_frost                 <dbl> 265, 265, 265, 265, 265, 265, 265
## $ date_last_spring_frost                <dbl> 143, 143, 143, 143, 143, 143, 143
## $ length_frost_free                     <dbl> 121, 121, 121, 121, 121, 121, 121
## $ prob                                  <fct> 10%, 25%, 33%, 50%, 66%, 75%, 90%
## $ prob_first_fall_temp_below_0_on_date  <dbl> 255, 259, 261, 265, 268, 270, 276
## $ prob_length_frost_free                <dbl> 96, 109, 114, 119, 126, 129, 141
## $ prob_last_spring_temp_below_0_on_date <dbl> 158, 152, 148, 144, 140, 137, 129

Finding stations with specific measurements

The include data frame, normals_measurements contains a list of stations with their corresponding measurements. Be aware that this data might be out of date!

normals_measurements
## # A tibble: 113,325 x 4
##    prov  station_name climate_id measurement            
##    <chr> <chr>        <chr>      <chr>                  
##  1 AB    HORBURG      301C3D4    temp_daily_average     
##  2 AB    HORBURG      301C3D4    temp_daily_average_code
##  3 AB    HORBURG      301C3D4    temp_sd                
##  4 AB    HORBURG      301C3D4    temp_sd_code           
##  5 AB    HORBURG      301C3D4    temp_daily_max         
##  6 AB    HORBURG      301C3D4    temp_daily_max_code    
##  7 AB    HORBURG      301C3D4    temp_daily_min         
##  8 AB    HORBURG      301C3D4    temp_daily_min_code    
##  9 AB    HORBURG      301C3D4    temp_extreme_max       
## 10 AB    HORBURG      301C3D4    temp_extreme_max_code  
## # … with 113,315 more rows

For example, if you wanted all climate_ids for stations that have data on soil temperature

normals_measurements %>%
  filter(stringr::str_detect(measurement, "soil")) %>%
  pull(climate_id) %>%
  unique()
##  [1] "3070560" "1100119" "112G8L1" "8502800" "8403605" "2403500" "6073960" "6105976"
##  [9] "4028060" "4043900" "4075518" "2100630"

Understanding Climate Normals

The measurements contained in the climate normals are very specific. To better understand how they are calculated please explore the following resources: