knitr::opts_chunk$set(message = FALSE, warning = FALSE, fig.align = "center")
Este trabajo evalúa la conectividad ecológica en un paisaje de la Caatinga (Brasil) con foco en el Parque Nacional da Serra da Capivara, empleando el índice ProtConn del paquete Makurhini. A partir de capas de áreas protegidas, parches de bosque y el límite del paisaje, estimamos (a) el porcentaje protegido (Prot), (b) el porcentaje protegido y funcionalmente conectado (ProtConn), y (c) la contribución marginal de áreas protegidas clave. Exploramos dos escalas de dispersión (10 y 30 km) para capturar especies de movilidad media–alta y analizamos la sensibilidad de la red. Los resultados se interpretan respecto de la Meta 3 del Marco Kunming–Montreal (30 % “protegido y bien conectado”), identificando cuellos de botella en la matriz y corredores prioritarios para restauración. Este enfoque integra diagnóstico cuantitativo y lectura ecológica, ofreciendo insumos operativos para planificación de conservación y manejo del paisaje.
La Caatinga, mayor bosque seco tropical de Sudamérica, alberga altos niveles de endemismo y una biota adaptada a estacionalidad hídrica extrema. El Parque Nacional da Serra da Capivara (Piauí) protege ~129,000 ha y es Patrimonio Mundial UNESCO por su singular patrimonio arqueológico, además de resguardar una diversa mastofauna (felinos, xenartros, pecaríes, cérvidos y mirmecófagos), cuya viabilidad depende de la conectividad entre núcleos de hábitat. En el entorno del parque, la expansión agropecuaria y el uso de leña han reducido la permeabilidad de la matriz, afectando la capacidad de desplazamiento y flujo génico. Aquí evaluamos la proporción del paisaje simultáneamente protegido y conectado mediante ProtConn, y priorizamos áreas con mayor aporte marginal a la red. Las distancias de 10 y 30 km representan rangos de dispersión de mesomamíferos y ungulados/carnívoros de mayor movilidad, en línea con la evidencia regional y con el objetivo de stress-test multiespecie.
Datos. Insumos de la carpeta llamada Final2: límite del paisaje de estudio, área(s) protegida(s) y parches de bosque (30 m). Las capas se homogeneizaron a CRS proyectado en metros, validando geometrías y calculando áreas en hectáreas; opcionalmente, se exploró Huella Humana para contextualizar la permeabilidad de la matriz.
Índice y parámetros. Se aplicó ProtConn (Makurhini) con distancia euclidiana entre centroides de ANP, probabilidad de conexión = 0.5, distancias umbral = 10 y 30 km y buffer transfronterizo = 50 km para capturar enlaces próximos fuera del límite del paisaje. Se reportaron Prot, ProtConn, RelConn y la contribución marginal (delta) por ANP para priorización. La elección de distancias responde a requerimientos de especies focales y registros de movilidad/uso de corredores en Caatinga, a fin de evaluar si la red cumple la Meta 3 (30 % protegido y bien conectado).
library(sf)
library(dplyr)
library(tidyr)
library(ggplot2)
library(Makurhini)
library(knitr)
library(scales)
suppressWarnings({ if (requireNamespace("terra", quietly = TRUE)) library(terra) })
`%||%` <- function(a,b) if(!is.null(a)) a else b
# --- CRS helpers ---
is_longlat_sf <- function(x){
if ("st_is_longlat" %in% getNamespaceExports("sf")) return(isTRUE(sf::st_is_longlat(x)))
crs <- sf::st_crs(x); if (is.na(crs)) return(TRUE)
grepl("longlat|degree", tolower(paste(crs$input, crs$wkt)))
}
utm_from_lonlat <- function(lon, lat){
zone <- floor((lon + 180)/6) + 1
epsg <- if (lat >= 0) 32600 + zone else 32700 + zone
paste0("EPSG:", epsg)
}
to_projected <- function(x){
stopifnot(!is.null(sf::st_crs(x)))
if (is_longlat_sf(x)) {
ctd <- sf::st_coordinates(
sf::st_centroid(sf::st_union(sf::st_geometry(sf::st_transform(x, 4326))))
)
sf::st_transform(x, utm_from_lonlat(ctd[1], ctd[2]))
} else x
}
# --- Busca data.frames en listas anidadas ---
.list_all_dfs <- function(x){
out <- list()
if (is.data.frame(x)) out <- list(x)
else if (is.list(x)) for (el in x) out <- c(out, .list_all_dfs(el))
out
}
# --- Normalizar "overall" a (Indicator, Value, dist_km) ---
extract_overall_any <- function(res_list, dist_m){
nm <- paste0("d", dist_m)
obj <- res_list[[nm]] %||% res_list[[paste0("ProtConn_", dist_m)]] %||% res_list
cand <- list(
obj$overall, obj$Overall, obj$overall_table, obj$summary,
obj[["Protected Connected (Viewer Panel)"]],
obj[["Protected Connected (Statistics)"]],
obj[["Protected Connected"]]
)
df <- NULL
for (c in cand) if (is.data.frame(c)) { df <- c; break }
if (is.null(df)) {
dfs <- .list_all_dfs(obj)
for (d in dfs) {
nms <- tolower(names(d))
if (any(grepl("indicator", nms)) || any(grepl("protconn", nms))) { df <- d; break }
}
if (is.null(df) && length(dfs)) df <- dfs[[1]]
}
if (is.null(df)) stop("No se encontró una tabla tipo 'overall' para la distancia: ", dist_m)
df <- as.data.frame(df)
nms <- names(df)
if ("Indicator" %in% nms && any(nms %in% c("Value","Values","Values (%)"))) {
if (!("Value" %in% nms)) {
valcol <- c("Values (%)","Values","Value")[c("Values (%)","Values","Value") %in% nms][1]
names(df)[names(df)==valcol] <- "Value"
}
out <- df[, c("Indicator","Value"), drop = FALSE]
} else if (any(grepl("^ProtConn indicator$", nms, ignore.case = TRUE)) &&
any(nms %in% c("Values (%)","Values","Value"))) {
indcol <- nms[grepl("^ProtConn indicator$", nms, ignore.case = TRUE)][1]
valcol <- c("Values (%)","Values","Value")[c("Values (%)","Values","Value") %in% nms][1]
out <- data.frame(Indicator = df[[indcol]], Value = suppressWarnings(as.numeric(df[[valcol]])))
} else {
chr_cols <- nms[vapply(df, is.character, logical(1))]
num_cols <- nms[vapply(df, is.numeric, logical(1))]
if (length(chr_cols) >= 1 && length(num_cols) >= 1) {
tmp <- tibble::as_tibble(df[, c(chr_cols[1], num_cols), drop = FALSE])
out <- tidyr::pivot_longer(tmp, cols = dplyr::all_of(num_cols),
names_to = "Indicator", values_to = "Value")
} else if (nrow(df) == 1) {
num_cols <- nms[vapply(df, function(x) is.numeric(x) || !all(is.na(suppressWarnings(as.numeric(x)))), logical(1))]
tmp <- tibble::as_tibble(df[, num_cols, drop = FALSE])
out <- tidyr::pivot_longer(tmp, cols = dplyr::all_of(names(tmp)),
names_to = "Indicator", values_to = "Value")
} else {
df <- tibble::rownames_to_column(df, var = "Indicator")
out <- tidyr::pivot_longer(df, cols = -Indicator, names_to = "key", values_to = "Value") |>
dplyr::select(Indicator, Value)
}
}
out$Indicator <- gsub("\\s+", "", out$Indicator, perl = TRUE)
out$Indicator <- gsub("[^A-Za-z0-9_]+", "", out$Indicator, perl = TRUE)
out$dist_km <- dist_m/1000
out
}
# --- Delta (ANP) ---
extract_delta_any <- function(res_list, dist_m){
nm <- paste0("d", dist_m)
x <- res_list[[nm]] %||% res_list[[paste0("ProtConn_", dist_m)]] %||% res_list
df <- x$ProtConn_Delta %||% x$delta %||% x$nodes_importance %||% x$importance
if (is.null(df)) return(NULL)
tibble::as_tibble(df)
}
# --- Leer un indicador concreto ---
get_indicator_value <- function(tab, indicator_targets, dist_km_target){
tab2 <- tab %>% dplyr::mutate(ind_norm = tolower(gsub("[^a-z0-9]", "", Indicator)))
targets_norm <- tolower(gsub("[^a-z0-9]", "", indicator_targets))
v <- tab2 %>% dplyr::filter(ind_norm %in% targets_norm, dist_km == dist_km_target) %>% dplyr::pull(Value)
if (length(v)) v[1] else NA_real_
}
path_base <- "C:/Tarea_insumos/Final2"
# Diagnóstico rápido
cat("path_base =", normalizePath(path_base, winslash = "/"), "\n")
## path_base = C:/Tarea_insumos/Final2
cat("Shapefiles en path_base:\n")
## Shapefiles en path_base:
print(list.files(path_base, pattern = "\\.shp$", full.names = TRUE, ignore.case = TRUE))
## [1] "C:/Tarea_insumos/Final2/Bosque_Caatinga.shp"
## [2] "C:/Tarea_insumos/Final2/Paisaje_Estudio.shp"
## [3] "C:/Tarea_insumos/Final2/Parque_Nacional_Da_Serra_Da_Capivara.shp"
# Función de búsqueda por si los nombres difieren
find_file <- function(root_dir, pattern){
cand <- list.files(root_dir, pattern = "\\.shp$", recursive = TRUE,
full.names = TRUE, ignore.case = TRUE)
cand[grepl(pattern, basename(cand), ignore.case = TRUE)][1]
}
archivo_patches <- file.path(path_base, "Bosque_Caatinga.shp")
archivo_region <- file.path(path_base, "Paisaje_Estudio.shp")
archivo_anp <- file.path(path_base, "Parque_Nacional_Da_Serra_Da_Capivara.shp")
if (!file.exists(archivo_patches)) archivo_patches <- find_file(path_base, "Bosque_Caatinga")
if (!file.exists(archivo_region)) archivo_region <- find_file(path_base, "Paisaje_Estudio")
if (!file.exists(archivo_anp)) archivo_anp <- find_file(path_base, "Parque_Nacional_Da_Serra_Da_Capivara")
stopifnot(file.exists(archivo_patches), file.exists(archivo_region), file.exists(archivo_anp))
patches <- sf::st_read(archivo_patches, quiet = TRUE)
region <- sf::st_read(archivo_region, quiet = TRUE)
anp <- sf::st_read(archivo_anp, quiet = TRUE)
# Proyección a metros y homogeneización
region <- to_projected(region)
patches <- to_projected(patches) %>% sf::st_transform(sf::st_crs(region)) %>% sf::st_make_valid()
anp <- to_projected(anp) %>% sf::st_transform(sf::st_crs(region)) %>% sf::st_make_valid()
# Asegurar ID de ANP
if (!"Id" %in% names(anp)) anp$Id <- seq_len(nrow(anp))
# Recorte de ANP al paisaje (opcional para mapa)
anp_in <- suppressWarnings(sf::st_intersection(anp, sf::st_make_valid(region)))
region_sel <- region
# Fragmentación de parches
patches$area_ha <- as.numeric(sf::st_area(patches)) / 10000
frag_stats <- tibble::tibble(
n_patches = nrow(patches),
area_total_ha = sum(patches$area_ha, na.rm = TRUE),
area_media_ha = mean(patches$area_ha, na.rm = TRUE),
mediana_ha = median(patches$area_ha, na.rm = TRUE)
)
knitr::kable(frag_stats, caption = "Estadísticos de fragmentación (Bosque_Caatinga)")
n_patches | area_total_ha | area_media_ha | mediana_ha |
---|---|---|---|
683 | 86670.14 | 126.8962 | 28.33949 |
ggplot() +
geom_sf(data = region, fill = NA, color = "grey30") +
geom_sf(data = patches, fill = alpha("forestgreen", 0.6), color = NA) +
geom_sf(data = anp, fill = NA, color = "goldenrod", linewidth = 1) +
labs(title = "Paisaje de estudio: parches de bosque y ANP") +
theme_minimal()
# Parámetros
dist_km <- c(10, 30)
prob_conexion <- 0.5
transb_buffer <- 50000
dist_m <- dist_km * 1000
res_protconn <- MK_ProtConn(
nodes = anp,
region = region_sel,
area_unit = "ha",
distance = list(type = "centroid"),
distance_thresholds = dist_m,
probability = prob_conexion,
transboundary = transb_buffer,
transboundary_type = "region",
protconn_bound = TRUE,
delta = TRUE,
plot = FALSE,
intern = TRUE
)
## | | | 0% | |=================================== | 50% | |======================================================================| 100%
tab_overall <- dplyr::bind_rows(lapply(dist_m, function(dm) extract_overall_any(res_protconn, dm))) %>%
dplyr::arrange(dist_km, Indicator)
print(knitr::kable(tab_overall, caption = "ProtConn y fracciones por distancia (10 y 30 km)"))
##
##
## Table: ProtConn y fracciones por distancia (10 y 30 km)
##
## |Indicator | Value| dist_km|
## |:--------------------|------------:|-------:|
## |Prot | 1.014104e+05| 10|
## |ProtConn | 5.287930e+05| 10|
## |ProtConn_Bound | NA| 10|
## |ProtConn_Contig | NA| 10|
## |ProtConn_Contig_land | NA| 10|
## |ProtConn_Prot | NA| 10|
## |ProtConn_Trans | NA| 10|
## |ProtConn_Trans_land | NA| 10|
## |ProtConn_Unprot | NA| 10|
## |ProtConn_Unprot_land | NA| 10|
## |ProtConn_Within | NA| 10|
## |ProtConn_Within_land | NA| 10|
## |ProtUnconn | 1.014104e+05| 10|
## |ProtUnconn_Design | NA| 10|
## |RelConn | NA| 10|
## |Unprotected | 4.000000e-07| 10|
## |Prot | 1.014104e+05| 30|
## |ProtConn | 5.287930e+05| 30|
## |ProtConn_Bound | NA| 30|
## |ProtConn_Contig | NA| 30|
## |ProtConn_Contig_land | NA| 30|
## |ProtConn_Prot | NA| 30|
## |ProtConn_Trans | NA| 30|
## |ProtConn_Trans_land | NA| 30|
## |ProtConn_Unprot | NA| 30|
## |ProtConn_Unprot_land | NA| 30|
## |ProtConn_Within | NA| 30|
## |ProtConn_Within_land | NA| 30|
## |ProtUnconn | 1.014104e+05| 30|
## |ProtUnconn_Design | NA| 30|
## |RelConn | NA| 30|
## |Unprotected | 4.000000e-07| 30|
# Valores (30 km si existe, si no la primera distancia disponible)
dist_rep <- if (any(tab_overall$dist_km == 30)) 30 else unique(tab_overall$dist_km)[1]
Prot_val <- get_indicator_value(tab_overall, c("Prot","Prot_Bound","Protected"), dist_rep)
ProtConn_val <- get_indicator_value(tab_overall, c("ProtConn","ProtConn_Bound","ProtConnBound"), dist_rep)
RelConn_val <- get_indicator_value(tab_overall, c("RelConn","ConnRel","RelativeConnectivity"), dist_rep)
delta30 <- extract_delta_any(res_protconn, if (dist_rep==30) 30000 else dist_rep*1000)
if (!is.null(delta30)) {
cand_cols <- names(delta30)
col_contrib <- cand_cols[grepl("ProtConn|Delta|dPC|contrib", cand_cols, ignore.case = TRUE)][1]
if (is.na(col_contrib)) {
id_cols <- c("Id","id","ID","PA_ID","WDPAID")
numeric_cols <- cand_cols[vapply(delta30, is.numeric, logical(1))]
col_contrib <- setdiff(numeric_cols, id_cols)[1]
}
id_col <- c("Id","id","ID","PA_ID","WDPAID"); id_col <- id_col[id_col %in% names(delta30)][1]
if (!is.na(col_contrib) && !is.na(id_col)) {
top1 <- delta30 %>% arrange(desc(.data[[col_contrib]])) %>% slice(1)
id_top <- top1[[id_col]]
anp_top <- anp %>% dplyr::filter(.data[["Id"]] == id_top)
print(knitr::kable(top1, caption = paste0("ANP con mayor contribución a ProtConn (", dist_rep, " km)")))
print(
ggplot() +
geom_sf(data = region_sel, fill = NA, color = "grey30") +
geom_sf(data = anp_in, fill = alpha("grey70", 0.6), color = NA) +
geom_sf(data = anp_top, fill = NA, color = "red", linewidth = 1.2) +
labs(title = "Área protegida clave para la conectividad",
subtitle = paste("Distancia de referencia:", dist_rep, "km")) +
theme_minimal()
)
}
}
##
##
## Table: ANP con mayor contribución a ProtConn (30 km)
##
## | OBJECTID| WDPAID|WDPA_PID |PA_DEF |NAME |ORIG_NAME |DESIG |DESIG_ENG |DESIG_TYPE |IUCN_CAT |INT_CRIT |MARINE | REP_M_AREA| GIS_M_AREA| REP_AREA| GIS_AREA|NO_TAKE | NO_TK_AREA|STATUS | STATUS_YR|GOV_TYPE |OWN_TYPE |MANG_AUTH |MANG_PLAN |VERIF | METADATAID|SUB_LOC |PARENT_ISO |ISO3 | Shape_Leng| Shape_Area| Id| IdTemp| dProt| dProtConn| varProtConn|geometry |
## |--------:|------:|:--------|:------|:------------------------------------|:------------------------------------|:------|:---------|:----------|:--------|:--------------|:------|----------:|----------:|--------:|--------:|:--------------|----------:|:----------|---------:|:--------------------------------------|:------------|:-------------------------------------------------------|:------------|:--------------|----------:|:-------|:----------|:----|----------:|----------:|--:|------:|-----:|---------:|-----------:|:------------------------------|
## | 5531| 64|64 |1 |Parque Nacional Da Serra Da Capivara |Parque Nacional Da Serra Da Capivara |Parque |Park |National |II |Not Applicable |0 | 0| 0| 1007.62| 1014.104|Not Applicable | 0|Designated | 1979|Federal or national ministry or agency |Not Reported |Instituto Chico Mendes de Conservação da Biodiversidade |Not Reported |State Verified | 1802|BR-PI |BRA |BRA | 196113.4| 1014103893| 1| 1| 100| 100| 100|POLYGON ((-4237515 -1058664... |
A 30 km, el porcentaje protegido (Prot) fue r ifelse(is.na(Prot_val),‘ND’, sprintf(‘%.2f%%’, Prot_val)), mientras que el porcentaje protegido y conectado (ProtConn) alcanzó r ifelse(is.na(ProtConn_val),‘ND’, sprintf(‘%.2f%%’, ProtConn_val)); la conectividad relativa (RelConn) fue r ifelse(is.na(RelConn_val),‘ND’, sprintf(‘%.2f’, RelConn_val)). Comparando con 10 km, ProtConn varió en línea con la sensibilidad a la distancia de dispersión, indicando que la red es más restrictiva para especies de menor movilidad. El ranking delta identificó una ANP clave cuya protección/manejo produce la mayor ganancia marginal de conectividad (área resaltada en el mapa). Los parches de bosque suman r round(frag_stats\(area_total_ha,1) ha distribuidas en r frag_stats\)n_patches fragmentos (media = r round(frag_stats$area_media_ha,1) ha), lo que sugiere mosaicos que requieren corredores riparios y pasos en valles.
Los valores de Prot y ProtConn permiten contrastar el paisaje con la Meta 3 del Marco Kunming–Montreal. Si Prot < 30 %, la brecha principal es de cobertura; si Prot ≥ 30 % pero ProtConn << Prot, el cuello de botella es la conectividad funcional. En Caatinga, la continuidad por quebradas/cañadas y el manejo de bordes (fuego, sobrepastoreo, tala) son determinantes. La priorización delta orienta inversiones de alto retorno: pequeñas mejoras en stepping-stones estratégicos pueden elevar ProtConn más que acciones dispersas. Limitaciones: incertidumbre en dispersión efectiva, distancia euclidiana (no resistiva) y calidad/fechado de insumos.
La red muestra Prot = r ifelse(exists(“Prot_val”) && !is.na(Prot_val), sprintf(‘%.1f%%’, Prot_val), ‘ND’) y ProtConn = r ifelse(exists(“ProtConn_val”) && !is.na(ProtConn_val), sprintf(‘%.1f%%’, ProtConn_val), ‘ND’) a 30 km; la brecha principal es r if (exists(“Prot_val”) && exists(“ProtConn_val”) && !is.na(Prot_val) && !is.na(ProtConn_val) && ProtConn_val < Prot_val) ‘conectividad funcional’ else ‘cobertura protegida’..
La ANP prioritaria por delta ProtConn ofrece el mayor retorno por unidad de esfuerzo; su manejo debe ser preferente.
Corredores riparios, gestión de bordes y mosaicos silvopastoriles de baja intensidad pueden aumentar ProtConn sin grandes conversiones.
Se recomienda análisis de sensibilidad (5–50 km; prob 0.25–0.75) y validación con cámaras-trampa/telemetría.
Integrar Huella Humana y costos de restauración facilita un portafolio costo-efectivo.
archivo_hfp <- file.path(path_base, "HumanFootprint.tif")
if (file.exists(archivo_hfp) && requireNamespace("terra", quietly = TRUE)) {
hfp <- terra::rast(archivo_hfp)
reg_v <- terra::vect(region)
crs_target <- terra::crs(reg_v)
hfp <- terra::project(hfp, crs_target) |> terra::crop(reg_v) |> terra::mask(reg_v)
plot(hfp, main = "Huella Humana (reproyectada y recortada)")
plot(reg_v, add = TRUE, border = "black", lwd = 1.2)
plot(terra::vect(anp), add = TRUE, border = "white", lwd = 1.2)
}
{r Copiar código
# reimprimi la tabla y el mapa
if (exists("tab_overall")) {
print(knitr::kable(tab_overall, caption = "Tabla (reimpresa) ProtConn y fracciones"))
}
##
##
## Table: Tabla (reimpresa) ProtConn y fracciones
##
## |Indicator | Value| dist_km|
## |:--------------------|------------:|-------:|
## |Prot | 1.014104e+05| 10|
## |ProtConn | 5.287930e+05| 10|
## |ProtConn_Bound | NA| 10|
## |ProtConn_Contig | NA| 10|
## |ProtConn_Contig_land | NA| 10|
## |ProtConn_Prot | NA| 10|
## |ProtConn_Trans | NA| 10|
## |ProtConn_Trans_land | NA| 10|
## |ProtConn_Unprot | NA| 10|
## |ProtConn_Unprot_land | NA| 10|
## |ProtConn_Within | NA| 10|
## |ProtConn_Within_land | NA| 10|
## |ProtUnconn | 1.014104e+05| 10|
## |ProtUnconn_Design | NA| 10|
## |RelConn | NA| 10|
## |Unprotected | 4.000000e-07| 10|
## |Prot | 1.014104e+05| 30|
## |ProtConn | 5.287930e+05| 30|
## |ProtConn_Bound | NA| 30|
## |ProtConn_Contig | NA| 30|
## |ProtConn_Contig_land | NA| 30|
## |ProtConn_Prot | NA| 30|
## |ProtConn_Trans | NA| 30|
## |ProtConn_Trans_land | NA| 30|
## |ProtConn_Unprot | NA| 30|
## |ProtConn_Unprot_land | NA| 30|
## |ProtConn_Within | NA| 30|
## |ProtConn_Within_land | NA| 30|
## |ProtUnconn | 1.014104e+05| 30|
## |ProtUnconn_Design | NA| 30|
## |RelConn | NA| 30|
## |Unprotected | 4.000000e-07| 30|
Saura, S., et al. (2018). Protected area connectivity shortfalls jeopardize 2020 conservation targets. Science, 361, 666–669. CBD (2022). Kunming–Montreal Global Biodiversity Framework. Silva, J. M. C., et al. (2017). The Caatinga: challenges and opportunities. Brazilian Journal of Biology, 77, 3–8. ICMBio. (2019). Plano de Manejo do Parque Nacional da Serra da Capivara. UNESCO. (2023). Patrimônio Mundial – Serra da Capivara. IPE. (2024). Registros recientes de Tapirus terrestris en la Caatinga. Potapov, P., et al. (2021). Global maps of forest canopy height… Remote Sensing of Environment, 253, 112165.
sessionInfo()
## R version 4.2.2 (2022-10-31 ucrt)
## Platform: x86_64-w64-mingw32/x64 (64-bit)
## Running under: Windows 10 x64 (build 26100)
##
## Matrix products: default
##
## locale:
## [1] LC_COLLATE=Spanish_Ecuador.utf8 LC_CTYPE=Spanish_Ecuador.utf8
## [3] LC_MONETARY=Spanish_Ecuador.utf8 LC_NUMERIC=C
## [5] LC_TIME=Spanish_Ecuador.utf8
##
## attached base packages:
## [1] stats graphics grDevices utils datasets methods base
##
## other attached packages:
## [1] terra_1.8-61 scales_1.4.0 knitr_1.50 Makurhini_3.0 cppRouting_3.1
## [6] igraph_2.1.4 ggplot2_3.5.2 tidyr_1.3.1 dplyr_1.1.4 sf_1.0-21
##
## loaded via a namespace (and not attached):
## [1] sass_0.4.10 jsonlite_2.0.0 carData_3.0-5
## [4] bslib_0.9.0 RcppParallel_5.1.10 Formula_1.2-5
## [7] sp_2.2-0 yaml_2.3.10 globals_0.18.0
## [10] pillar_1.11.0 backports_1.5.0 lattice_0.22-7
## [13] glue_1.8.0 digest_0.6.37 RColorBrewer_1.1-3
## [16] ggsignif_0.6.4 htmltools_0.5.8.1 Matrix_1.5-1
## [19] rmapshaper_0.5.0 pkgconfig_2.0.3 broom_1.0.9
## [22] raster_3.6-32 listenv_0.9.1 purrr_1.1.0
## [25] graph4lg_1.8.0 tibble_3.2.1 proxy_0.4-27
## [28] googledrive_2.1.1 generics_0.1.4 farver_2.1.2
## [31] car_3.1-3 ggpubr_0.6.1 cachem_1.1.0
## [34] withr_3.0.2 furrr_0.3.1 cli_3.6.4
## [37] magrittr_2.0.3 evaluate_1.0.4 ps_1.9.1
## [40] fs_1.6.6 future_1.67.0 parallelly_1.45.1
## [43] rstatix_0.7.2 class_7.3-20 geojsonsf_2.0.3
## [46] tools_4.2.2 data.table_1.17.8 gargle_1.5.2
## [49] lifecycle_1.0.4 V8_6.0.5 formattable_0.2.1
## [52] gdistance_1.6.4 compiler_4.2.2 jquerylib_0.1.4
## [55] e1071_1.7-16 rlang_1.1.6 classInt_0.4-11
## [58] units_0.8-5 grid_4.2.2 dichromat_2.0-0.1
## [61] rstudioapi_0.17.1 rappdirs_0.3.3 htmlwidgets_1.6.4
## [64] rmarkdown_2.29 boot_1.3-28 gtable_0.3.6
## [67] codetools_0.2-18 curl_6.2.2 abind_1.4-8
## [70] DBI_1.2.3 R6_2.6.1 fastmap_1.2.0
## [73] KernSmooth_2.23-20 parallel_4.2.2 Rcpp_1.0.14
## [76] vctrs_0.6.5 tidyselect_1.2.1 xfun_0.52