El código fuente de este documento está disponible en https://github.com/pf0953-programaciongeoespacialr-2020/leccion-08-r-leaflet.

Recursos de interés

Preparativos

Instalación de paquetes:

# Leaflet
install.packages("leaflet")

# tidyr
install.packages("tidyr")

Carga de paquetes:

# Leaflet
library(leaflet)

# sf
library(sf)

# tidyr
library(tidyr)
## Warning: package 'tidyr' was built under R version 4.0.3
# dplyr
library(dplyr)

Introducción

Leaflet es una de las bibliotecas más utilizadas para la creación de mapas interactivos en la Web. Está escrita en el lenguaje JavaScript y también puede utilizarse a través de otros lenguajes de programación, como Python y R.

El paquete Leaflet permite acceder la funcionalidad de Leaflet a través de R. Entre las capacidades que proporciona Leaflet están:

  • Capas base (ej. OpenStreetMap, Stamen, ESRI).
  • Capas vectoriales y raster.
  • Mapas temáticos (ej. coropletas).
  • Marcadores.
  • Acercamientos (zoom in) y alejamientos (zoom out).
  • Leyendas.
  • Escalas.

Uso básico

Los pasos básicos para la creación de un mapa con Leaflet son: 1. Crear un widget mediante un llamado a la función leaflet().
2. Añadir capas (mapas base, marcadores, puntos, líneas, polígonos, etc.).
3. Añadir controles (ej. leyenda, escala).
4. Desplegar el mapa.

El siguiente ejemplo ilustra estos pasos:

# Definición de mapa con capa base y con marcador 
m <- leaflet() %>%
  addTiles() %>%  # Añadir capa base
  addMarkers(
    lng=-84.0427264, lat=9.9380638, 
    popup="Escuela de Geografía de la Universidad de Costa Rica"
  ) 

# Despliegue del mapa
m

Capas base

El método addProviderTiles() permite añadir mapas de teselas, generalmente como capas base de un mapa. El sitio Leaflet Provider Demo proporciona una lista de capas base que pueden utilizarse.

# Definición de mapa con capa base y con marcador 
m <- leaflet() %>%
  addTiles() %>% # Agrega una capa base de OSM
  addProviderTiles(providers$Stamen.TonerLite, group = "Stamen Toner Lite") %>%
  addProviderTiles(providers$Esri.WorldImagery, group = "Imágenes de ESRI") %>% 
  addMarkers(lng=-84.0427264, lat=9.9380638, 
             popup="Escuela de Geografía de la Universidad de Costa Rica"
  ) %>%  
  addLayersControl(
    baseGroups = c("OpenStreetMap", "Stamen Toner Lite", "Imágenes de ESRI")
  )

# Despliegue del mapa
m

Controles

El siguiente ejemplo ilustra el uso de método para añadir controles, como addLayersControl() (leyenda) y addMiniMap() (mapa de referencia). También se ejemplifica el uso de addCircleMarkers().

mammalia <- 
  st_read("https://raw.githubusercontent.com/pf0953-programaciongeoespacialr-2020/datos/master/biodiversidad/registros-presencia/cr/gam/mammalia.geojson")
## Reading layer `mammalia-amphibia-reptilia-aves-plantae' from data source `https://raw.githubusercontent.com/pf0953-programaciongeoespacialr-2020/datos/master/biodiversidad/registros-presencia/cr/gam/mammalia.geojson' using driver `GeoJSON'
## Simple feature collection with 1140 features and 5 fields
## geometry type:  POINT
## dimension:      XY
## bbox:           xmin: -84.45085 ymin: 9.74913 xmax: -83.76667 ymax: 10.11853
## geographic CRS: WGS 84
m <- leaflet() %>% 
  addProviderTiles(providers$Esri.WorldImagery, group = "Imágenes de ESRI") %>% 
  addProviderTiles(providers$Stamen.TonerLite, group = "Stamen Toner Lite") %>%
  addProviderTiles(providers$OpenStreetMap.Mapnik, group = "OpenStreetMap") %>%
  addCircleMarkers(
    data = mammalia,
    stroke = F,
    radius = 4,
    fillColor = 'red',
    fillOpacity = 1,
    popup = paste(mammalia$order, mammalia$species, sep = '<br/>')
  ) %>%
  addLayersControl(
    baseGroups = c("OpenStreetMap", "Stamen Toner Lite", "Imágenes de ESRI")
  ) %>%
  addMiniMap(
    toggleDisplay = TRUE,
    tiles = providers$Stamen.TonerLite
  )

