El Valle del Cauca es un departamento ubicado en el suroccidente de Colombia, atravesado longitudinalmente por el río Cauca entre las cordilleras Central y Occidental. Esta configuración genera un contraste geomorfológico marcado: un valle aluvial plano (con pendientes generalmente inferiores al 3%), dedicado en buena parte a la agroindustria de la caña de azúcar, flanqueado por vertientes montañosas de las dos cordilleras con pendientes fuertes y alta variabilidad de aspecto. En un mismo departamento coexisten así zonas planas de vega, piedemonte y alta montaña (incluyendo sectores del Parque Nacional Natural Farallones de Cali y del macizo occidental hacia el Pacífico).
En este notebook usaremos el paquete MultiscaleDTM para
calcular pendiente y aspecto a partir de un modelo digital de elevación
(DEM) del Valle del Cauca, y exactextractr para resumir
esos valores por municipio (el departamento cuenta con 42 municipios,
con capital en Cali). A diferencia de una versión anterior de este
notebook, aquí los datos de entrada (límites municipales y DEM) se
descargan automáticamente desde el código, sin necesidad de conseguirlos
manualmente.
Los paquetes requeridos deben instalarse previamente desde la Consola.
## CONFIGURACIÓN
# INSTALAR ESTOS PAQUETES DESDE LA CONSOLA, NO DESDE ESTE CHUNK
paquetes <- c("MultiscaleDTM", "exactextractr", "geodata", "elevatr", "sf", "terra", "leaflet")
install.packages(paquetes)
Limpiamos la memoria:
rm(list = ls())
Cargamos las librerías necesarias:
library(geodata)
library(elevatr)
library(sf)
library(leaflet)
library(terra)
library(MultiscaleDTM)
library(exactextractr)
Al ejecutar cada chunk, presta atención a los mensajes de error o
advertencia de conflictos entre funciones de distintos paquetes (por
ejemplo terra::extract vs tidyr::extract).
Para evitar ambigüedades, varias funciones se llamarán usando la
notación larga paquete::funcion.
Usamos el paquete geodata, que descarga directamente los
límites administrativos de la base GADM, para obtener los municipios de
Colombia y filtrar los que pertenecen al Valle del Cauca.
level = 2 corresponde al nivel municipal.
carpeta_datos <- "valle_del_cauca"
dir.create(carpeta_datos, showWarnings = FALSE)
# descarga los municipios de toda Colombia (se guarda en caché local)
mpios_col <- geodata::gadm(country = "COL", level = 2, path = carpeta_datos)
# convertimos a objeto sf y filtramos el departamento
mpios_col_sf <- sf::st_as_sf(mpios_col)
munic <- mpios_col_sf[mpios_col_sf$NAME_1 == "Valle del Cauca", ]
# nos quedamos con las columnas relevantes y renombramos para mayor claridad
munic <- munic[, c("NAME_1", "NAME_2", "geometry")]
names(munic)[1:2] <- c("departamento", "municipio")
# al filtrar/seleccionar columnas, sf a veces deja la geometría como el tipo
# genérico "GEOMETRY" en lugar de "MULTIPOLYGON", lo cual rompe funciones como
# elevatr::get_elev_raster(). Forzamos el tipo correcto:
munic <- sf::st_cast(munic, "MULTIPOLYGON")
munic <- sf::st_make_valid(munic)
(munic)
Guardamos esta capa como geopackage para reutilizarla sin tener que descargarla de nuevo:
sf::st_write(munic, file.path(carpeta_datos, "valle_del_cauca.gpkg"), append = FALSE, quiet = TRUE)
Visualicemos rápidamente los municipios descargados:
plot(sf::st_geometry(munic), col = "darkseagreen3", border = "gray30",
main = "Municipios del Valle del Cauca")
Descargamos el DEM correspondiente al área del Valle del Cauca con
elevatr, usando el polígono departamental como máscara de
recorte. El parámetro z controla la resolución (entre mayor
el zoom, mayor la resolución y el peso del archivo; z = 9
es un buen punto de partida para un departamento completo).
dem_raw <- elevatr::get_elev_raster(locations = munic, z = 9, clip = "locations")
## Mosaicing & Projecting
## Clipping DEM to locations
## Note: Elevation units are in meters.
dem <- terra::rast(dem_raw)
terra::writeRaster(dem, file.path(carpeta_datos, "elev_valle_z9.tif"), overwrite = TRUE)
(dem)
## class : SpatRaster
## size : 1425, 1342, 1 (nrow, ncol, nlyr)
## resolution : 0.001371367, 0.001371367 (x, y)
## extent : -77.54495, -75.70458, 3.061129, 5.015327 (xmin, xmax, ymin, ymax)
## coord. ref. : +proj=longlat +datum=WGS84 +no_defs
## source(s) : memory
## name : file28e05d169
## min value : -564
## max value : 4204
paleta_relieve <- grDevices::colorRampPalette(
c("#1a4314", "#3d7a1f", "#8fae3d", "#d9c66b", "#a97d4f", "#6b4423", "#4a2e1a")
)(100)
terra::plot(dem, main = "DEM del Valle del Cauca", col = paleta_relieve)
dem2 <- terra::aggregate(dem, 2, "mean")
dem3 <- terra::crop(dem2, munic, mask = TRUE)
Para calcular atributos de terreno, el DEM debe estar en coordenadas planas. Desde 2020 el IGAC adoptó el sistema de coordenadas planas con origen único nacional (EPSG:9377).
Transforma el DEM y la capa de municipios a este sistema:
# revisa los parámetros de esta función en
# https://rdrr.io/github/rspatial/terra/man/project.html
(dem_plane <- terra::project(dem3, "EPSG:9377"))
## class : SpatRaster
## size : 715, 676, 1 (nrow, ncol, nlyr)
## resolution : 304.2633, 304.2633 (x, y)
## extent : 4494648, 4700330, 1896389, 2113937 (xmin, xmax, ymin, ymax)
## coord. ref. : MAGNA-SIRGAS 2018 / Origen-Nacional (EPSG:9377)
## source(s) : memory
## name : file28e05d169
## min value : -319.718994
## max value : 4113.18457
# revisa los parámetros de esta función en
# https://github.com/rstudio/cheatsheets/blob/main/sf.pdf
(munic_plane <- sf::st_transform(munic, "EPSG:9377"))
Calculamos pendiente (slope) y orientación (aspect) con
SlpAsp. Consulta ?SlpAsp en la Consola para
revisar los parámetros w (tamaño de la ventana de análisis)
y method (esquema de vecindad).
# Explica qué es w
# Explica qué es method
# Modifica si es necesario
(slp_asp <- MultiscaleDTM::SlpAsp(
dem_plane,
w = c(3, 3),
unit = "degrees",
method = "queen",
metrics = c("slope", "aspect"),
na.rm = TRUE,
include_scale = FALSE,
mask_aspect = TRUE
))
## class : SpatRaster
## size : 715, 676, 2 (nrow, ncol, nlyr)
## resolution : 304.2633, 304.2633 (x, y)
## extent : 4494648, 4700330, 1896389, 2113937 (xmin, xmax, ymin, ymax)
## coord. ref. : MAGNA-SIRGAS 2018 / Origen-Nacional (EPSG:9377)
## source(s) : memory
## names : slope, aspect
## min values : 0, 0.002835
## max values : 50.832156, 359.99919
Separamos las dos capas resultantes.
Capa 1 (pendiente):
(slope <- subset(slp_asp, 1))
## class : SpatRaster
## size : 715, 676, 1 (nrow, ncol, nlyr)
## resolution : 304.2633, 304.2633 (x, y)
## extent : 4494648, 4700330, 1896389, 2113937 (xmin, xmax, ymin, ymax)
## coord. ref. : MAGNA-SIRGAS 2018 / Origen-Nacional (EPSG:9377)
## source(s) : memory
## name : slope
## min value : 0
## max value : 50.832156
terra::hist(slope,
main = "Pendiente del Valle del Cauca",
xlab = "Pendiente (en grados)"
)
Capa 2 (aspecto):
(aspect <- subset(slp_asp, 2))
## class : SpatRaster
## size : 715, 676, 1 (nrow, ncol, nlyr)
## resolution : 304.2633, 304.2633 (x, y)
## extent : 4494648, 4700330, 1896389, 2113937 (xmin, xmax, ymin, ymax)
## coord. ref. : MAGNA-SIRGAS 2018 / Origen-Nacional (EPSG:9377)
## source(s) : memory
## name : aspect
## min value : 0.002835
## max value : 359.99919
terra::hist(aspect,
main = "Aspecto del Valle del Cauca",
xlab = "Aspecto (en grados)"
)
Convertimos la pendiente de grados a porcentaje, unidad de uso común en clasificación agrológica en Colombia:
(slope_perc <- tan(slope * (pi / 180)) * 100)
## class : SpatRaster
## size : 715, 676, 1 (nrow, ncol, nlyr)
## resolution : 304.2633, 304.2633 (x, y)
## extent : 4494648, 4700330, 1896389, 2113937 (xmin, xmax, ymin, ymax)
## coord. ref. : MAGNA-SIRGAS 2018 / Origen-Nacional (EPSG:9377)
## source(s) : memory
## name : slope
## min value : 0
## max value : 122.752709
terra::hist(slope_perc,
main = "Pendiente del Valle del Cauca",
xlab = "Pendiente (en porcentaje)"
)
Dada la geografía del departamento, se espera una distribución bimodal: un pico marcado cerca de 0% correspondiente al valle aluvial del río Cauca (zona de agroindustria cañera), y una cola larga de valores altos asociada a las vertientes de las cordilleras Central y Occidental.
Usamos la clasificación de pendientes del IGAC para fines agrológicos y calculamos el promedio de pendiente por municipio.
m <- c(
0, 3, 1,
3, 7, 2,
7, 12, 3,
12, 25, 4,
25, 50, 5,
50, 75, 6,
75, 160, 7
)
m <- matrix(m, ncol = 3, byrow = TRUE)
rc <- terra::classify(slope_perc, m, right = TRUE)
Calculamos estadísticas zonales con exactextractr:
(munic$mean_slope <- exactextractr::exact_extract(slope_perc, munic, "mean"))
## Warning in .local(x, y, ...): Polygons transformed to raster CRS (EPSG: 9377) .
## To avoid on-the-fly coordinate transformation, ensure that st_crs() returns the
## same result for both raster and polygon inputs.
## | | | 0% | |== | 2% | |=== | 5% | |===== | 7% | |======= | 10% | |======== | 12% | |========== | 14% | |============ | 17% | |============= | 19% | |=============== | 21% | |================= | 24% | |================== | 26% | |==================== | 29% | |====================== | 31% | |======================= | 33% | |========================= | 36% | |=========================== | 38% | |============================ | 40% | |============================== | 43% | |================================ | 45% | |================================= | 48% | |=================================== | 50% | |===================================== | 52% | |====================================== | 55% | |======================================== | 57% | |========================================== | 60% | |=========================================== | 62% | |============================================= | 64% | |=============================================== | 67% | |================================================ | 69% | |================================================== | 71% | |==================================================== | 74% | |===================================================== | 76% | |======================================================= | 79% | |========================================================= | 81% | |========================================================== | 83% | |============================================================ | 86% | |============================================================== | 88% | |=============================================================== | 90% | |================================================================= | 93% | |=================================================================== | 95% | |==================================================================== | 98% | |======================================================================| 100%
## [1] 5.5744586 5.1779618 19.1408596 21.1887646 26.1608505 11.5885410
## [7] 8.1660175 14.9600506 24.0302525 0.3369108 6.6544151 24.1689396
## [13] 30.2476768 26.9027443 17.6654491 24.2423954 23.3342361 22.7411823
## [19] 8.6025810 23.9334431 12.9214354 14.9278593 11.1586790 6.1246181
## [25] 8.7152472 15.3353434 21.0480251 14.9463530 17.8954411 12.4469519
## [31] 12.2564573 15.1116304 18.7486839 16.3780346 22.5365429 21.8216362
## [37] 5.8662834 23.8242264 14.3155890 14.1256762 15.4605160 3.4692101
hist(munic$mean_slope,
main = "Pendiente media por municipio - Valle del Cauca",
xlab = "Pendiente (en porcentaje)"
)
(munic$class <- exactextractr::exact_extract(rc, munic, "mode"))
## Warning in .local(x, y, ...): Polygons transformed to raster CRS (EPSG: 9377) .
## To avoid on-the-fly coordinate transformation, ensure that st_crs() returns the
## same result for both raster and polygon inputs.
## | | | 0% | |== | 2% | |=== | 5% | |===== | 7% | |======= | 10% | |======== | 12% | |========== | 14% | |============ | 17% | |============= | 19% | |=============== | 21% | |================= | 24% | |================== | 26% | |==================== | 29% | |====================== | 31% | |======================= | 33% | |========================= | 36% | |=========================== | 38% | |============================ | 40% | |============================== | 43% | |================================ | 45% | |================================= | 48% | |=================================== | 50% | |===================================== | 52% | |====================================== | 55% | |======================================== | 57% | |========================================== | 60% | |=========================================== | 62% | |============================================= | 64% | |=============================================== | 67% | |================================================ | 69% | |================================================== | 71% | |==================================================== | 74% | |===================================================== | 76% | |======================================================= | 79% | |========================================================= | 81% | |========================================================== | 83% | |============================================================ | 86% | |============================================================== | 88% | |=============================================================== | 90% | |================================================================= | 93% | |=================================================================== | 95% | |==================================================================== | 98% | |======================================================================| 100%
## [1] 1 1 5 4 5 1 1 4 5 1 1 5 5 5 1 5 5 5 1 5 1 4 1 1 1 1 5 4 4 4 1 1 4 5 4 5 2 4
## [39] 4 4 4 1
hist(munic$class,
main = "Pendiente reclasificada - Valle del Cauca",
xlab = "Pendiente (como categoría)"
)
Tabla resumen ordenada por pendiente media, de menor a mayor:
tabla_resumen <- sf::st_drop_geometry(munic[, c("municipio", "mean_slope", "class")])
tabla_resumen <- tabla_resumen[order(tabla_resumen$mean_slope), ]
(tabla_resumen)
Se espera que municipios ubicados sobre la vega del río Cauca (por ejemplo, en el eje Cali-Palmira-Buga-Tuluá-Cartago) muestren clases bajas (1-2), mientras que municipios de cordillera (hacia el Pacífico u hacia el oriente del departamento) presenten clases más altas.
Regresamos las capas a coordenadas geográficas para su visualización
en leaflet:
# Pendiente reclasificada
(rc.geo <- terra::project(rc, "EPSG:4326"))
## class : SpatRaster
## size : 719, 678, 1 (nrow, ncol, nlyr)
## resolution : 0.002742672, 0.002742672 (x, y)
## extent : -77.55587, -75.69634, 3.053583, 5.025564 (xmin, xmax, ymin, ymax)
## coord. ref. : lon/lat WGS 84 (EPSG:4326)
## source(s) : memory
## name : slope
## min value : 0
## max value : 7
# Pendiente en porcentaje
(slope.geo <- terra::project(slope_perc, "EPSG:4326"))
## class : SpatRaster
## size : 719, 678, 1 (nrow, ncol, nlyr)
## resolution : 0.002742672, 0.002742672 (x, y)
## extent : -77.55587, -75.69634, 3.053583, 5.025564 (xmin, xmax, ymin, ymax)
## coord. ref. : lon/lat WGS 84 (EPSG:4326)
## source(s) : memory
## name : slope
## min value : 0
## max value : 114.035812
Definimos una paleta de colores para la pendiente:
# amplía el número de colores para mejorar la visualización
# https://r-graph-gallery.com/42-colors-names.html
palredgreen <- leaflet::colorNumeric(
c("darkseagreen3", "yellow2", "orange", "brown2", "darkred"),
terra::values(slope.geo),
na.color = "transparent"
)
Generamos el mapa interactivo, centrado sobre el Valle del Cauca:
leaflet::leaflet(munic) %>%
leaflet::addTiles() %>%
leaflet::setView(-76.3, 3.9, 8) %>%
leaflet::addPolygons(
color = "gray", weight = 1.0, smoothFactor = 0.5,
opacity = 0.4, fillOpacity = 0.10,
popup = paste(
"Municipio: ", munic$municipio, "<br>",
"Clase de pendiente: ", munic$class, "<br>"
)
) %>%
leaflet::addRasterImage(slope.geo, colors = palredgreen, opacity = 0.8) %>%
leaflet::addLegend(
pal = palredgreen, values = terra::values(slope.geo),
title = "Pendiente del terreno en el Valle del Cauca (%)"
)
Haz clic en distintos puntos del mapa para consultar el nombre del municipio y su clase de pendiente predominante.
Visualiza la pendiente del terreno en grados y añade etiquetas con el nombre de cada municipio junto a su pendiente media. Conserva los popups tal como en el mapa anterior.
Calculamos la pendiente media por municipio en grados (además de la que ya teníamos en porcentaje), y llevamos la capa de pendiente en grados a coordenadas geográficas para poder mapearla:
munic$mean_slope_deg <- exactextractr::exact_extract(slope, munic, "mean")
## Warning in .local(x, y, ...): Polygons transformed to raster CRS (EPSG: 9377) .
## To avoid on-the-fly coordinate transformation, ensure that st_crs() returns the
## same result for both raster and polygon inputs.
## | | | 0% | |== | 2% | |=== | 5% | |===== | 7% | |======= | 10% | |======== | 12% | |========== | 14% | |============ | 17% | |============= | 19% | |=============== | 21% | |================= | 24% | |================== | 26% | |==================== | 29% | |====================== | 31% | |======================= | 33% | |========================= | 36% | |=========================== | 38% | |============================ | 40% | |============================== | 43% | |================================ | 45% | |================================= | 48% | |=================================== | 50% | |===================================== | 52% | |====================================== | 55% | |======================================== | 57% | |========================================== | 60% | |=========================================== | 62% | |============================================= | 64% | |=============================================== | 67% | |================================================ | 69% | |================================================== | 71% | |==================================================== | 74% | |===================================================== | 76% | |======================================================= | 79% | |========================================================= | 81% | |========================================================== | 83% | |============================================================ | 86% | |============================================================== | 88% | |=============================================================== | 90% | |================================================================= | 93% | |=================================================================== | 95% | |==================================================================== | 98% | |======================================================================| 100%
(slope_deg.geo <- terra::project(slope, "EPSG:4326"))
## class : SpatRaster
## size : 719, 678, 1 (nrow, ncol, nlyr)
## resolution : 0.002742672, 0.002742672 (x, y)
## extent : -77.55587, -75.69634, 3.053583, 5.025564 (xmin, xmax, ymin, ymax)
## coord. ref. : lon/lat WGS 84 (EPSG:4326)
## source(s) : memory
## name : slope
## min value : 0
## max value : 48.722939
Definimos una paleta para la pendiente en grados y calculamos los centroides de cada municipio, donde ubicaremos las etiquetas con el nombre y la pendiente media:
pal_deg <- leaflet::colorNumeric(
c("darkseagreen3", "yellow2", "orange", "brown2", "darkred"),
terra::values(slope_deg.geo),
na.color = "transparent"
)
centros <- sf::st_centroid(munic)
## Warning: st_centroid assumes attributes are constant over geometries
etiquetas_slope <- paste0(munic$municipio, ": ", round(munic$mean_slope_deg, 1), "°")
Generamos el mapa: pendiente en grados como capa raster, los mismos popups del mapa anterior, y etiquetas permanentes con el nombre del municipio y su pendiente media:
leaflet::leaflet(munic) %>%
leaflet::addTiles() %>%
leaflet::setView(-76.3, 3.9, 8) %>%
leaflet::addPolygons(
color = "gray", weight = 1.0, smoothFactor = 0.5,
opacity = 0.4, fillOpacity = 0.10,
popup = paste(
"Municipio: ", munic$municipio, "<br>",
"Clase de pendiente: ", munic$class, "<br>"
)
) %>%
leaflet::addRasterImage(slope_deg.geo, colors = pal_deg, opacity = 0.8) %>%
leaflet::addLegend(
pal = pal_deg, values = terra::values(slope_deg.geo),
title = "Pendiente del terreno en el Valle del Cauca (grados)"
) %>%
leaflet::addLabelOnlyMarkers(
data = centros,
label = etiquetas_slope,
labelOptions = leaflet::labelOptions(
noHide = TRUE, direction = "center", textOnly = TRUE,
style = list("font-weight" = "bold", "font-size" = "10px", "color" = "black")
)
)
Describe el resultado obtenido y su significado, relacionándolo con la posición del municipio dentro del valle o sobre alguna de las dos cordilleras.
Visualiza el aspecto del terreno usando una paleta cíclica adecuada para una variable circular (0°-360°).
Como el aspecto es una variable circular (0° y 360° representan la misma orientación, Norte), no tiene sentido usar una paleta continua tipo semáforo como la de la pendiente. Primero llevamos la capa de aspecto (en grados) a coordenadas geográficas:
(aspect.geo <- terra::project(aspect, "EPSG:4326"))
## class : SpatRaster
## size : 719, 678, 1 (nrow, ncol, nlyr)
## resolution : 0.002742672, 0.002742672 (x, y)
## extent : -77.55587, -75.69634, 3.053583, 5.025564 (xmin, xmax, ymin, ymax)
## coord. ref. : lon/lat WGS 84 (EPSG:4326)
## source(s) : memory
## name : aspect
## min value : 0.130264
## max value : 359.940155
Luego la reclasificamos en 8 direcciones cardinales/intercardinales y usamos una paleta tipo “rosa de los vientos”, donde direcciones opuestas tienen colores contrastantes:
m2 <- matrix(c(
0, 22.5, 1, # N
22.5, 67.5, 2, # NE
67.5, 112.5, 3, # E
112.5, 157.5, 4, # SE
157.5, 202.5, 5, # S
202.5, 247.5, 6, # SW
247.5, 292.5, 7, # W
292.5, 337.5, 8, # NW
337.5, 360, 1 # N (cierra el círculo)
), ncol = 3, byrow = TRUE)
aspect_class <- terra::classify(aspect.geo, m2, right = FALSE)
direcciones <- c("N", "NE", "E", "SE", "S", "SW", "W", "NW")
colores_direccion <- c(
"red", "darkorange", "gold", "chartreuse3",
"forestgreen", "cyan3", "blue", "purple"
)
pal_aspect <- leaflet::colorFactor(
palette = colores_direccion,
domain = 1:8,
na.color = "transparent"
)
Generamos el mapa de orientación del terreno:
leaflet::leaflet(munic) %>%
leaflet::addTiles() %>%
leaflet::setView(-76.3, 3.9, 8) %>%
leaflet::addPolygons(
color = "gray", weight = 1.0, smoothFactor = 0.5,
opacity = 0.4, fillOpacity = 0.10,
popup = paste("Municipio: ", munic$municipio, "<br>")
) %>%
leaflet::addRasterImage(aspect_class, colors = pal_aspect, opacity = 0.8) %>%
leaflet::addLegend(
colors = colores_direccion, labels = direcciones,
title = "Orientación del terreno (aspecto)", opacity = 1
)
## Warning in colors(.): Some values were outside the color scale and will be
## treated as NA
Si reutilizas el código de este notebook, por favor cita este trabajo.
Fuentes de datos:
geodata.elevatr.sessionInfo()
## R version 4.6.0 (2026-04-24 ucrt)
## Platform: x86_64-w64-mingw32/x64
## Running under: Windows 10 x64 (build 19045)
##
## Matrix products: default
## LAPACK version 3.12.1
##
## locale:
## [1] LC_COLLATE=Spanish_Spain.utf8 LC_CTYPE=Spanish_Spain.utf8
## [3] LC_MONETARY=Spanish_Spain.utf8 LC_NUMERIC=C
## [5] LC_TIME=Spanish_Spain.utf8
##
## time zone: America/Bogota
## tzcode source: internal
##
## attached base packages:
## [1] stats graphics grDevices utils datasets methods base
##
## other attached packages:
## [1] exactextractr_0.10.1 MultiscaleDTM_1.0.1 leaflet_2.2.3
## [4] sf_1.1-1 elevatr_0.99.1 geodata_0.6-9
## [7] terra_1.9-27
##
## loaded via a namespace (and not attached):
## [1] xfun_0.57 bslib_0.10.0 raster_3.6-32 htmlwidgets_1.6.4
## [5] lattice_0.22-9 vctrs_0.7.3 tools_4.6.0 crosstalk_1.2.2
## [9] generics_0.1.4 curl_7.1.0 rgl_1.3.36 tibble_3.3.1
## [13] proxy_0.4-29 pkgconfig_2.0.3 KernSmooth_2.23-26 RColorBrewer_1.1-3
## [17] lifecycle_1.0.5 farver_2.1.2 compiler_4.6.0 progress_1.2.3
## [21] codetools_0.2-20 httpuv_1.6.17 htmltools_0.5.9 class_7.3-23
## [25] sass_0.4.10 yaml_2.3.12 later_1.4.8 pillar_1.11.1
## [29] crayon_1.5.3 jquerylib_0.1.4 classInt_0.4-11 slippymath_0.3.1
## [33] cachem_1.1.0 wk_0.9.5 mime_0.13 tidyselect_1.2.1
## [37] digest_0.6.39 dplyr_1.2.1 purrr_1.2.2 fastmap_1.2.0
## [41] grid_4.6.0 cli_3.6.6 magrittr_2.0.5 base64enc_0.1-6
## [45] e1071_1.7-17 scales_1.4.0 prettyunits_1.2.0 promises_1.5.0
## [49] rappdirs_0.3.4 sp_2.2-1 rmarkdown_2.31 httr_1.4.8
## [53] otel_0.2.0 progressr_0.19.0 png_0.1-9 hms_1.1.4
## [57] shiny_1.13.0 evaluate_1.0.5 knitr_1.51 s2_1.1.9
## [61] rlang_1.2.0 Rcpp_1.1.1-1.1 xtable_1.8-8 glue_1.8.1
## [65] DBI_1.3.0 rstudioapi_0.18.0 jsonlite_2.0.0 R6_2.6.1
## [69] units_1.0-1