Mapas dinámicos con leaflet

El paquete leaflet permite crear mapas dinámicos e interactivos utilizando la librería Leaflet de JavaScript. La principal ventaja de utilizar leaflet frente a otras alternativas es su flexibilidad y que su implementación en R es realmente sencilla de usar.

Para crear un mapa básico tendrás que cargar la librería y luego utilizar la función leaflet para después poder cargar capas con el operador pipe (%>%). Con addTiles agregarás el mapa base por defecto y con setView podrás establecer el punto central y un nivel de zoom.

library(leaflet)

leaflet() %>%
  addTiles() %>%
  setView(lng = -3.7, lat = 40.4, zoom = 5)

Marcadores

Es posible añadir diferentes tipos de marcadores a los mapas. Las funciones principales son addMarkers, que agregará marcadores con iconos (que además permite agregar iconos personalizados) y addCircleMarkers, que agregará marcadores circulares que pueden ser personalizados.

Puedes agregar un único marcador al gráfico pasando sus coordenadas a los argumentos lng (longitud) y lat (latitud) de la función addMarkers. Recuerda que la función permite pasar un único valor o un vector para cada argumento.

library(leaflet)

leaflet() %>%
  addTiles() %>%
  setView(lng = -3.7, lat = 40.4, zoom = 5) %>%
  addMarkers(lng = -3.7, lat = 40.4)

Marcadores a partir de un data frame

Ten en cuenta que existen varias maneras de agregar datos. Por ejemplo, si tus datos provienen de un data frame puedes pasar el data frame a data. Recuerda que en este caso los nombres de columna deben ser lng y lat.

library(leaflet)

leaflet() %>%
  addTiles() %>%
  setView(lng = -3.7, lat = 40.4, zoom = 5) %>%
  addMarkers(data = data.frame(lng = c(-3.7, -8, -4.2), lat = c(40.4, 43.1, 41.4)))

Marcadores con iconos personalizados

Un argumento muy útil de la función addMarkers es icon, ya que permite pasar una lista para establecer marcadores personalizados. La lista se puede crear manualmente o con icons, una función que requiere al menos, especificar en enlace a la imagen o imágenes del icono con iconUrl, así como el grosor y altura del icono con iconWidth y iconHeight, respectivamente, para establecer el tamaño de todos o cada uno de los iconos.

library(leaflet)

# Data
df <- data.frame(lng = c(12.5, 14.3, 11.234),
                 lat = c(42, 41, 43.84),
                 group = c("A", "B", "A"))

# Icons
lista_iconos <- icons(iconUrl = ifelse(df$group == "A", 
                     'https://raw.githubusercontent.com/R-CoderDotCom/samples/main/marker.png',
                      ifelse(df$group == "B", "https://raw.githubusercontent.com/R-CoderDotCom/chinchet/main/inst/red.png", NA)),
                      iconWidth = c(50, 90, 40), iconHeight = c(50, 90, 40))

leaflet() %>%
  addTiles() %>%
  setView(lng = 12.43, lat = 42.98, zoom = 6) %>%
  addMarkers(data = df, icon = lista_iconos)

Marcadores circulares

Los marcadores circulares se pueden añadir al mapa con addCircleMarkers. Estos marcadores funcionan de la misma manera que los anteriores, pero la diferencia principal es que puedes personalizar su color con color y su radio, en píxeles, con radius.

library(leaflet)

circulos <- data.frame(lng = c(23.59, 34.95, 17.47),
                       lat = c(-3.53, -6.32, -12.24))

leaflet() %>%
  addTiles() %>%
  addCircleMarkers(data = circulos, color = "red")

Polígonos

Puedes agregar polígonos o geometrías espaciales a los mapas a partir de archivos shapefile o geojson. Tendrás que importar tus datos con sf, rgdal o un paquete similar, aunque utilizaremos sf en nuestros ejemplos. Para importar los polígonos tendrás que pasar los datos de entrada a la función addPolygons.

library(leaflet)
library(sf)

# Lee un Geojson o shapefile
data_map <- read_sf("https://raw.githubusercontent.com/R-CoderDotCom/data/main/sample_geojson.geojson")

