Mapas interactivos con {mapgl} para visualizar datos geoespaciales en R

7/9/2026

mapas visualización de datos

{mapgl} es un paquete de R para visualizar datos geográficos de manera interactiva. Este paquete, desarrollado por Kyle Walker, implementa los visores de mapas interactivos Mapbox y MapLibre en R, para que puedas usarlos como lienzos para tus cartografías y datos geográficos.

En este tutorial aprenderemos a usar {mapgl}, y como ejemplo usaremos la cartografía Censal del Censo 2024 de Chile.

El primer paso es instalar {mapgl}:

install.packages("mapgl")

Datos censales

Descarga los datos cartográficos del Censo 2024 desde la página del INE, entrando a Cartografía Censal y luego descargando el archivo Cartografía País Censo 2024 (geoparquet).

Cargar cartografías censales

Los datos censales vienen en formato parquet, un formato moderno y eficiente para almacenar y consultar datos, y se cargan con la función read_parquet() del paquete {arrow}, o con open_dataset() si queremos abrir el archivo como base de datos.

Si no tenemos {arrow} instalado, lo instalamos con install.packages("arrow").

library(arrow)

manzanas <- open_dataset("Cartografia_censo2024_Pais/Cartografia_censo2024_Pais_Manzanas.parquet")

Cargamos los datos del Censo como base de datos, lo que significa que la información no está cargada aún en nuestro computador, sino que obtuvimos un esquema de los datos. Tenemos que hacer una consulta (query) a la base de datos para que Arrow obtenga los datos y los cargue al entorno de R. Filtraremos los datos con {dplyr} y luego los obtendremos con collect(). De esta manera sólo cargamos lo que necesitamos!

library(dplyr)

# desde base de datos local
manzanas <- censo |> 
  # filtrar región del país
  filter(COD_REGION == 8) |> 
  # seleccionar algunas variables interesantes
  select(SHAPE,
         CUT, COMUNA, LOCALIDAD,
         COD_MANZANA, 
         n_per, prom_edad, n_edad_60_mas, n_edad_0_5, 
         n_discapacidad, prom_escolaridad18, 
         n_desocupado, n_analfabet,
         n_transporte_bicicleta, n_jefatura_mujer,
         n_viv_hacinadas) |> 
  # copiar a la memoria
  collect()

Ahora sí, cargamos a nuestro entorno de R unos varios miles de filas de datos censales por manzana:

manzanas
# A tibble: 21,022 × 16
        SHAPE   CUT COMUNA LOCALIDAD COD_MANZANA n_per prom_edad n_edad_60_mas
   <arrw_bnr> <int> <chr>  <chr>           <int> <dbl>     <dbl>         <dbl>
 1    [2,422]  8203 CAÑETE HUILLINCO           1    31      41.1             7
 2    [7,734]  8203 CAÑETE HUILLINCO           2   107      36.5            17
 3    [3,894]  8203 CAÑETE HUILLINCO           3    63      47.5            24
 4    [2,758]  8203 CAÑETE HUILLINCO           4    10      52.9             4
 5    [1,894]  8203 CAÑETE CAYUCUPIL           1    77      40.7            17
 6    [1,510]  8203 CAÑETE CAYUCUPIL           5    55      41.7            12
 7      [246]  8203 CAÑETE CAYUCUPIL           7    28      41.3             8
 8      [822]  8203 CAÑETE CAYUCUPIL           9    18      31.4             2
 9      [294]  8203 CAÑETE CAYUCUPIL          10    16      41.9             5
10      [310]  8203 CAÑETE CAYUCUPIL          13     8      52.4             3
# ℹ 21,012 more rows
# ℹ 8 more variables: n_edad_0_5 <dbl>, n_discapacidad <dbl>,
#   prom_escolaridad18 <dbl>, n_desocupado <dbl>, n_analfabet <dbl>,
#   n_transporte_bicicleta <dbl>, n_jefatura_mujer <dbl>, n_viv_hacinadas <dbl>

El último paso es convertir la tabla de datos a una tabla de datos geográficos usando {sf}, para reconocer la columna SHAPE como la que contiene los polígonos de los datos censales:

library(sf)

manzanas <- manzanas |> 
  st_as_sf(crs = 4326)
Nota: para hacer más liviana esta página, se simplificaron los mapas

Los mapas originales del Censo son extremadamente detallados, por lo que fueron simplificados para hacer qu esta página se cargue más rápido.

library(rmapshaper)

manzanas <- manzanas |> 
  ms_simplify(keep = 0.4,
              keep_shapes = TRUE)

Con esta configuración se retienen el 40% de todos los puntos del mapa, un cambio casi imperceptible. Para más información sobre este método, revisa este tutorial!

Ahora sí podemos visualizar los datos en mapas!

Visor de mapas básico

Para empezar, probemos con un mapa vacío, usando la función maplibre().

library(mapgl)

maplibre(
  center = c(-71.5, -33.0), 
  zoom = 4)

