Mapping Weather Data

weathercan
sf
GIS
leaflet
R
Published

September 20, 2023

[2023-09-20] Until recently, this article was part of the documentation for the weathercan package. To simplify the docs while retaining this article, I’ve decided to move it here.

This example is a bit dated (it isn’t the most modern approach), and is lacking in detailed explanations. However, I hope this is still useful as a more advanced example of how data can be combined using different types of tools.

This article is based on the blog post Integrating data from weathercan written for rOpenSci March 6th 2018.

In that article I demonstrated how we can incorporate data from weathercan into spatial visualizations. In this article I’d like to take that even further and show you how you can create interactive maps which highlight spatial variability in weather data.

Here, we’ll take a look at annual temperatures throughout different Eco Regions in Manitoba, Canada.

Setup

Using extra CSS styles

The map that we create here may look different for you unless you include the tweaks to the CSS styles I have made. If you’re using RMarkdown, you can supply these as a custom .css file, or inline with the <style> and </style> tags (like below).

<style>
div.leaflet-popup-content-wrapper {
  width: 700px;
  height: 100%;
}

div.leaflet-popup-tip-container {
  opacity: 0;
}

div.leaflet-popup-content {
  width: 90% !important;
}

img {
  max-width: 90% !important;
  min-width: 90% !important;
  border: none;
}

/* Fix the NA mis-alignment in the legend */
div.info.legend.leaflet-control br {
  clear: both;
}
</style>

Loading packages

Download Manitoban Eco Regions shapefile

download.file("http://mli2.gov.mb.ca/environment/shp_zip_files/env_ecological_areas_py_shp.zip",
              destfile = "ecological_shp.zip")
unzip("ecological_shp.zip")
file.remove("ecological_shp.zip")
[1] TRUE

Download Manitoba weather data

We’ll select all currently operating stations (end >= 2018) and download the daily weather data for 2017:

mb <- filter(stations(), prov == "MB", interval == "day", end >= 2018)
w <- weather_dl(mb$station_id, start = "2017-01-01", end = "2017-12-31", interval = "day")

Calculating summaries

In this section, we’ll summarize our data and create the means of showcasing it in our map. We’ll calculate some basic summaries and we’ll style some popups to contain this information (including the figures we’ll create later).

We’ll do a station-specific summaries/pop-ups for when users click on a station marker, and region-specific ones for when they click on the region polygon.

Station summaries

mb_stations <- w %>%
  group_by(station_id) %>%
  mutate(n = n(),
         n_missing = sum(is.na(mean_temp)),
         mean_temp = mean(mean_temp, na.rm = TRUE)) %>%
  filter((n - n_missing) > 0) %>% # Only keep stations with some temperature data
  select(station_name, station_id, lat, lon, mean_temp, n, n_missing) %>%
  distinct() %>%
  mutate(station_name = tools::toTitleCase(tolower(station_name)),
         info = paste0("<h3>Station: ", station_name, " (", station_id, ")</h2>",
                       "<hr>",
                       "<div>",
                       "<strong>Mean Temperature: </strong>", round(mean_temp, 1), "C<br>",
                       "<strong>No. days with data:  </strong>", n-n_missing, "<br>",
                       "<strong>No. days total:  </strong>", n, "</div>",
                       "<img src = 'svg/", station_id, ".svg'>"),
         pretty_name = map(station_name, 
                           ~HTML(paste0("<strong>Station: </strong>", .x)))) %>%
  ungroup() %>%
  st_as_sf(coords = c("lon", "lat"), crs = "+proj=longlat")

Eco Region summaries

Before we summarize this data, we’ll filter the Eco Regions to just Manitoba and will join this to the stations data (after transforming the stations data to the same CRS), so we can figure out which stations belong to which regions.

mb_ecoregions <- st_read("env_ecological_areas.shp") %>%
  filter(MANITOBA == "yes") %>%
  # Get the larger-scale regions and combine
  group_by(ECOREGION, REGION_NAM, REGION_NOM) %>%
  summarize()
