Introducción

En el presente documento se expone, de manera detallada y basada en el contexto de la Universidad Nacional de Colombia Sede La Paz, el proceso completo para realizar un análisis de información biológica geoespacial mediante el uso del software R. A lo largo del informe se describe la lectura, tratamiento y conversión de bases de datos provenientes de archivos en formatos .xlsx, .csv y .shp, así como la construcción de objetos espaciales que permiten estructurar adecuadamente los datos para su representación cartográfica. De igual manera, se presenta la forma en que se elaboran mapas de observaciones, mapas de calor y representaciones temáticas basadas en índices de diversidad, utilizando herramientas como sf, dplyr, leaflet y vegan. Adicionalmente, se desarrolla la división del espacio geográfico en cuadrículas, la creación de matrices de abundancia y ausencia-presencia y el cálculo de los índices de Shannon y Simpson, todo ello con el fin de ilustrar una ruta metodológica clara que facilite la comprensión, visualización y análisis de la distribución espacial de las aves en el campus universitario. En síntesis, este documento tiene como propósito servir como una guía práctica y pedagógica que permita a los lectores familiarizarse con el manejo de información georreferenciada en R y con la generación de productos analíticos y cartográficos aplicados al estudio de la biodiversidad.

Previo a empezar, se recomienda tener la última versión de R instalada R 4.5.1.

Paquetes requeridos para la ejecución

Para el procesamiento y el análisis de los datos, sera necesario utilizar los siguientes paquetes:

library(sf)
## Linking to GEOS 3.11.2, GDAL 3.8.2, PROJ 9.3.1; sf_use_s2() is TRUE
library(dplyr)
## 
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
## 
##     filter, lag
## The following objects are masked from 'package:base':
## 
##     intersect, setdiff, setequal, union
library(readxl)
library(janitor)
## 
## Attaching package: 'janitor'
## The following objects are masked from 'package:stats':
## 
##     chisq.test, fisher.test
library(leaflet)
library(leaflet.extras)
library(tidyr)
library(viridis)
## Loading required package: viridisLite
library(vegan)
## Loading required package: permute
## Loading required package: lattice
## This is vegan 2.6-6.1

Obsérvese que la lectura de un paquete se realiza con la función library() y en caso de que aparezca el siguiente error Error: no se encontró la librería 'nombre_paquete', el cual indica que el paquete bajo el nombre nombre_paquete no está instalado, puede proceder instalándolo con la siguiente línea de código install.package("nombre_paquete").

Lectura de las bases de datos

Una vez realizada la lectura de los paquetes, se procede a realizar la importación o lectura de la base de datos. Considerando en este caso que no solo se cuenta con el archivo que contiene los datos del levantamiento, sino que además, se necesitan archivos de la capa base (ya sea poligonos o raster) para la proyección del mapa del campus universitario UNAL; entonces la importación se realizará para ambos archivos.

Lectura de los datos en formato “.xlsx”

Consideremos que el archivo en el cual se encuentran los datos esta un formato .xlsx (es decir, un archivo excel), se utilizará la función read_excel() para la importación como se muestra a continuación:

ruta <- "C:\\Users\\brial\\OneDrive\\Documentos\\Avistamiento_Aves\\"

aves <- read_excel(paste(ruta,"Simulados_datos.xlsx", sep=""),
                   sheet = "Hoja3") 

Cabe mencionar, que la ruta debe ajustarse según donde tenga guardado su archivo.

Lectura de los datos en formato “.csv”

Considere ahora que su archivo de datos sobre el avistamiento de aves no se encuentra en un archivo .xlsx sino en un archivo .csv, entonces la indicación es utilizar la función read.csv() adecuada para esta situación. A continuación, un ejemplo:

aves <- read.csv(ruta,sep = ";")

Note que esta función posee el parametro sep = ";" lo que indica que nuestro archivo esta separado por el signo “;”; por lo cual, usted deberá ajustar este parametro según requiera (por ejemplo: “,”, “_“,”-“,”@“,…).

Tratamiento del registro de aves

Una vez realizada la lectura de la base de datos, se procederá con un tratamiento sencillo para mostrar un ejemplo sencillo de cómo tratar su base de datos una vez cargada al programa R.

aves <- aves %>%
  select(decimalLongitude, decimalLatitude, scientificName, cantidad) %>%
  mutate(
    longitud = as.numeric(decimalLongitude),
    latitud = as.numeric(decimalLatitude)
    ) %>%
  filter(!is.na(latitud), !is.na(longitud))

aves_filtro <- aves %>%
  select(decimalLatitude, scientificName, cantidad) %>%
  mutate(
    latitud = as.numeric(decimalLatitude)
    ) %>% 
  group_by(scientificName) %>%
  summarise(Total_individuos = sum(cantidad, na.rm = TRUE)) %>%
  filter((scientificName == "Colinus cristatus" | 
           scientificName == "Eupsittula pertinax" |
          scientificName == "Falco sparverius"
          ) &
           Total_individuos >= 3)

