Leaflet population maps

J. Miettinen

2019/10/20

Maps are a very informative way of displaying data. In this example we are going to visualize population size by postcoded areas to a map with Leaflet, geofi and pxweb R-packages. With following code map of population statistics can be plotted reproducible. Visit links below to get more information of the packages and pxweb API:

Load necessary libraries

First you need to have packages available in your R instance. Package geofi can be installed from Github repo with following command

remotes::install_github("ropengov/geofi")

Other packages you can find from CRAN. Install them with install.packages() function if not already.

# Load necessary packages
library(geofi)
## 
## geofi R package: tools for open GIS data for Finland.
## Part of rOpenGov <ropengov.github.io>.
library(ggplot2)
library(leaflet)
library(dplyr)
## 
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
## 
##     filter, lag
## The following object is masked from '.env':
## 
##     n
## The following objects are masked from 'package:base':
## 
##     intersect, setdiff, setequal, union
library(janitor)
## 
## Attaching package: 'janitor'
## The following objects are masked from 'package:stats':
## 
##     chisq.test, fisher.test
library(pxweb)
## pxweb: R tools for PX-WEB API.
## Copyright (C) 2014-2018 Mans Magnusson, Leo Lahti et al.
## https://github.com/ropengov/pxweb
library(tidyr)

Download and prepare datasets

For this example we are going to plot population size by postcoded areas of city of Kuopio. First download spatial data with geofi package.

## Get post code map data 
municipalities <- get_municipalities(year = 2019) %>% filter(nimi == "Kuopio")
## Requesting response from: http://geo.stat.fi/geoserver/wfs?service=WFS&version=1.0.0&request=getFeature&typename=tilastointialueet%3Akunta4500k_2019
## Warning: Coercing CRS to epsg:3067 (ETRS89 / TM35FIN)
## Data is licensed under: Attribution 4.0 International (CC BY 4.0)
zipcodes <- get_zipcodes(year = 2019) %>% filter(kunta == municipalities$kunta)
## Requesting response from: http://geo.stat.fi/geoserver/wfs?service=WFS&version=1.0.0&request=getFeature&typename=postialue%3Apno_2019
## Warning: Coercing CRS to epsg:3067 (ETRS89 / TM35FIN)
## Data is licensed under: Attribution 4.0 International (CC BY 4.0)

After this, let’s download population statistics data with pxweb-package and shape data format a bit

## Get stat.fi data 
pxweb_query_list <- list("Postinumeroalue" = zipcodes$posti_alue,
                         "Tiedot" = c("He_vakiy", 
                                      "He_kika"))
px_data <- pxweb_get(url = "http://pxnet2.stat.fi/PXWeb/api/v1/fi/Postinumeroalueittainen_avoin_tieto/2019/paavo_1_he_2019.px",
                     query = pxweb_query_list)
# wrangle to data frame
tk_data <- as.data.frame(px_data, column.name.type = "text", variable.value.type = "text")
## Warning in pxweb_as_data_frame.pxweb_data(x, row.names = row.names, optional =
## optional, : NAs introduced by coercion
tk_data <- tk_data %>% 
  rename(avointieto = `Paavo - Postinumeroalueittainen avoin tieto 2019`) %>% 
  mutate(posti_alue = substr(Postinumeroalue, 1,5)) %>% 
  spread(Tiedot, avointieto) %>% 
  janitor::clean_names() %>% 
  as_tibble()

Join spatial and population datasets together

## Join datasets and transform to leaflet data
dat <- left_join(zipcodes, tk_data)
## Joining, by = "posti_alue"
zipcodes_lonlat <- sf::st_transform(x = dat, crs = "+proj=longlat +datum=WGS84")

Plotting a leaflet map

Plot interactive map with leaflet package

## Plot leaflet map 
leaflet(zipcodes_lonlat, height=720, width=720) %>% 
  # Add the OSM, CartoDB and Esri tiles
  addTiles(group = "OSM") %>% 
  addProviderTiles("CartoDB", group = "CartoDB") %>% 
  addProviderTiles("Esri", group = "Esri") %>% 
  # Use addLayersControl to allow users to toggle between basemaps
  addLayersControl(baseGroups = c("OSM", "CartoDB", "Esri")) %>% 
  addPolygons(color = "coral", 
              weight = 1,
              smoothFactor = .5,
              opacity = .9,
              fillColor = ~colorBin(palette = "plasma", asukkaat_yhteensa_2017_he)(asukkaat_yhteensa_2017_he),
              fillOpacity = 0.5,
              label = ~paste0(nimi, " (", posti_alue ,") ", asukkaat_yhteensa_2017_he, " asukasta, keski-ikä ",asukkaiden_keski_ika_2017_he," vuotta"),
              highlightOptions = highlightOptions(color = "white", 
                                                  weight = 2,
                                                  bringToFront = TRUE)) %>% 
  setView(lat = 62.89238, lng = 27.67703, zoom=8)

With small changes in code, you can plot different municipalities or even whole countrys population to a map. For more examples, check GitHub project https://github.com/janikmiet/example_maps