Reading layer `env_ecological_areas' from data source 
  `/home/steffi/Projects/AA Websites/steffilazerte.github.io/posts/weathercan-mapping/env_ecological_areas.shp' 
  using driver `ESRI Shapefile'
Simple feature collection with 279 features and 15 fields
Geometry type: POLYGON
Dimension:     XY
Bounding box:  xmin: -621621.3 ymin: 5386414 xmax: 1868189 ymax: 7166472
Projected CRS: NAD83 / UTM zone 14N
`summarise()` has grouped output by 'ECOREGION', 'REGION_NAM'. You can override
using the `.groups` argument.
mb_stations <- st_transform(mb_stations, crs = st_crs(mb_ecoregions))
  
mb_ecoregions <- st_join(mb_ecoregions, mb_stations) %>%
  group_by(ECOREGION, REGION_NAM, REGION_NOM) %>%
  summarize(n_stations = length(unique(station_id[!is.na(station_id)])),
            mean_temp = mean(mean_temp, na.rm = TRUE),
            mean_temp = replace(mean_temp, is.nan(mean_temp), NA), 
            .groups = "drop") %>%
  mutate(info = paste0("<h3>Region: ", REGION_NAM, "/", REGION_NOM, " (", ECOREGION, ")</h2>",
                       "<hr>",
                       "<div>",
                       "<strong>Mean Temperature: </strong>", round(mean_temp, 1), 
                       if_else(!is.na(mean_temp), "C<br>", "<br>"),
                       "<strong>No. stations:  </strong>", n_stations, "</div>"),
         info = if_else(n_stations > 0, 
                        paste0(info, "<img src = 'svg/", ECOREGION, ".svg'>"),
                        info),
         pretty_name = map(REGION_NAM, 
                           ~HTML(paste0("<strong>Region: </strong>", .x)))) %>%
  ungroup()

Figures

We’ll set up some functions to create and save figures for our map

plot_station_fig <- function(d, station_id) {
  g <- ggplot(d, aes(x = date, y = mean_temp)) +
    theme_bw() +
    geom_line(na.rm = TRUE) +
    labs(x = "Date", y = "Mean Daily Temperature (C)")
  ggsave(paste0("svg/", station_id, ".svg"), plot = g,
         width = 6, height = 3, dpi = 100)
}

plot_region_fig <- function(d, region) {
  g <- ggplot(d, aes(x = date, y = mean_temp, 
                group = station_name, colour = station_name)) +
    theme_bw() +
    geom_line(na.rm = TRUE) +
    scale_colour_viridis_d(end = 0.8) +
    labs(x = "Date", y = "Mean Daily Temperature (C)", colour = "Stations")
  ggsave(paste0("svg/", region, ".svg"), plot = g,
         width = 6, height = 3, dpi = 100)
}

Now we’ll apply these functions to our data. Note that this figs object isn’t important, it’s just used as a way to loop through the data and save the figures as svg files.

dir.create("svg")
Warning in dir.create("svg"): 'svg' already exists
figs <- st_join(mb_stations, mb_ecoregions) %>%
  st_drop_geometry %>%
  left_join(select(w, station_id, date, mean_temp), by = "station_id") %>%
  nest(data = -ECOREGION) %>%
  mutate(fig_region = map2(data, ECOREGION, ~plot_region_fig(.x, .y))) %>%
  unnest(data) %>%
  nest(data = c(-ECOREGION, -station_id)) %>%
  mutate(fig_station = map2(data, station_id, ~plot_station_fig(.x, .y)))

Mapping

Finally, we’re ready to create our map!

We’ll start by transforming our data into WGS84 for leaflet, then we’ll create a palette and get some icons…

# Required for Leaflet
mb_ecoregions <- st_transform(mb_ecoregions, crs = 4326)
mb_stations <- st_transform(mb_stations, crs = 4326)

# Setup Palette for polygons
pal_eco <- colorNumeric(palette = "viridis",
                          domain = mb_ecoregions$mean_temp)

# Get icons for stations (red if above average, blue if below)
station_icons <- awesomeIcons(iconColor = "black", library = "ion",
                              markerColor = ifelse(mb_stations$mean_temp > 
                                                     mean(mb_stations$mean_temp, 
                                                          na.rm = TRUE), 
                                                   "red", "blue"))

Now for the real magic!

leaflet(width = "750px", height = "85vh") %>% 
  addTiles() %>%
  addPolygons(data = mb_ecoregions,
              color = "#444444", weight = 1, opacity = 1, fillOpacity = 0.5,
              fillColor = ~pal_eco(mean_temp),
              label = ~pretty_name, popup = ~info,
              popupOptions = popupOptions(keepInView = TRUE),
              highlightOptions = highlightOptions(bringToFront = TRUE, 
                                                  fillOpacity = 1)) %>%
  addAwesomeMarkers(data = mb_stations, group = "Stations",
                    icon = station_icons,
                    label = ~pretty_name, popup = ~info,
                    popupOptions = popupOptions(keepInView = TRUE)) %>%
  addLegend("bottomright", pal = pal_eco,
            values = mb_ecoregions$mean_temp,
            title = "Mean region temperature",
            labFormat = labelFormat(suffix = " C")) %>%
  addLegend("bottomright", 
            title = "Station temperature", 
            colors = c("#d63e2a", "#37a7da"), opacity = 1, 
            labels = c("Above the average", "Below the average")) %>%
  addLayersControl(
    overlayGroups = "Stations",
    options = layersControlOptions(collapsed = FALSE))

I think this is an interesting way of looking at the Eco Regions in Manitoba.

First we see a clear (and expected) pattern of decreasing temperatures with latitude (South to North). Further, we also see a bit of a South West to North East pattern.

Looking at the Eco Regions like this gives a clear idea of some of the parameters that make these Eco Regions distinct. For example, the patch of lands in the lower left corner of the province are the Mid-Boreal Uplands and the Boreal Transition. See how much cooler they are (on average) than the rest of southern Manitoba.

These southern Boreal regions represent a distinct ecology in southern Manitoba. If you zoom in on the map, you’ll see that they also hold two parks: Duck Mountain Provincial Park and Riding Mountain National Park.

Session Info

devtools::session_info()
─ Session info ───────────────────────────────────────────────────────────────
 setting  value
 version  R version 4.3.3 (2024-02-29)
 os       Ubuntu 22.04.4 LTS
 system   x86_64, linux-gnu
 ui       X11
 language en_CA:en
 collate  en_CA.UTF-8
 ctype    en_CA.UTF-8
 tz       America/Winnipeg
 date     2024-03-15
 pandoc   3.1.1 @ /usr/lib/rstudio/resources/app/bin/quarto/bin/tools/ (via rmarkdown)

─ Packages ───────────────────────────────────────────────────────────────────
 package      * version    date (UTC) lib source
 bit            4.0.5      2022-11-15 [1] CRAN (R 4.3.0)
 bit64          4.0.5      2020-08-30 [1] CRAN (R 4.3.0)
 cachem         1.0.8      2023-05-01 [1] CRAN (R 4.3.0)
 class          7.3-22     2023-05-03 [4] CRAN (R 4.3.1)
 classInt       0.4-10     2023-09-05 [1] CRAN (R 4.3.1)
 cli            3.6.2      2023-12-11 [1] CRAN (R 4.3.2)
 codetools      0.2-19     2023-02-01 [4] CRAN (R 4.2.2)
 colorspace     2.1-0      2023-01-23 [1] CRAN (R 4.3.0)
 crayon         1.5.2      2022-09-29 [1] CRAN (R 4.3.0)
 crosstalk      1.2.1      2023-11-23 [1] CRAN (R 4.3.2)
 curl           5.2.1      2024-03-01 [1] CRAN (R 4.3.2)
 DBI            1.2.2      2024-02-16 [1] CRAN (R 4.3.2)
 devtools       2.4.5      2022-10-11 [1] CRAN (R 4.3.0)
 digest         0.6.34     2024-01-11 [1] CRAN (R 4.3.2)
 dplyr        * 1.1.4      2023-11-17 [1] CRAN (R 4.3.2)
 e1071          1.7-14     2023-12-06 [1] CRAN (R 4.3.2)
 ellipsis       0.3.2      2021-04-29 [1] CRAN (R 4.3.0)
 evaluate       0.23       2023-11-01 [1] CRAN (R 4.3.1)
 fansi          1.0.6      2023-12-08 [1] CRAN (R 4.3.2)
 farver         2.1.1      2022-07-06 [1] CRAN (R 4.3.0)
 fastmap        1.1.1      2023-02-24 [1] CRAN (R 4.3.0)
 fs             1.6.3      2023-07-20 [1] CRAN (R 4.3.1)
 generics       0.1.3      2022-07-05 [1] CRAN (R 4.3.0)
 ggplot2      * 3.5.0      2024-02-23 [1] CRAN (R 4.3.2)
 glue           1.7.0      2024-01-09 [1] CRAN (R 4.3.2)
 gridExtra      2.3        2017-09-09 [1] CRAN (R 4.3.0)
 gtable         0.3.4      2023-08-21 [1] CRAN (R 4.3.1)
 hms            1.1.3      2023-03-21 [1] CRAN (R 4.3.0)
 htmltools    * 0.5.7      2023-11-03 [1] CRAN (R 4.3.1)
 htmlwidgets    1.6.4      2023-12-06 [1] CRAN (R 4.3.2)
 httpuv         1.6.14     2024-01-26 [1] CRAN (R 4.3.2)
 httr           1.4.7      2023-08-15 [1] CRAN (R 4.3.1)
 jquerylib      0.1.4      2021-04-26 [1] CRAN (R 4.3.0)
 jsonlite       1.8.8      2023-12-04 [1] CRAN (R 4.3.2)
 KernSmooth     2.23-22    2023-07-10 [1] CRAN (R 4.3.1)
 knitr          1.45       2023-10-30 [1] CRAN (R 4.3.1)
 labeling       0.4.3      2023-08-29 [1] CRAN (R 4.3.1)
 later          1.3.2      2023-12-06 [1] CRAN (R 4.3.2)
 leaflet      * 2.2.1      2023-11-13 [1] CRAN (R 4.3.2)
 lifecycle      1.0.4      2023-11-07 [1] CRAN (R 4.3.2)
 lubridate      1.9.3      2023-09-27 [1] CRAN (R 4.3.1)
 lutz           0.3.2      2023-10-17 [1] CRAN (R 4.3.1)
 magrittr       2.0.3      2022-03-30 [1] CRAN (R 4.3.0)
 memoise        2.0.1      2021-11-26 [1] CRAN (R 4.3.0)
 mime           0.12       2021-09-28 [1] CRAN (R 4.3.0)
 miniUI         0.1.1.1    2018-05-18 [1] CRAN (R 4.3.0)
 munsell        0.5.0      2018-06-12 [1] CRAN (R 4.3.0)
 pillar         1.9.0      2023-03-22 [1] CRAN (R 4.3.0)
 pkgbuild       1.4.3      2023-12-10 [1] CRAN (R 4.3.2)
 pkgconfig      2.0.3      2019-09-22 [1] CRAN (R 4.3.0)
 pkgload        1.3.3      2023-09-22 [1] CRAN (R 4.3.1)
 profvis        0.3.8      2023-05-02 [1] CRAN (R 4.3.1)
 promises       1.2.1      2023-08-10 [1] CRAN (R 4.3.1)
 proxy          0.4-27     2022-06-09 [1] CRAN (R 4.3.0)
 purrr        * 1.0.2      2023-08-10 [1] CRAN (R 4.3.1)
 R6             2.5.1      2021-08-19 [1] CRAN (R 4.3.0)
 ragg           1.2.6      2023-10-10 [1] CRAN (R 4.3.1)
 rappdirs       0.3.3      2021-01-31 [1] CRAN (R 4.3.0)
 RColorBrewer   1.1-3      2022-04-03 [1] CRAN (R 4.3.0)
 Rcpp           1.0.12     2024-01-09 [1] CRAN (R 4.3.2)
 readr          2.1.5      2024-01-10 [1] CRAN (R 4.3.2)
 remotes        2.4.2.1    2023-07-18 [1] CRAN (R 4.3.2)
 rlang          1.1.3      2024-01-10 [1] CRAN (R 4.3.2)
 rmarkdown      2.25       2023-09-18 [1] CRAN (R 4.3.1)
 rstudioapi     0.15.0     2023-07-07 [1] CRAN (R 4.3.1)
 s2             1.1.6      2023-12-19 [1] CRAN (R 4.3.2)
 scales         1.3.0      2023-11-28 [1] CRAN (R 4.3.2)
 sessioninfo    1.2.2      2021-12-06 [1] CRAN (R 4.3.0)
 sf           * 1.0-15     2023-12-18 [1] CRAN (R 4.3.2)
 shiny          1.8.0      2023-11-17 [1] CRAN (R 4.3.2)
 stringi        1.8.3      2023-12-11 [1] CRAN (R 4.3.2)
 stringr      * 1.5.1      2023-11-14 [1] CRAN (R 4.3.2)
 svglite        2.1.3      2023-12-08 [1] CRAN (R 4.3.2)
 systemfonts    1.0.5      2023-10-09 [1] CRAN (R 4.3.1)
 textshaping    0.3.7      2023-10-09 [1] CRAN (R 4.3.1)
 tibble         3.2.1      2023-03-20 [1] CRAN (R 4.3.0)
 tidyr        * 1.3.1      2024-01-24 [1] CRAN (R 4.3.2)
 tidyselect     1.2.0      2022-10-10 [1] CRAN (R 4.3.0)
 timechange     0.3.0      2024-01-18 [1] CRAN (R 4.3.2)
 tzdb           0.4.0      2023-05-12 [1] CRAN (R 4.3.1)
 units          0.8-5      2023-11-28 [1] CRAN (R 4.3.2)
 urlchecker     1.0.1      2021-11-30 [1] CRAN (R 4.3.0)
 usethis        2.2.2      2023-07-06 [1] CRAN (R 4.3.1)
 utf8           1.2.4      2023-10-22 [1] CRAN (R 4.3.1)
 vctrs          0.6.5      2023-12-01 [1] CRAN (R 4.3.2)
 viridis        0.6.5      2024-01-29 [1] CRAN (R 4.3.2)
 viridisLite    0.4.2      2023-05-02 [1] CRAN (R 4.3.1)
 vroom          1.6.5      2023-12-05 [1] CRAN (R 4.3.2)
 weathercan   * 0.7.0.9000 2023-09-20 [1] local
 withr          3.0.0      2024-01-16 [1] CRAN (R 4.3.2)
 wk             0.9.1      2023-11-29 [1] CRAN (R 4.3.2)
 xfun           0.42       2024-02-08 [1] CRAN (R 4.3.2)
 xtable         1.8-4      2019-04-21 [1] CRAN (R 4.3.0)
 yaml           2.3.8      2023-12-11 [1] CRAN (R 4.3.2)

 [1] /home/steffi/R/x86_64-pc-linux-gnu-library/4.3
 [2] /usr/local/lib/R/site-library
 [3] /usr/lib/R/site-library
 [4] /usr/lib/R/library

──────────────────────────────────────────────────────────────────────────────