En este caso, el paquete dplyr permite ejecutar varias acciones a una base de datos y generar una nueva con todo el tratamiento realizado, esto lo realiza con ayuda del operador %>%. En el código mostrado anteriormente para generar la tabla aves_filtro permite seleccionar en primer lugar las columnas que se deseen, en segundo lugar, agregar nuevas columnas, en tercer lugar, agrupar y resumir los datos agrupados sumandolos, en cuarto lugar, filtrar los datos cuantas veces desee.

Base de datos del mapa del campus en formato “.shp”

Ahora bien, para el caso del polígono que delimita el área del campus universitario, se requiere la lectura de un archivo en formato .shp, el cual es un formato de archivo de datos vectoriales para Sistemas de Información Geográfica (SIG), de manera que, si se desea hacer mapas en R, un paquete útil y estándar en el manejo de este tipo de archivos es el paquete sf (simple features), que facilita el trabajo con los datos geográficos, proporcionando una integración más sencilla y directa con los objetos de R.

De manera que la lectura del polígono será realizada con la función st_read() del paquete mencionado anteriormente (sf).

campus <- st_read(paste(ruta,"campus_unal.shp", sep=""), quiet = TRUE) %>%
  st_transform(4326) %>%
  st_make_valid()

Observe que en este caso a la función de la lectura del shapefile (.shp) se le agregan las funciones st_transform(4326) y st_make_valid(), donde la primera permitirá transformar el sistema de coordenadas del objeto espacial para mostrar el mapa correctamente en visores como Leaflet, Google Maps o OpenStreetMap; y la segunda función, aumenta la garantía de que las geometrías cumplan con los estándares espaciales, pues algunos shapefiles tienen geometrías inválidas.

Convertir a objeto espacial la base de archivos “.xlsx”

En este paso, se convierte la base de datos previamente cargada a un objeto espacial, lo cual permite trabajarla en un entorno geográfico. Para ello, se utiliza la función st_as_sf() del paquete sf, que transforma un data frame convencional en un objeto espacial con coordenadas geográficas definidas.

aves.sf <- aves %>%
  st_as_sf(coords = c("longitud", "latitud"), crs = 4326, remove = FALSE)

El argumento coords = c("longitud", "latitud") indica las columnas donde se encuentran las coordenadas, mientras que crs = 4326 establece el sistema de referencia espacial WGS 84, utilizado de manera estándar en plataformas como Google Maps y OpenStreetMap. Por su parte, remove = FALSE conserva las columnas originales de coordenadas dentro del nuevo objeto espacial, evitando su eliminación tras la conversión.

Delimitación según el área de estudio

Una vez definidos los puntos espaciales, se procede a filtrar aquellos que se encuentren dentro del polígono que delimita el campus universitario. Esta operación se realiza mediante la función st_within(), que permite seleccionar únicamente los registros ubicados dentro del área de interés.

aves.sf <- aves.sf[st_within(aves.sf, campus, sparse = FALSE), ]

De esta manera, se garantiza que el análisis posterior se concentre exclusivamente en los datos correspondientes al ámbito espacial del estudio.

Mapa de distribuciones de las aves en el campus universitario

A continuación, se presentan diferentes representaciones cartográficas que permiten visualizar la distribución espacial de las aves registradas dentro del campus universitario, utilizando el paquete leaflet, que facilita la creación de mapas interactivos.

Mapa de observaciones

El primer mapa muestra los puntos de observación de aves sobre una imagen satelital del campus. En este caso, se utiliza la función addCircleMarkers() para representar cada registro con un marcador circular.

leaflet() %>%
  addProviderTiles("Esri.WorldImagery") %>%
  addPolygons(data = campus, fillColor = "transparent", color = "red", weight = 2) %>%
  addCircleMarkers(
    lng = aves.sf$longitud,
    lat = aves.sf$latitud,
    radius = 5,
    color = "orange",
    stroke = FALSE,
    fillOpacity = 0.7,
    popup = paste0(
      "<b>Nombre:</b> ", aves.sf$scientificName, "<br>",
      "<b>Coordenada:</b> ", aves.sf$longitud, ";", aves.sf$latitud, "<br>"
    )
  )

Cada marcador incluye un popup informativo con el nombre científico de la especie y su localización. Esta visualización permite identificar las zonas del campus con mayor concentración de observaciones.

Mapa de calor

En esta segunda representación, se genera un mapa de calor que permite identificar visualmente las zonas con mayor intensidad de observaciones. Para ello, se emplea la función addHeatmap(), la cual utiliza los valores de cantidad de individuos como ponderador.

leaflet() %>%
  addProviderTiles("Esri.WorldImagery") %>%
  addPolygons(data = campus, fillColor = "transparent", color = "red", weight = 2) %>%
  addHeatmap(
    lng = aves.sf$longitud,
    lat = aves.sf$latitud,
    intensity = aves.sf$cantidad * 3,
    radius = 50, blur = 20,
    max = max(aves.sf$cantidad, na.rm = TRUE),
    gradient = c(
      "0.0" = "transparent",
      "0.2" = "skyblue",
      "0.4" = "limegreen",
      "0.6" = "yellow",
      "0.8" = "orange",
      "1.0" = "red"
    )
  )

