Creación de mapas de calor de especies endémicas de Chile A lo largo del siguiente documento se realizara, a modo de tutorial, como realizar paso a paso mapas de calor en base a puntos georreferenciados de plantas obtenido de la plataforma de GBIF.
A lo largo de este documento se realizara, paso a paso, lo necesario para realizar un mapa de calor para “4 especies endémicas seleccionadas” de la Región de Valparaíso.
Los criterios de selección para estas especies fueron que estuvieran clasificadas por el Ministerio de Medio Ambiente (MMA) cómo especies vulnerables, a su vez se buscó dar con aquellas que se encontraran principalmente en la provincia de Valparaíso continental, descartando las islas por razones de escala.
El objetivo de este trabajo es visualizar las áreas de presencia de cada especie y generar un producto final que muestre las zonas donde, en conjunto, estas cuatro especies presentan mayor concentración. Para esto se descargaron datos abiertos de la plataforma de Global Biodiversity Information Facility (GBIF), la cual contiene registros georreferenciados de avistamientos voluntarios de flora y fauna, siendo necesaria una cuenta para acceder a la descarga de los archivos.
A partir de estos datos, se realizó un proceso completo que incluyó la preparación de la información espacial (como transformaciones de polígonos y recortes del área de estudio), la definición de parámetros clave para el KDE, como el ancho de banda y el tipo de kernel, y la generación de los mapas de calor individuales y generales. Este procedimiento permitió identificar ,patrones geográficos de concentración que aportan una mirada integral sobre la distribución de estas especies y su relación con las áreas protegidas actuales.
Lo primero que haremos será cargar todos los paquetes que se utilizarán para realizar todo este proceso, tanto para la cargar tablas de datos (como .xlxs o .csv), vectores y raster, transformación y manipulación de estos, y finalmente los paquetes de SpatialKDE y MASS, los cuales son los requeridos para crear un mapa de calor.
Utilizando un archivo .shp de todas las provincias de Chile, obtenida desde la plataforma de la Biblioteca del Congreso Nacional de Chile (BCN), filtraremos nuestra área de estudio. Importante tener en cuenta que la provincia de Valparaíso posee las islas Juan Fernandez, lo que hara que al momento de plotear el objeto, por las distancias entre las islas y el territorio continentl, los poligonos se veran pequeños, por lo que haremos un proceso para obtener el poligono de la provincia continental.
#### Paquetes ####
library(tidyverse)
library(terra)
library(gstat)
library(sf)
library(SpatialKDE)
library(MASS)
##### Area de estudio #####
# Cargar shape de provincias de Chile
prov <- vect("D:/Aplicaciones_Trabajo/PrimerSemestre2025/SIG-2/Datos Ev. Clave/Provincias/Provincias.shp")
# Filtrar provincia de Valparaíso (Esta posee las islas de Juan Fernandez)
valpo <- prov[prov$Provincia == "Valparaíso", ]
# Separar en polígonos individuales (separa islas de la provincia continental)
valpo_parts <- disagg(valpo)
# Calcular el área de cada poligono resultante
valpo_parts$area <- expanse(valpo_parts)
# Tomar el polígono con mayor área, el cual corresponde a la provincia continental.
prov_valpo <- valpo_parts[which.max(valpo_parts$area), ]
# Reproyectar a UTM
prov_valpo <- project(prov_valpo, "EPSG:32719")
# Visualización
plot(prov_valpo)## class : SpatVector
## geometry : polygons
## dimensions : 1, 9 (geometries, attributes)
## extent : 243756.1, 295615.4, 6291809, 6387507 (xmin, xmax, ymin, ymax)
## coord. ref. : WGS 84 / UTM zone 19S (EPSG:32719)
## names : objectid cir_sena codregion cod_prov st_area_sh st_length_
## type : <int> <int> <int> <int> <num> <num>
## values : 418 6 5 51 2.883e+09 7.536e+05
## Provincia Region area
## <chr> <chr> <num>
## Valparaíso Región de Valp~ 1.905e+09
Lo siguiente que haremos es cargar las bases de datos de las plantas, estas son archivos .csv, los cuales seran cargados con la función read_delim de la libreria readr. Estas tablas serán tratadas mediante filter(!is.na(CoordenadaX/Y)) al momento de cargarlas con tal de eliminar puntos sin coordenadas, posteriormente, estos serán convertidos en vectores utilizando el paquete terra.
Como se mencionó anteriormente, los datos son tablas de datos en formato .csv, a las cuales al leerse se le aplicaran procesos de filtracion, en los cuales las coordenadas sin datos “Na” en las Longitudes y Latitudes seran eliminadas de la tabla con tal de que no de errores a futuro. Se realizara un print() al objeto para confirmar que los archivos habran cargado correctamente.
### Palma Chilena (Jubea Chilensis Molina Baill)
# Abrir tabla con datos de palma
tabla_palma <- read_delim("D:/Aplicaciones_Trabajo/PrimerSemestre2025/SIG-2/Datos Ev. Clave/Plantas/Jubaea Chilensis Molina Baill.csv") %>%
filter(!is.na(decimalLatitude) & !is.na(decimalLongitude))
print(tabla_palma)## # A tibble: 1,381 × 50
## gbifID datasetKey occurrenceID kingdom phylum class order family genus
## <dbl> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr>
## 1 574806525 7adf20e0-c95… http://data… Plantae Trach… Lili… Arec… Areca… Juba…
## 2 574772142 7adf20e0-c95… http://data… Plantae Trach… Lili… Arec… Areca… Juba…
## 3 574670817 7adf20e0-c95… http://data… Plantae Trach… Lili… Arec… Areca… Juba…
## 4 5188456366 50c9509d-22c… https://www… Plantae Trach… Lili… Arec… Areca… Juba…
## 5 5188425990 50c9509d-22c… https://www… Plantae Trach… Lili… Arec… Areca… Juba…
## 6 5188338372 50c9509d-22c… https://www… Plantae Trach… Lili… Arec… Areca… Juba…
## 7 5188246928 50c9509d-22c… https://www… Plantae Trach… Lili… Arec… Areca… Juba…
## 8 5188216315 50c9509d-22c… https://www… Plantae Trach… Lili… Arec… Areca… Juba…
## 9 5188199623 50c9509d-22c… https://www… Plantae Trach… Lili… Arec… Areca… Juba…
## 10 5188196021 50c9509d-22c… https://www… Plantae Trach… Lili… Arec… Areca… Juba…
## # ℹ 1,371 more rows
## # ℹ 41 more variables: species <chr>, infraspecificEpithet <lgl>,
## # taxonRank <chr>, scientificName <chr>, verbatimScientificName <chr>,
## # verbatimScientificNameAuthorship <chr>, countryCode <chr>, locality <chr>,
## # stateProvince <chr>, occurrenceStatus <chr>, individualCount <dbl>,
## # publishingOrgKey <chr>, decimalLatitude <dbl>, decimalLongitude <dbl>,
## # coordinateUncertaintyInMeters <dbl>, coordinatePrecision <lgl>, …
## [1] "gbifID" "datasetKey"
## [3] "occurrenceID" "kingdom"
## [5] "phylum" "class"
## [7] "order" "family"
## [9] "genus" "species"
## [11] "infraspecificEpithet" "taxonRank"
## [13] "scientificName" "verbatimScientificName"
## [15] "verbatimScientificNameAuthorship" "countryCode"
## [17] "locality" "stateProvince"
## [19] "occurrenceStatus" "individualCount"
## [21] "publishingOrgKey" "decimalLatitude"
## [23] "decimalLongitude" "coordinateUncertaintyInMeters"
## [25] "coordinatePrecision" "elevation"
## [27] "elevationAccuracy" "depth"
## [29] "depthAccuracy" "eventDate"
## [31] "day" "month"
## [33] "year" "taxonKey"
## [35] "speciesKey" "basisOfRecord"
## [37] "institutionCode" "collectionCode"
## [39] "catalogNumber" "recordNumber"
## [41] "identifiedBy" "dateIdentified"
## [43] "license" "rightsHolder"
## [45] "recordedBy" "typeStatus"
## [47] "establishmentMeans" "lastInterpreted"
## [49] "mediaType" "issue"
Mediante el uso de print() confirmaremos que la tabla haya sido correctamente cargada y mediante colnames() veremos los nombres de las columnas que posee nuestra tabla de datos, esto con tal de ver cuales poseen las coordenadas de cada objeto. En este caso, las columnas son decimalLatitude y decimalLongitude.
En este punto lo que haremos sera convertir la tabla de datos a un vector usando el paquete terra, lo cual es necesario a la hora de crear un mapa de calor. Como confirmamos en el punto anterior las columnas que poseen nuestras coordenadas a utilizar, nos daremos cuenta que estas estan en sistema de coordenadas geográficas (EPSG:4326), por lo que lo siguiente que haremos sera reproyectarla al mismo sistema de coordenadas de nuestra area de estudio, a su vez sera necesario recortar los datos, esto ya que la tabla de datos posee datos fuera de la provincia, y finalmente lo plotearemos junto al objeto del area de estudio.
# Convertir a objeto espacial (SpatVector) con terra
palma_vect <- vect(tabla_palma,
geom = c("decimalLongitude", "decimalLatitude"), # Se determina la coordenada X e Y
crs = "EPSG:4326") # Sistema de coordenadas
# Reproyectar al CRS de la provincia (EPSG:32719)
palma_vect_proj <- project(palma_vect, crs(prov_valpo))
## Filtrar puntos dentro del área de estudio
# Intersectar o enmascarar según la geometría
palma_valpo <- palma_vect_proj[prov_valpo]
# Visualizar
plot(prov_valpo, col = "lightgray", main = "Jubaea chilensis en provincia de Valparaíso")
points(palma_valpo, col = "darkgreen", pch = 16)Una vez confirmado que los puntos se vean, el siguiente paso consiste en cargar los datos de las siguientes plantas, repitiendo el mismo proceso.
### Flor del águila (alstroemeria pulchra)
# Abrir tabla con datos de pulchra
tabla_pulchra <- read_delim("D:/Aplicaciones_Trabajo/PrimerSemestre2025/SIG-2/Datos Ev. Clave/Plantas/Alstroemeria Pulchra Sims.csv") %>%
filter(!is.na(decimalLatitude) & !is.na(decimalLongitude))
# Convertir a objeto espacial (SpatVector) con terra
pulchra_vect <- vect(tabla_pulchra,
geom = c("decimalLongitude", "decimalLatitude"),
crs = "EPSG:4326")
# Reproyectar al CRS de la provincia (EPSG:32719)
pulchra_vect_proj <- project(pulchra_vect, crs(prov_valpo))
# Filtrar puntos dentro del área de estudio
# Intersectar o enmascarar según la geometría
pulchra_valpo <- pulchra_vect_proj[prov_valpo]
# Visualizar
plot(prov_valpo, col = "lightgray", main = "Alstroemeria Pulchra en provincia de Valparaíso")
points(pulchra_valpo, col = "darkgreen", pch = 16)### Orquidea amarilla (chloraea cristata)
# Abrir tabla con datos de chlorea cristata
tabla_cristata <- read_delim("D:/Aplicaciones_Trabajo/PrimerSemestre2025/SIG-2/Datos Ev. Clave/Plantas/Chloraea cristata Lindl.zip") %>%
filter(!is.na(decimalLatitude) & !is.na(decimalLongitude))
# Convertir a objeto espacial (SpatVector) con terra
cristata_vect <- vect(tabla_cristata,
geom = c("decimalLongitude", "decimalLatitude"),
crs = "EPSG:4326")
# Reproyectar al CRS de la provincia (EPSG:32719)
cristata_vect_proj <- project(cristata_vect, crs(prov_valpo))
# Filtrar puntos dentro del área de estudio
# Intersectar o enmascarar según la geometría
cristata_valpo <- cristata_vect_proj[prov_valpo]
# Visualizar
plot(prov_valpo, col = "lightgray", main = "Chloraea cristata en provincia de Valparaíso")
points(cristata_valpo, col = "darkgreen", pch = 16)### Orquidea de paposo (chloraea disoides)
# Abrir tabla con datos de chlorea disoides
tabla_disoides <- read_delim("D:/Aplicaciones_Trabajo/PrimerSemestre2025/SIG-2/Datos Ev. Clave/Plantas/Chloraea disoides Lindl.csv") %>%
filter(!is.na(decimalLatitude) & !is.na(decimalLongitude))
# Convertir a objeto espacial (SpatVector) con terra
disoides_vect <- vect(tabla_disoides,
geom = c("decimalLongitude", "decimalLatitude"),
crs = "EPSG:4326")
# Reproyectar al CRS de la provincia (EPSG:32719)
disoides_vect_proj <- project(disoides_vect, crs(prov_valpo))
# Filtrar puntos dentro del área de estudio
# Intersectar o enmascarar según la geometría
disoides_valpo <- disoides_vect_proj[prov_valpo]
# Visualizar
plot(prov_valpo, col = "lightgray", main = "Chloraea disoides en provincia de Valparaíso")
points(disoides_valpo, col = "darkgreen", pch = 16)Finalmente guardaremos los poligonos de las plantas en su propia carpeta.
### Guardar vectores de cada planta
# Crear una carpeta para guardar vectores
dir.create("D:/Aplicaciones_Trabajo/PrimerSemestre2025/SIG-2/Shapefiles_plantas", showWarnings = FALSE)
# Guardar el shapefile
writeVector(palma_valpo, "D:/Aplicaciones_Trabajo/PrimerSemestre2025/SIG-2/Shapefiles_plantas/jubaea_chilensis_valpo.shp", overwrite = TRUE)
writeVector(pulchra_valpo, "D:/Aplicaciones_Trabajo/PrimerSemestre2025/SIG-2/Shapefiles_plantas/alstroemeria_pulchra_valpo.shp", overwrite = TRUE)
writeVector(cristata_valpo, "D:/Aplicaciones_Trabajo/PrimerSemestre2025/SIG-2/Shapefiles_plantas/chloraea_cristata_valpo.shp", overwrite = TRUE)
writeVector(disoides_valpo, "D:/Aplicaciones_Trabajo/PrimerSemestre2025/SIG-2/Shapefiles_plantas/chloraea_disoides_valpo.shp", overwrite = TRUE)Ahora comenzaremos con el proceso necesario para crear un mapa de calor (KDE). Este procedimiento incluye la preparación inicial de los datos, como la transformación de polígonos y la extracción de los registros de presencia de nuestras especies endémicas. A partir de esta información definiremos parámetros fundamentales para el cálculo, como el ancho de banda (H) y el tipo de kernel, ajustándolos a las características del área de estudio. Con estos elementos podremos generar el mapa de calor final, el cual se materializa como un raster que representa la intensidad de concentración espacial de las especies y permite identificar patrones geográficos relevantes.
Para realizar este tipo de mapa los vectores tendran que ser convertidos a objetos sf.
Una vez convertidos a objetos sf, ya podremos realizar el proceso de creación de nuestro mapa de calor, en este caso usando la palma chilena como ejemplo. El ancho de banda (h), es un valor numérico que determina la extensión espacial de influencia que tiene cada punto individual sobre el cálculo de densidad, osea el peso que tendra cada uno en el calculo del radio o distancia de dispersion. Valores altos de h otorgan un área de densidad más amplia pero perdiendo patrones locales, mientras que valores pequeños de h permiten observar patrones más localizados, lo que puede acabar provocando “ruido” en el mapa de calor.
Lo primero que tendremos que hacer sera la extracción de las coordenadas de nuestro objeto y con esta calcularemos el ancho de las bandas de nuestro mapa de calor (h).
### Palma
# Extraer coordenadas desde SpatVector
xcoors <- crds(palma_valpo, df = TRUE) # Extrae coordenadas X/Y como data.frame
# Calcular ancho de banda (h) con método de referencia (bandwidth.nrd)
h_est <- (bandwidth.nrd(xcoors[,2]) + bandwidth.nrd(xcoors[,1])) / 2
print(h_est)## [1] 2346.405
Mediante create_raster() crearemos un raster vacio el cual sera usado de base para el kernel, este al tener el tamaño de nuestra area de estudio ocupara el objeto sf de esta, a su vez debemos elegir tanto el tamaño de los pixeles de las celdas (en este caso 500 metros). El kernel es una función matemática la cual es utilizada para distribuir el peso de cada punto dentro del KDE, osea nuestro mapa de calor. Esta define la forma en que decae la influencia de cada punto a medida que aumenta la distancia, esto es parte para determinar la forma de la “campana” de cada punto.
Posteriormente ocupando kde() se creara el mapa de calor, para este sera necesario el objeto de nuestra area de estudio, definir nuestro objeto h, que tipo de proceso kernel usaremos y finalmente nuestro raster.
# crear raster vacio
raster_kernel <- create_raster(prov_valpo_sf, cell_size = 500, side_offset = 100)
# Ejecutar KDE (creación de mapa de calor)
kde_palma <- kde(palma_valpo_sf, # Objeto de puntos al que se le calculara la densidad
band_width = h_palma, # Ancho de banda
kernel = "quartic", # Tipo de funcion que determina como decae la influencia de cada punto.
grid = raster_kernel) # Define el tamaño de las celdas, extension, crs y geometria del KDE## Done: [--------------------------------------------------------------------] .Done: [========================================================------------] .Done: [=========================================================-----------] .Done: [==========================================================----------] .Done: [===========================================================---------] .Done: [============================================================--------] .Done: [=============================================================-------] .Done: [==============================================================------] .Done: [===============================================================-----] .Done: [================================================================----] .Done: [=================================================================---] .Done: [==================================================================--] .Done: [===================================================================-] .Done: [====================================================================] .
# Recortar KDE al área de estudio (cortar y enmascarar)
kde_palma_masked <- kde_palma %>%
crop(prov_valpo_sf) %>%
mask(prov_valpo_sf)
# Visualización
palette <- heat.colors(12) # Creamos una paleta de colores con tonos rojizos para nuestro KDE
rev_palette <- rev(palette)
plot(prov_valpo, col = "lightgray", main = paste("KDE Palma Chilena h =", round(h_palma, 2)))
plot(kde_palma_masked, col = rev_palette, alpha = 0.7, add = TRUE)Con esto finalmente habremos realizado el mapa de calor de la Palma Chilena.
### Pulchra
# Extraer coordenadas desde SpatVector
xcoors_pul <- crds(pulchra_valpo, df = TRUE) # Extrae coordenadas X/Y como data.frame
# Calcular ancho de banda (h) con método de referencia (bandwidth.nrd)
h_pul <- (bandwidth.nrd(xcoors_pul[,2]) + bandwidth.nrd(xcoors_pul[,1])) / 2
print(h_est)## [1] 2346.405
## valor de h = 8434.531
h_pulchra <- h_pul / 3 # para ser mas especificos, partiendo h por 3
# Ejecutar KDE
kde_pulchra <- kde(pulchra_valpo_sf, band_width = h_pulchra, kernel = "quartic", grid = raster_kernel)## Done: [--------------------------------------------------------------------] .Done: [====================================================================] .
# Recortar al área de estudio (cortar y enmascarar)
kde_pulchra_masked <- kde_pulchra %>%
crop(prov_valpo_sf) %>%
mask(prov_valpo_sf)
# Visualización
plot(prov_valpo, col = "lightgray", main = paste("KDE alstroemeria pulchra h =", round(h_pulchra, 2)))
plot(kde_pulchra_masked, col = rev_palette, alpha = 0.7, add = TRUE)### Cristata
# Extraer coordenadas desde SpatVector
xcoors_c <- crds(cristata_valpo, df = TRUE) # Extrae coordenadas X/Y como data.frame
# Calcular ancho de banda (h) con método de referencia (bandwidth.nrd)
h_c <- (bandwidth.nrd(xcoors_c[,2]) + bandwidth.nrd(xcoors_c[,1])) / 2
print(h_c)## [1] 18902.34
## valor de h = 18902.34
h_cristata <- h_c / 5 # para ser mas especificos, partiendo h por 5
# Ejecutar KDE
kde_cristata <- kde(cristata_valpo_sf, band_width = h_cristata, kernel = "quartic", grid = raster_kernel)## Done: [--------------------------------------------------------------------] .Done: [====================================================================] .
# Recortar al área de estudio (cortar y enmascarar)
kde_cristata_masked <- kde_cristata %>%
crop(prov_valpo_sf) %>%
mask(prov_valpo_sf)
# Visualización
plot(prov_valpo, col = "lightgray", main = paste("KDE Chloraea cristata h =", round(h_cristata, 2)))
plot(kde_cristata_masked, col = rev_palette, alpha = 0.7, add = TRUE)### Disoides
# Extraer coordenadas desde SpatVector
xcoors_d <- crds(disoides_valpo, df = TRUE) # Extrae coordenadas X/Y como data.frame
# Calcular ancho de banda (h) con método de referencia (bandwidth.nrd)
h_d <- (bandwidth.nrd(xcoors_d[,2]) + bandwidth.nrd(xcoors_d[,1])) / 2
print(h_d)## [1] 16903.19
## valor de h = 16903.19
h_disoides <- h_d / 4 # para ser mas especificos, partiendo h por 4
# Ejecutar KDE
kde_disoides <- kde(disoides_valpo_sf, band_width = h_disoides, kernel = "quartic", grid = raster_kernel)## Done: [--------------------------------------------------------------------] .Done: [====================================================================] .
# Recortar al área de estudio (cortar y enmascarar)
kde_disoides_masked <- kde_disoides %>%
crop(prov_valpo_sf) %>%
mask(prov_valpo_sf)
# Visualización
plot(prov_valpo, col = "lightgray", main = paste("KDE Chloraea disoides h =", round(h_disoides, 2)))
plot(kde_disoides_masked, col = rev_palette, alpha = 0.7, add = TRUE)La estandarización de los mapas de calor generados anteriormente es fundamental para asegurar una interpretación coherente de estos mismos. Dado que los valores de densidad dependen de factores como el número de puntos, el ancho de banda utilizado y la propia distribución espacial de los datos, los resultados iniciales no son directamente comparables entre diferentes especies o conjuntos de datos. Al transformar cada mapa de calor (los cuales son objetos raster) a una escala relativa entre 0 y 1, donde 0 representa la menor densidad observada y 1 la máxima, se obtiene una superficie normalizada que permite identificar y comparar patrones de acumulación de manera consistente. Esta estandarización mejora la claridad visual, evita interpretaciones confusas basadas en valores absolutos y facilita la lectura de zonas de mayor o menor concentración dentro de cada mapa de calor.
## Estandarizacion de mapas de calor
# Transformacion a objeto terra (necesario para poder generar la estandarización)
kde_palma_terra <- rast(kde_palma_masked)
kde_pulchra_terra <- rast(kde_pulchra_masked)
kde_cristata_terra <- rast(kde_cristata_masked)
kde_disoides_terra <- rast(kde_disoides_masked)
# Funcion de estandarización
estandarizar_raster <- function(r){
min_val <- global(r, "min", na.rm=TRUE)[[1]] # Obtener valor mínimo
max_val <- global(r, "max", na.rm=TRUE)[[1]] # Obtener valor máximo
(r - min_val) / (max_val - min_val) # Formula para que estandarización tenga valores de 0 a 1
}
# Estandarizar
kde_palma_std <- estandarizar_raster(kde_palma_terra)
kde_pulchra_std <- estandarizar_raster(kde_pulchra_terra)
kde_cristata_std <- estandarizar_raster(kde_cristata_terra)
kde_disoides_std <- estandarizar_raster(kde_disoides_terra)
# Visualización
par(mfrow = c(2, 2)) # Esta función sirve para crear un marco en el que cargar cada kde
# Mapa 1
plot(prov_valpo, col = "lightgrey", main = "Mapa de calor de Judaea Chilensis (Palma Chilena)", cex.main = 0.9)
plot(kde_palma_std, col = rev_palette, alpha = 0.7, add = TRUE)
# Mapa 2
plot(prov_valpo, col = "lightgrey", main = "Mapa de calor de Alstroemeria Pulchra (Flor del aguila)", cex.main = 0.9)
plot(kde_pulchra_std, col = rev_palette, alpha = 0.7, add = TRUE)
# Mapa 3
plot(prov_valpo, col = "lightgrey", main = "Mapa de calor de Chloraea cristata (Orquidea)", cex.main = 0.9)
plot(kde_cristata_std, col = rev_palette, alpha = 0.7, add = TRUE)
# Mapa 4
plot(prov_valpo, col = "lightgrey", main = "Mapa de calor de Chloraea Disoides (Flor del gallo)", cex.main = 0.9)
plot(kde_disoides_std, col = rev_palette, alpha = 0.7, add = TRUE)# Creamos carpeta para guardar resultados
dir.create("D:/Aplicaciones_Trabajo/PrimerSemestre2025/SIG-2/KDEs_plantas", showWarnings = FALSE)
# Guardar resultados
writeRaster(kde_palma_std,
filename = "D:/Aplicaciones_Trabajo/PrimerSemestre2025/SIG-2/KDEs_plantas/Palma.tif",
overwrite = TRUE)
writeRaster(kde_pulchra_std,
filename = "D:/Aplicaciones_Trabajo/PrimerSemestre2025/SIG-2/KDEs_plantas/Pulchra.tif",
overwrite = TRUE)
writeRaster(kde_cristata_std,
filename = "D:/Aplicaciones_Trabajo/PrimerSemestre2025/SIG-2/KDEs_plantas/Cristata.tif",
overwrite = TRUE)
writeRaster(kde_disoides_std,
filename = "D:/Aplicaciones_Trabajo/PrimerSemestre2025/SIG-2/KDEs_plantas/disoides.tif",
overwrite = TRUE)Lo ultimo que haremos sera crear un mapa de calor el cual contenga todos los puntos de las plantas, esto con tal de ver el area con mayor concentración general para finalmente contrastarlo con ciudades, calles y santuarios protegidos, tanto por la SNASPE como por la MMA.
Lo primero que haremos sera obtener las geometrias de cada planta mediante la función geom(), estas geometrias sera convertidos en nuevos vectores mediante vect(), las cuales seran posteriormente unidos en un unico objeto mediante rbind().
##### Union de plantas + KDE #####
###union
# Extraer solo geometría, ya que sino dara error fatal al no tener las mismas columnas e intentar unión
palma_geom <- geom(palma_valpo)
pulchra_geom <- geom(pulchra_valpo)
cristata_geom <- geom(cristata_valpo)
disoides_geom <- geom(disoides_valpo)
# Crear vectores nuevos con solo geometría
palma_geom_vect <- vect(palma_geom, crs = crs(palma_valpo))
pulchra_geom_vect <- vect(pulchra_geom, crs = crs(pulchra_valpo))
cristata_geom_vect <- vect(cristata_geom, crs = crs(cristata_valpo))
disoides_geom_vect <- vect(disoides_geom, crs = crs(disoides_valpo))
# Unir plantas
plantas_combinadas <- rbind(palma_geom_vect, pulchra_geom_vect, cristata_geom_vect, disoides_geom_vect)
# Visualizar para verificar
plot(prov_valpo, col = "lightgray", main = "unificacion de plantas")
points(plantas_combinadas, col = "darkred", pch = 16)A continuación vamos a realizar el mismo proceso para crear un mapa de calor con este nuevo objeto, finalizando con la estandarización de este mismo.
### KDE de union de plantas
# convertir a sf
plantas_unidas_sf <- st_as_sf(plantas_combinadas)
# Extraer coordenadas desde SpatVector
xcoors_p <- crds(plantas_combinadas, df = TRUE) # Extrae coordenadas X/Y como data.frame
# Calcular ancho de banda (h) con método de referencia (bandwidth.nrd)
h_p <- (bandwidth.nrd(xcoors_p[,2]) + bandwidth.nrd(xcoors_p[,1])) / 2
print(h_p)## [1] 2975.527
## valor de h = 2975.527
h_plantas <- h_p / 2
# Ejecutar KDE
kde_plantas <- kde(plantas_unidas_sf, band_width = h_plantas, kernel = "quartic", grid = raster_kernel)## Done: [--------------------------------------------------------------------] .Done: [===============================================---------------------] .Done: [================================================--------------------] .Done: [=================================================-------------------] .Done: [==================================================------------------] .Done: [===================================================-----------------] .Done: [====================================================----------------] .Done: [=====================================================---------------] .Done: [======================================================--------------] .Done: [=======================================================-------------] .Done: [========================================================------------] .Done: [=========================================================-----------] .Done: [==========================================================----------] .Done: [===========================================================---------] .Done: [============================================================--------] .Done: [=============================================================-------] .Done: [==============================================================------] .Done: [===============================================================-----] .Done: [================================================================----] .Done: [=================================================================---] .Done: [==================================================================--] .Done: [===================================================================-] .Done: [====================================================================] .
# Recortar al área de estudio (cortar y enmascarar)
kde_plantas_unidas_masked <- kde_plantas %>%
crop(prov_valpo_sf) %>%
mask(prov_valpo_sf)
# Visualización
plot(prov_valpo, col = "lightgray", main = paste("KDE de plantas combinadas h =", round(h_plantas, 2)))
plot(kde_plantas_unidas_masked, col = rev_palette, alpha = 0.7, add = TRUE)# Estandarizacion
kde_plantas_unidas_masked_terra <- rast(kde_plantas_unidas_masked)
kde_plantas_std <- estandarizar_raster(kde_plantas_unidas_masked_terra)
plot(kde_plantas_std, col = rev_palette)# Guardar KDE
writeRaster(kde_plantas_std,
filename = "D:/Aplicaciones_Trabajo/PrimerSemestre2025/SIG-2/KDEs_plantas/kde_plantas_unidas_valpo.tif", overwrite = TRUE)Para finalizar, vamos a contrastar el mapa de calor de todas las plantas con áreas urbanas y progetidas. Poligonos de áreas pobladas, calles y santuarios de la snaspe fueron obtenidos de la Biblioteca del Congreso Nacional de Chile (BCN), sin embargo el ultimo poligono el cual corresponde al Santuario de Palmar El Salto, fue obtenido de la pagina del SIMBIO, de la MMA.
### Poligonos
poblacion <- vect("D:/Aplicaciones_Trabajo/PrimerSemestre2025/SIG-2/Datos Ev. Clave/Areas_Pobladas/Areas_Pobladas.shp")
calles <- vect("D:/Aplicaciones_Trabajo/PrimerSemestre2025/SIG-2/Datos Ev. Clave/Red_Vial/redvial2019.shp")
santuarios <- vect("D:/Aplicaciones_Trabajo/PrimerSemestre2025/SIG-2/Datos Ev. Clave/Snaspe/snaspe.shp")
san_mma <- vect("D:/Aplicaciones_Trabajo/PrimerSemestre2025/SIG-2/Datos Ev. Clave/Palmar El Salto/polygon.shp")
# Reproyectar al CRS de la provincia (EPSG:32719)
poblacion_proj <- project(poblacion, crs(prov_valpo))
calles_proj <- project(calles, crs(prov_valpo))
santuarios_proj <- project(santuarios, crs(prov_valpo))
san_mma_proj <- project(san_mma, crs(prov_valpo))
# Filtrar puntos dentro del área de estudio
# Intersectar o enmascarar según la geometría
poblacion_crop <- intersect(poblacion_proj, prov_valpo)
calles_crop <- intersect(calles_proj, prov_valpo)
santuarios_crop <- intersect(santuarios_proj, prov_valpo)
# visualizar
plot(prov_valpo, col = "lightgray", main = "Contraste de poligonos y mapa de calor")
plot(santuarios_crop, col = "blue", add=T)
plot(calles_crop, col = "black", add = TRUE)
plot(poblacion_crop, col = "green", add = TRUE)
plot(san_mma_proj, col = "brown", add = TRUE)
plot(kde_plantas_std, col = rev_palette, alpha = 0.6, add = TRUE) # el kde se agrega al final ya que sino sale descuadrado lo demasplot(prov_valpo,
col = "lightgray",
xlim = c(255000, 270000), # Especificamos el zoom en las coordenadas X
ylim = c(6332000, 6345000), # Especificamos el zoom en las coordenadas Y
main = "Zoom área de interés")
plot(santuarios_crop, col = "blue", add = TRUE)
plot(calles_crop, col = "black", add = TRUE)
plot(poblacion_crop, col = "green", add = TRUE)
plot(san_mma_proj, col = "brown", add = TRUE)
plot(kde_plantas_std, col = rev_palette, alpha = 0.6, add = TRUE)A lo largo de este documento se explicó, a modo de tutorial, cómo generar mapas de calor para especies endémicas de Chile. Este proceso no solo permite comprender cómo generarlos paso a paso, sino también reflexionar sobre el valor que tienen estos mapas para el análisis espacial, en este caso para la biodiversidad.
Como se mostró, los KDE facilitan la visualización de patrones de concentración en los datos disponibles. Esto permite reconocer la distribución espacial de los registros e incluso sugerir áreas donde sería posible encontrar estas especies, más allá de los puntos muestreados. Esta capacidad es especialmente relevante en contextos de conservación, ya que, como se observó en la última sección, pueden existir zonas de alta concentración que actualmente no están protegidas.
Considerando que las especies seleccionadas son endémicas y están clasificadas como Vulnerables, identificar estos espacios adquiere un valor crítico. La información generada podría orientar a las instituciones responsables hacia la realización de actividades de terreno que confirmen estos patrones y que, eventualmente, respalden la propuesta de nuevas áreas protegidas. En este sentido, los mapas de calor se convierten en una herramienta que no solo apoya el análisis ecológico, sino que también contribuye a la toma de decisiones para la conservación.