
Entrada en la que os mostraré cómo hacer un mapa con Leaflet en R que además añadimos a un Shiny para poder filtrar datos de forma interactiva. Ya mostramos en el blog cómo crear mapas marcando coordenadas con Leaflet y R de forma muy sencilla y hoy damos una vuelta de tuerca a aquella entrada: las coordenadas que deseamos representar tienen, además, algún factor por el que hay especial interés en realizar un filtrado del mapa. Para ilustrar el ejemplo nos vamos a ir al Centro de descargas del Centro Nacional de Información Geográfica y nos bajamos del servidor los datos municipales, en concreto a Nomenclátor Geográfico de Municipios y Entidades de Población; descargamos el archivo y tenemos un ZIP que contiene un CSV llamado MUNICIPIOS.CSV.
El ejercicio va a consistir en lo más simple: marcar los municipios filtrando por provincia, nada más, pero el resultado será un Shiny que podréis aprovechar para sofisticar vuestros mapas. El programa total es:
library(shiny)
library(shinyWidgets)
library(leaflet)
library(dplyr)
# Importación
ub <- "MUNICIPIOS.csv"
municipios <- read.csv2(ub)
# Siempre tendremos latitud y longitud
municipios$latitud <- as.numeric(municipios$LATITUD_ETRS89)
municipios$longitud <- as.numeric(municipios$LONGITUD_ETRS89)
# Factores para filtros
filtro1 <- municipios %>% arrange(COD_INE) %>% select(PROVINCIA) %>% unique()
# Shiny
ui <- fluidPage(
p(),
titlePanel("Municipios"),
fluidRow(
column(width = 3,
pickerInput("prov", "Seleccionar provincia", choices = filtro1$PROVINCIA,
selected = filtro1$PROVINCIA[1], options = list(`actions-box` = TRUE), multiple = TRUE)),
mainPanel(leafletOutput("mapa", height = 800))
)
)
server <- function(input, output, session) {
# Definimos los puntos a representar
puntos <- eventReactive(input$prov, {
fil <- municipios %>% dplyr::filter(PROVINCIA %in% input$prov)
return(fil)
}, ignoreNULL = FALSE)
# Realizamos el mapa
output$mapa <- renderLeaflet({
leaflet() %>%
addTiles() %>%
setView(lng = -3.68444444, lat = 40.30861111, zoom = 7) %>%
addProviderTiles(providers$CartoDB.Positron) %>%
addMarkers(data = puntos(), lng = ~longitud, lat = ~latitud)
})
}
shinyApp(ui, server)
Ahora vamos paso a paso.
Datos de origen
library(shiny)
library(shinyWidgets)
library(leaflet)
# Importación
ub <- "MUNICIPIOS.csv"
municipios <- read.csv2(ub)
# Siempre tendremos latitud y longitud
municipios$latitud <- as.numeric(municipios$LATITUD_ETRS89)
municipios$longitud <- as.numeric(municipios$LONGITUD_ETRS89)
En nuestros datos con las coordenadas siempre tendremos el campo latitud y longitud como numéricos. Básico.
Creación del filtro
# Factores para filtros
filtro1 <- municipios %>% arrange(COD_INE) %>% select(PROVINCIA) %>% unique()
Muy simple, necesitamos los nombres de las provincias en un objeto al que luego llamaremos al crear el filtro; un truco: dad orden.
Fluid layout
ui <- fluidPage(
p(),
titlePanel("Municipios"),
fluidRow(
column(width = 3,
pickerInput("prov", "Seleccionar provincia", choices = filtro1$PROVINCIA,
options = list(`actions-box` = TRUE), multiple = TRUE)),
mainPanel(leafletOutput("mapa", height = 800))
)
)
El formato más sencillo: título, fluidRow y mainPanel. En fluidRow vamos a poner los elementos del panel de la izquierda; a sólo una columna ponemos un pickerInput, que es el tipo de filtro que he elegido y que suelo elegir habitualmente cuando puedo tener múltiples selecciones; podéis investigar más los filtros. El resultado de este filtro será nuestro input$prov y necesita datos y elecciones. Buscad documentación sobre pickerInput, pero si no queréis complicaros la existencia, tal cual. Si queréis añadir más filtros, añadid más; en mi caso no complico mucho copiando y pegando. En mainPanel especificamos qué tipo de output queremos ver, en este caso leafletOutput, y el nombre del mapa resultante será mapa; sí destaco el uso de height = 800 para ajustarlo mejor en pantalla.
Server
server <- function(input, output, session) {
# Definimos los puntos a representar
puntos <- eventReactive(input$prov, {
fil <- municipios %>% dplyr::filter(PROVINCIA %in% input$prov)
return(fil)
}, ignoreNULL = FALSE)
# Realizamos el mapa
output$mapa <- renderLeaflet({
leaflet() %>%
addTiles() %>%
setView(lng = -3.68444444, lat = 40.30861111, zoom = 7) %>%
addProviderTiles(providers$CartoDB.Positron) %>%
addMarkers(data = puntos(), lng = ~longitud, lat = ~latitud)
})
}
shinyApp(ui, server)
Vemos que puntos será el conjunto de datos para presentar las coordenadas en el mapa; se creará en el momento en el que modifiquemos el filtro; por ello usamos eventReactive; si cambiamos, se desarrolla el dashboard. Añadimos el código necesario para crear un data frame con el filtrado filter(PROVINCIA %in% input$prov) y siempre finalizamos con los elementos de nuestros “datos reactivos”. El mapa será nuestra salida Leaflet y el código es simple, ya se vio en el blog, y empleamos addMarkers(data = puntos()), que es el conjunto de datos “reactivo” donde tenemos siempre longitud, latitud. Si deseamos añadir más elementos en nuestros datos reactivos lo hacemos en el cbind o directamente devolviendo el data frame filtrado; prefiero no complicarlo en esta ocasión.
Y el resultado de todo esto ya le habéis visto. En fin, yo usando Shiny; quién me ha visto y quién me ve defendiendo el mundo libre. Subiré el código a Git y haré un vídeo porque sobre estos cimientos se pueden hacer maravillas.