En este mapa, los colores más cálidos (amarillos y rojos) representan áreas con mayor número de registros o abundancia, mientras que las zonas frías indican menor actividad observada.

Índices de diversidad

División del espacio geografico en cuadriculas

# Convertir a proyección métrica (UTM zona 18N)
campus_utm <- st_transform(campus, 32618)
aves_sf_utm <- st_transform(aves.sf, 32618)

# Crear una cuadrícula de 100 m dentro del campus
grid <- st_make_grid(campus_utm, cellsize = 100, square = TRUE)
grid_sf <- st_sf(ID = 1:length(grid), geometry = grid)
grid_campus <- st_intersection(grid_sf, campus_utm)
## Warning: attribute variables are assumed to be spatially constant throughout
## all geometries
# Unir aves a la cuadrícula
aves_join <- st_join(aves_sf_utm, grid_campus, left = FALSE)

Creación de la matriz de ausencia-presencia

tabla_abundancia <- aves_join %>%
  st_drop_geometry() %>%
  group_by(ID, scientificName) %>%
  summarise(Total_individuos = sum(cantidad, na.rm = TRUE)) %>%
  ungroup() %>%
  pivot_wider(names_from = scientificName,
              values_from = Total_individuos,
              values_fill = 0)
## `summarise()` has grouped output by 'ID'. You can override using the `.groups`
## argument.

Cálculo de los índices de: Shannon y Simpson

Estos índices permiten cuantificar la diversidad de especies dentro de cada cuadrícula definida en el campus. El índice de Shannon mide la abundancia y equidad de las especies, mientras que el índice de Simpson evalúa la probabilidad de que dos individuos seleccionados al azar pertenezcan a la misma especie. Ambos proporcionan una visión integral de la composición ecológica.

diversidad_indices <- tabla_abundancia %>%
  mutate(
    Shannon = diversity(select(., -ID), index = "shannon"),
    Simpson = diversity(select(., -ID), index = "simpson")
  ) %>%
  select(ID, Shannon, Simpson)

En este fragmento, la función diversity() del paquete vegan calcula ambos índices a partir de la matriz de abundancia, excluyendo la columna ID mediante select(., -ID) para operar únicamente sobre las especies.

Unión de los índices con las cuadriculas geoespaciales

Una vez obtenidos los índices, es necesario integrarlos con la capa espacial que representa las celdas del campus, para así visualizar la distribución espacial de la diversidad.

diversidad_sf <- grid_campus %>%
  left_join(diversidad_indices, by = "ID") %>%
  st_transform(4326)

El uso de left_join() permite mantener todas las celdas del campus, asociando los valores de Shannon y Simpson según su identificador (ID). Finalmente, st_transform(4326) ajusta el sistema de coordenadas para garantizar la compatibilidad con visores geográficos.

Mapa del índice de shannon por cuadricula

Para representar los valores obtenidos, se genera un mapa temático utilizando la paleta viridis, la cual ofrece una escala perceptualmente uniforme y adecuada para interpretación visual.

pal_shannon <- colorNumeric("viridis", domain = diversidad_sf$Shannon)

leaflet(diversidad_sf) %>%
  addProviderTiles(providers$CartoDB.Positron) %>%
  addPolygons(
    fillColor = ~pal_shannon(Shannon),
    color = "grey40",
    weight = 1,
    fillOpacity = 0.7,
    label = ~paste0("Shannon: ", round(Shannon, 2))
  ) %>%
  addLegend(pal = pal_shannon, values = diversidad_sf$Shannon,
            title = "Índice de Shannon") %>%
  addPolygons(data = campus, fill = NA, color = "black", weight = 1.5)

En este código, cada celda se colorea según su valor de diversidad. La función addLegend() agrega una escala interpretativa al mapa, facilitando la comparación entre áreas. La capa final resalta los límites del campus para contextualizar espacialmente los resultados.

Mapa del índice de simpson por cuadricula

Finalmente, se representa el índice de Simpson, el cual mide la probabilidad de que dos individuos seleccionados al azar dentro de una muestra pertenezcan a la misma especie. A diferencia del índice de Shannon, este indicador otorga un mayor peso a las especies dominantes, por lo que valores bajos reflejan una alta diversidad y valores altos indican dominancia de pocas especies.

pal_simpson <- colorNumeric("magma", domain = diversidad_sf$Simpson)

leaflet(diversidad_sf) %>%
  addProviderTiles(providers$CartoDB.Positron) %>%
  addPolygons(
    fillColor = ~pal_simpson(Simpson),
    color = "grey40",
    weight = 1,
    fillOpacity = 0.7,
    label = ~paste0("Simpson: ", round(Simpson, 2))
  ) %>%
  addLegend(pal = pal_simpson, values = diversidad_sf$Simpson,
            title = "Índice de Simpson") %>%
  addPolygons(data = campus, fill = NA, color = "black", weight = 1.5)

En este caso, la paleta “magma” permite resaltar las variaciones en los valores del índice de forma visualmente armónica. La función addLegend() agrega una escala que facilita la interpretación de los resultados, mientras que addPolygons() refuerza los límites del campus universitario para mantener el contexto espacial de la representación.