Indicamos unas coordenadas y un nivel de zoom. Prueba moviendo el mapa o acercándote! Guau! Esta función será la primera capa de nuestros mapas interactivos.

Visualizar polígonos en el mapa

Ahora usemos {mapgl} con los datos censales. Primero filtremos un poco los datos para hacer un mapa de ejemplo:

comuna <- manzanas |> 
  filter(COMUNA == "CONCEPCIÓN")

Ahora crearemos el mapa base con maplibre(), y le agregamos una capa de relleno con add_fill_layer():

mapa_poligono <- maplibre(
  center = c(-73.04, -36.82), 
  zoom = 11) |> 
  # capa con polígonos
  add_fill_layer(
    id = "comuna",
    source = comuna, # objeto sf
    fill_color = "#6E3998",
    fill_opacity = 0.6)

mapa_poligono

Obtenemos el mapa base con los polígonos encima, con un color de nuestra elección. Hazle zoom para ver el nivel de calidad!

Esto nos sirve para probar los polígonos, o visualizaciones simples.

Mapa con marcadores

Podemos agregar marcadores individuales a un mapa a partir de coordenadas (longitud y latitud). Para ello, creamos una tabla de datos con varios lugares y sus respectivas coordenadas de longitud y latitud:

# tabla de coordenadas
lugares <- tribble(
  ~lugar,       ~lon,     ~lat,   
  "Barriga",    -70.9251, -33.5304, 
  "Chada",      -70.6488, -33.9348, 
  "Mallarauco", -70.9608, -33.6180, 
  "Dormida",    -71.0096, -33.0618, 
  "Chacabuco",  -70.7065, -32.9595
) |> 
  # texto en html
  mutate(texto = paste("<b>Lugar:</b>", lugar))

También creamos una columna texto en la que agregaremos contenido HTML que aparecerá como popup cuando se aprieten los marcadores.

Convertimos esta tabla de coordenadas a una tabla de datos geográficos con st_as_sf() y la agregamos al mapa:

puntos <- lugares |> 
  st_as_sf(
    coords = c("lon", "lat"), 
    crs = 4326
  )

# agregar marcadores al mapa
maplibre(
  center = c(-70.65, -33.44),
  zoom = 7
) |>
  add_markers(
    data = puntos,
    color = "#6E3998",
    popup = "texto"
  )

Presiona los marcadores para ver su información! Puedes ver un ejemplo aplicado de un mapa {mapgl} con marcadores y popups con imágenes en mi blog personal.

Ver una alternativa para agregar un solo marcador

La primera sería agregar una única coordenada creando un punto con sf::st_point() a partir de los valores de longitud y latitud:

library(sf)

coordenadas <- c(-71.48135, -33.96850)

# convertir las coordenadas en datos geográficos
punto <- coordenadas |> 
  st_point() |> 
  st_sfc(crs = 4326)

Luego agregamos el punto como un marcador con add_markers():

# agregar al mapa
maplibre(
  center = coordenadas,
  zoom = 8,
) |>
  add_markers(
    data = punto,
    color = "#6E3998")

Mapa coroplético interactivo

Los mapas coropléticos o de coropletas rellenan cada polígono del mapa con un color de acuerdo al valor de una variable. Es quizás la forma más básica e intuitiva de visualizar datos que se corresponden con polígonos.

Filtremos un poco los datos para hacer un mapa de ejemplo:

comuna <- manzanas |> 
  filter(COMUNA == "TALCAHUANO")

Para visualizar un mapa coloreando los polígonos según una variable en {mapgl}, primero tenemos que crear una escala. Esta escala nos permitirá definir la variable que queremos visualizar, los cortes en los datos, y los colores.

Creamos la escala con interpolate_palette(), indicando la columna que nos interesa. Elegimos la variable n_per(cantidad de habitantes por manzana), junto al método para cortar la variable (en este caso, el método Jenks), la cantidad de cortes, y la paleta de colores.

escala <- interpolate_palette(
  data = comuna,
  column = "n_per",
  method = "jenks", 
  n = 5, 
  colors = c("#EAD1FA", "#9069C0", "#6E3998")
)

Una vez que tenemos la escala de colores, la usamos en el argumento fill_color como escala$expression para indicarle al mapa los cortes en los datos y los colores que les corresponden. Luego agregamos la leyenda correspondiente con add_continuous_legend().

# mapa base
mapa_poblacion <- maplibre(
  center = c(-73.10, -36.74),
  zoom = 11) |> 
  # capa de relleno
  add_fill_layer(
    id = "comuna",
    source = comuna, # objeto sf con geometrías
    fill_color = escala$expression, # desde escala
    fill_opacity = 0.8
  ) |> 
  # leyenda
  add_continuous_legend(
    legend_title = "Personas por manzana",
    values = escala$breaks,
    colors = escala$colors,
    position = "top-right",
    style = legend_style(
      border_radius = 6,
      padding = 8,
      background_opacity = 0.8,
      text_size = 10
    )
  )

mapa_poblacion