Mapas interactivos con {mapgl} para visualizar datos geoespaciales en R
7/9/2026
Actualizado el 14/10/2026
{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 que esta página se cargue más rápido.
library(rmapshaper)
manzanas <- manzanas |>
ms_simplify(keep = 0.3,
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!
Publicaciones relacionadas
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 = 6, minZoom = 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 = 12, minZoom = 10) |>
# 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, minZoom = 6
) |>
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, minZoom = 6
) |>
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, minZoom = 10) |>
# 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
Como vemos, la leyenda adquiere sus características desde la escala que creamos antes, y además tiene varias opciones de personalización.
Agregar tooltips
Los tooltips permiten que el/la usuario/a pase el cursor sobre los polígonos o elementos del mapa para ver información relevante. Son clave para poder entregar información más detallada en mapas interactivos.
Podemos agregar tooltips a una capa de relleno de polígonos, como la que agregamos en el paso anterior, con el argumento tooltip de la función add_fill_layer(). Este argumento recibe el nombre de una variable, o bien, se pueden construir textos con la función concat(), y usando dentro HTML y la función get_column() para referirnos al valor del polígono en alguna variable.
En este ejemplo agregamos un tooltip que hace referencia a tres variables:
mapa_tooltip <- maplibre(
center = c(-73.13, -36.715),
zoom = 14, minZoom = 10) |>
# capa de relleno
add_fill_layer(
id = "comuna",
source = comuna,
fill_color = escala$expression,
fill_opacity = 0.8,
# agregar tooltip
tooltip = concat(
"<div style='font-size: 120%;'>Personas por manzana</div>",
"<b>Población: </b>", get_column("n_per"), " personas",
"<br>",
"<b>Edad promedio: </b>", get_column("prom_edad"), " años",
"<br>",
"<b>Escolaridad: </b>", get_column("prom_escolaridad18")
),
# personalizar estilo de tooltip
tooltip_style = tooltip_style(
max_width = 200,
padding = 8,
background_color = "#FFFFFF",
background_opacity = .9,
)
)
mapa_tooltip
Pasa el cursor sobre el mapa para ver el tooltip!
En el argumento tooltip_style podemos personalizar la ventanita, pero si necesitamos algo más personalizado siempre podemos usar CSS.
Mapa interactivo categórico
También podemos visualizar en el mapa no son numéricos, sino categóricos, donde tenemos varios niveles discretos que queremos expresar como colores sobre los puntos o polígonos.
Primero cambiemos un poco los datos para unir los polígonos de las manzanas por localidades, y así obtener 6 polígonos:
localidades <- manzanas |>
filter(COMUNA == "TOMÉ") |>
# unir por localidades
group_by(LOCALIDAD) |>
summarize(SHAPE = st_union(SHAPE)) |>
# agrandar para borrar calles
mutate(SHAPE = st_buffer(SHAPE, 15,
max_cells = 100000
))
localidades
Simple feature collection with 6 features and 1 field
Geometry type: MULTIPOLYGON
Dimension: XY
Bounding box: xmin: -72.9804 ymin: -36.67717 xmax: -72.78573 ymax: -36.52311
Geodetic CRS: WGS 84
# A tibble: 6 × 2
LOCALIDAD SHAPE
* <chr> <MULTIPOLYGON [°]>
1 DICHATO (((-72.95045 -36.54792, -72.95045 -36.54793, -72.95045 -36.547…
2 LOS MORROS (((-72.96276 -36.53283, -72.96276 -36.53283, -72.96276 -36.532…
3 MENQUE (((-72.8701 -36.55405, -72.8701 -36.55405, -72.8701 -36.55405,…
4 PUNTA DE PARRA (((-72.94606 -36.65974, -72.94606 -36.65974, -72.94606 -36.659…
5 RAFAEL (((-72.79419 -36.62449, -72.79419 -36.62449, -72.79419 -36.624…
6 TOMÉ (((-72.94015 -36.60208, -72.94015 -36.60207, -72.94016 -36.602…
Para visualizar datos categóricos en mapas, tenemos que crear una escala de colores para cada categoría. Usaremos la variable LOCALIDAD para colorear los polígonos, así que podemos usar su largo con length() dentro de una
función para generar paletas de colores para obtener 6 colores distintos:
categorias <- unique(localidades$LOCALIDAD)
library(colorspace)
# paleta categórica de arcoíris
paleta_categorica <- rainbow_hcl(
n = length(categorias), # cantidad de colores
c = 100,
start = 180,
end = 360)
Publicaciones relacionadas
Ahora, cuando creemos la capa de relleno con add_fill_layer() igual que antes, en el color de relleno usaremos match_expr(), función que requiere la variable a usar para aplicar el color (en este caso LOCALIDAD), los valores únicos de esta variable (unique(localidades$LOCALIDAD)) y finalmente los colores que creamos recién.
También agregamos una leyenda categórica con add_categorical_legend(), que funciona casi igual que match_expr() y add_continuous_legend().
mapa_localidades <- maplibre(
center = c(-72.88, -36.60),
zoom = 10.5,
minZoom = 8, maxZoom = 12) |>
# capa de figuras
add_fill_layer(
id = "localidades",
source = localidades,
# paleta categórica
fill_color = match_expr(
"LOCALIDAD", # variable a usar
values = categorias, # valores únicos
stops = paleta_categorica # colores para cada valor
),
fill_opacity = 0.8
) |>
# leyenda categórica
add_categorical_legend(
legend_title = "Localidades",
values = categorias, # valores únicos
colors = paleta_categorica, # colores para cada valor
position = "top-right",
style = legend_style(background_opacity = .8)
)
mapa_localidades