# Transforma a la proyección de leaflet si es necesario
data_map <- st_transform(data_map, crs = '+proj=longlat +datum=WGS84')

leaflet() %>%
  addTiles() %>%
  setView(lng = -0.49, lat = 38.34, zoom = 14) %>%
  addPolygons(data = data_map, color = "blue", stroke = 1, opacity = 0.8)

Ten en cuenta que dependiendo de tus datos también tendrás que transformarlos a la proyección de leaflet (+proj=longlat +datum=WGS84).

Círculos

Puedes dibujar círculos con la función addCircles. Estos círculos son muy similares a los marcadores circulares, pero en este caso el radio (radius) se establece en metros en lugar de píxeles y por tanto pueden ser utilizados, por ejemplo, para dibujar áreas de influencia.

library(leaflet)

circulos <- data.frame(lng = c(-3.7, -3.72),
                       lat = c(40.4, 40.42))

leaflet() %>%
  addTiles() %>%
  setView(lng = -3.7, lat = 40.4, zoom = 13) %>%
  addCircleMarkers(data = circulos, color = "red") %>%
  addCircles(data = circulos, radius = 2000)

Rectángulos

En lugar de círculos puedes agregar rectángulos con addRectangles, pero tendrás que pasar las coordenadas de las esquinas suroeste (lng1 y lat1) y noreste (lng2 y lat2) del rectángulo a ser dibujado.

library(leaflet)

leaflet() %>%
  addTiles() %>%
  setView(lng = -77.04, lat = -12.05, zoom = 11) %>%
  addRectangles(lng1 = -77.08, lat1 = -12.1,
                lng2 = -76.95, lat2 = -11.98)

Colores

Los colores de los círculos, rectángulos, polígonos y otros elementos se pueden personalizar con color y su transparencia con opacity. Algunos elementos, como los círculos, incluyen los argumentos fillColor y fillOpacity que cambiarán el color de fondo mientras que los otros argumentos servirán para cambiar el color del borde, como en el ejemplo siguiente.

library(leaflet)

circulos <- data.frame(lng = c(-3.7, -3.72),
                       lat = c(40.4, 40.42))

leaflet() %>%
  addTiles() %>%
  setView(lng = -3.7, lat = 40.4, zoom = 13) %>%
  addCircles(data = circulos, radius = 2000,
             color = "blue",  opacity = 1,
             fillColor = "red", fillOpacity = 0.25)

Puedes pasar un vector de colores como entrada en base a ciertas condiciones, e.g. ifelse(data$var > 1, "red", "blue") asignará color rojo a los valores mayores a uno y azul en otro caso.

Paleta de colores continua

También puedes asignar una paleta de colores continua a los elementos. Para ello puedes utilizar una función que mapee los colores, como colorNumeric y luego tendrás que aplicar la paleta a color. En el siguiente ejemplo creamos un mapa de coropletas en leaflet.

library(leaflet)
library(sf)

# Lee un geojson o shapefile
data_map <- read_sf("https://raw.githubusercontent.com/R-CoderDotCom/data/main/sample_geojson.geojson")

# Transforma a la proyección de leaflet si es necesario
data_map <- st_transform(data_map, crs = '+proj=longlat +datum=WGS84')

# Paleta de colores continua
pal <- colorNumeric(palette = "viridis", domain = data_map$tot_pob)

leaflet() %>%
  addTiles() %>%
  setView(lng = -0.49, lat = 38.34, zoom = 14) %>%
  addPolygons(data = data_map, color = pal(data_map$tot_pob), stroke = 1, opacity = 0.8)

Paleta de colores discreta

Si tus datos están categorizados puedes establecer los colores en base a esa variable. En este escenario, puedes usar una función de color como colorFactor para mapear los grupos a los colores.

library(leaflet)
library(sf)

# Lee un geojson o shapefile
data_map <- read_sf("https://raw.githubusercontent.com/R-CoderDotCom/data/main/sample_geojson.geojson")