# Despliegue del mapa
m

Mapas de coropletas

En el siguiente ejemplo. se cargan en un objeto sf los datos de casos activos de COVID-19 en los cantones de Costa Rica, de acuerdo con la información publicada por el Ministerio de Salud de Costa Rica. Para procesar y transformar los datos, se utilizan los paquetes dplyr y tidyr.

# Lectura de la capa de cantones de un archivo GeoJSON
sf_cantones <-
  st_read(
          "https://raw.githubusercontent.com/taller-r-jornadas-sigtd-2020/datos/master/cantones.geojson", 
          quiet = T
)

# Data frame de casos activos por cantón, con fechas en las columnas
df_activos_cantones_ancho <- 
  read.csv(
    "https://raw.githubusercontent.com/pf0953-programaciongeoespacialr-2020/datos/master/covid19/ms/covid19-activos-cantones-20201020.csv"
    )

# Data frame con fechas en las filas
df_activos_cantones <-
  df_activos_cantones_ancho %>%
  pivot_longer(
    cols = c(-cod_provin, -provincia, -cod_canton, -canton), 
    names_to = "fecha", 
    values_to = "activos"
  )

# Cambio de tipo de la columna "fecha"
df_activos_cantones$fecha <- as.Date(df_activos_cantones$fecha, "X%d.%m.%Y")

# Data frame de casos activos por cantón en la última fecha
df_activos_cantones_ultima_fecha <- 
  df_activos_cantones %>%
  filter(fecha == max(fecha, na.rm = TRUE)) %>%
  select(cod_canton, activos)

# Objeto sf de casos activos en cantones en la última fecha
sf_activos_cantones_ultima_fecha <-
  left_join(sf_cantones, df_activos_cantones_ultima_fecha, by = c('cod_canton')) %>%
  arrange(desc(activos))

Luego, se utiliza Leaflet para construir un mapa de coropletas.

bins <- c(0, 100, 500, 1000, 2000, Inf)
paleta_azul <- colorBin("YlOrRd", domain = sf_activos_cantones_ultima_fecha$activos, bins = bins)

leaflet(sf_activos_cantones_ultima_fecha) %>% 
  fitBounds(lng1 = -86, lng2 = -82, lat1 = 8, lat2 = 11) %>%
  addProviderTiles(providers$OpenStreetMap.Mapnik, group = "OpenStreetMap") %>%
  addPolygons(fillColor = ~paleta_azul(activos), stroke=T, fillOpacity = 1,
              color="black", weight=0.2, opacity= 0.5,
              group = "Cantones",
              popup = paste(
                        "Provincia: ", sf_activos_cantones_ultima_fecha$provincia, "<br>",
                        "Cantón: ", sf_activos_cantones_ultima_fecha$canton, "<br>",
                        "activos: ", sf_activos_cantones_ultima_fecha$activos
                      )
  ) %>%
  addLegend("bottomright", pal = paleta_azul, values = ~activos,
    title = "Casos activos",
    opacity = 1
  ) %>%  
  addLayersControl(
    baseGroups = c("OpenStreetMap"),
    overlayGroups = c("Cantones"),
    options = layersControlOptions(collapsed = TRUE)    
  ) %>%  
  addMiniMap(
    toggleDisplay = TRUE,
    position = "bottomleft",
    tiles = providers$OpenStreetMap.Mapnik
  )