# Transforma a la proyección de leaflet si es necesario
data_map <- st_transform(data_map, crs = '+proj=longlat +datum=WGS84')

# Paleta de colores discreta
data_map$tot_pob_cat <- cut(data_map$tot_pob, breaks = 3)
pal <- colorFactor("plasma", levels = levels(data_map$tot_pob_cat))

leaflet() %>%
  addTiles() %>%
  setView(lng = -0.49, lat = 38.34, zoom = 14) %>%
  addPolygons(data = data_map, color = pal(data_map$tot_pob_cat), stroke = 1, opacity = 0.8)

Los pop ups pueden aparecer cuando se hace click sobre un marcador, polígono, rectángulo, etc. haciendo uso del argumento popup. Estos popups se pueden utilizar para mostrar información relevante sobre un punto o región, como por ejemplo su población. El argumento toma como entrada una cadena de caracteres y admite HTML y estilos CSS inline.

library(leaflet)

circulos <- data.frame(lng = c(-73.58, -73.46), lat = c(45.5, 45.55))

leaflet() %>%
  addTiles() %>%
  setView(lng = -73.53, lat = 45.5, zoom = 12) %>%
  addCircles(data = circulos, radius = 2000,
             popup = paste0("Título", "<hr>", "Texto 1", "<br>", "Texto 2")) %>%
  addCircleMarkers(data = circulos,
                   popup = c("A", "B"))

Puede que tengas que ordenar las capas cuando utilices popups. Por ejemplo, si agregas marcadores y luego círculos sobre ellos, no podrás hacer clic sobre los marcadores, por lo que necesitarás agregar los círculos y luego los marcadores y entonces ambos elementos serán clicables.

Mapas base

El estilo de mapa por defecto de addTiles se puede cambiar con addProviderTiles. Tras importar leaflet tendrás acceso a una lista llamada providers cuyos elementos se pueden pasar a la función addProviderTiles, como en los ejemplos siguientes. Revisa esta lista para previsualizar distintos temas.

“CartoDB.Positron”

En este ejemplo establecemos el estilo de mapa llamado CartoDB.Positron, que es muy popular.

library(leaflet)

leaflet() %>%
  addProviderTiles(providers$CartoDB.Positron) %>%
  setView(lng = 13.4, lat = 52.52, zoom = 14)

“Esri.WorldImagery”

En este ejemplo establecemos el tipo de mapa llamado Esri.WorldImagery, que permite visualizar el mapa mediante imágenes reales.

library(leaflet)

leaflet() %>%
  addProviderTiles(providers$Esri.WorldImagery) %>%
  setView(lng = 13.4, lat = 52.52, zoom = 14)

Leyenda

Con addLegend puedes hacer que se muestre una leyenda a los mapas de Leaflet. Tendrás que importar los valores y la paleta de colores correspondiente además de la posición o el título, tal y como se hace en el siguiente bloque de código.

library(leaflet)

circulos <- data.frame(lng = c(-3.7, -8, -4.2),
                      lat = c(40.4, 43.1, 41.4),
                      valores = c(10, 20, 30))

# Paleta de colores continua
# pal <- colorNumeric(palette = "viridis", domain = circulos$valores)

# Paleta de colores discreta
pal <- colorFactor("viridis", levels = circulos$valores)

leaflet() %>%
  addTiles() %>%
  setView(lng = -3.7, lat = 40.4, zoom = 5) %>%
  addCircleMarkers(data = circulos, color = ~pal(valores)) %>%
  addLegend(data = circulos,
            position = "bottomright",
            pal = pal, values = ~valores,
            title = "Legend",
            opacity = 1)

👉 Consejo: utiliza ~ para no tener que especificar el nombre del conjunto de datos si ya lo pasaste a data.

Otras características

Seleccionar y deseleccionar capas

Con addLayersControl podrás seleccionar y deseleccionar diferentes capas del gráfico. Para ello tendrás que asignar un nombre a cada capa con el argumento group y luego utilizar la función y especificar los baseGroups (capas que se pueden seleccionar una a la vez) y los overlayGroups (capas que se pueden seleccionar varias a la vez).

library(leaflet)

leaflet() %>%
  addTiles(group = "StreetMap") %>%
  addProviderTiles(providers$Stamen.Watercolor, group = "Stamen") %>%
  addMarkers(lng = c(-102.8, -101.1), lat = c(38.7, 39.4), group = "Markers") %>%
  addLayersControl(baseGroups = c("StreetMap", "Stamen"), overlayGroups = c("Markers"),
                   position = "topright")

Herramienta para medir

Puedes agregar una herramienta que permite medir distancias con la función addMeasure. Esta función proporciona varios argumentos para personalizar su posición, métricas y colores. Una vez se agrega, tendrás que hacer clic sobre la herramienta para comenzar a realizar medidas.

library(leaflet)

leaflet() %>%
  addTiles() %>%
  setView(lng = -101.6, lat = 39.86, zoom = 3) %>%
  addMeasure(
    position = "bottomleft",
    primaryLengthUnit = "meters",
    primaryAreaUnit = "sqmeters",
    activeColor = "#3D535D",
    completedColor = "#7D4479")

Agregar gratícula

Una gratícula es una rejilla que se muestra sobre el mapa y lo divide en diferentes secciones. Puedes agregar una gráticula con la función addSimpleGraticule o con la función addGraticule, que permite personalizar el estilo de la rejilla pasando una lista a style, es decir, addGraticule(style = list(color = "#333", weight = 1)).

library(leaflet)

leaflet() %>%
  addTiles() %>%
  setView(lng = -3.7, lat = 40.4, zoom = 2) %>%
  addSimpleGraticule()

Agregar una capa que representa el día y la noche

La función addTerminator agrega una capa al mapa que representa la noche y el día. Por defecto la función se basa en el instante en el que se ejecuta, pero puedes personalizar la hora con el argumento time.

library(leaflet)

leaflet() %>%
  addTiles() %>%
  addTerminator()

Agregar un minimapa

Con la función addMiniMap puedes añadir un mini mapa sobre el gráfico, de modo que podrás ver dónde estás a pesar del nivel de zoom. Esta función proporciona varios argumentos para personalizar el tamaño, los colores (aimingRectOptions), la sombra (shadowRectOptions) y otras características.

library(leaflet)

leaflet() %>%
  addTiles() %>%
  setView(lng = 2.4, lat = 46.6, zoom = 5) %>%
  addMiniMap(width = 150, height = 150)

Plugins adicionales con leaflet.extras

leaflet.extras es una librería increíblemente útil para utilizar junto con leaflet, ya que proporciona muchos plugins adicionales que no están disponibles en la librería central. Algunas de las funciones de leaflet.extras se destacan en esta sección, pero recuerda que puedes leer la documentación original para ver más funciones y detalles.

Herramienta de dibujo

Dibujar sobre un mapa de leaflet puede ser muy útil para aplicaciones Shiny o para ilustrar algo en directo. También podrás almacenar las coordenadas de lo que dibujes.

library(leaflet)
library(leaflet.extras)

leaflet() %>%
  addTiles() %>%
  setView(lng = -73, lat = 3.5, zoom = 5) %>%
  addDrawToolbar()

Herramienta para medir áreas

Otra herramienta interesante es la herramienta de medida, que permite medir las áreas de las geometrías dibujadas sobre el mapa.

library(leaflet)
library(sf)
library(leaflet.extras)

data_map <- read_sf("https://raw.githubusercontent.com/R-CoderDotCom/data/main/sample_geojson.geojson")
data_map <- st_transform(data_map, crs = '+proj=longlat +datum=WGS84')

leaflet() %>%
  addTiles() %>%
  enableMeasurePath() %>%
  setView(lng = -0.49, lat = 38.34, zoom = 14) %>%
  addPolygons(data = data_map, color = "blue", stroke = 1, opacity = 0.8) %>%
  addMeasurePathToolbar(options = measurePathOptions(imperial = FALSE,
                                                     minPixelDistance = 100,
                                                     showDistances = FALSE,
                                                     showOnHover = TRUE))

También te puede interesar