2 Estadísticas de fragmentación del paisaje
Exploraremos la función MK_Fragmentation()
para caracterizar la composición y la configuración espacial de los parches en nuestro paisaje.
La función calcula ocho métricas a nivel de nodo (como el área de nodo, el porcentaje de borde y la dimensión fractal) y 13 estadísticas de fragmentación a nivel de paisaje (como el número de nodos, el tamaño medio, la densidad de borde y el tamaño efectivo de la malla).
Las entradas incluyen un objeto vectorial que representa los nodos del paisaje y un parámetro que define la distancia o profundidad de la influencia del borde (es decir, la distancia al borde del nodo).
Los resultados consisten en un archivo vectorial tipo poligonal que contiene métricas a nivel de nodo y una tabla que detalla las métricas a nivel de paisaje.
2.1 Inputs
Usaremos la librerias sf, para trabajar con un shapefile que contiene 404 parches de vegetación con la menor alteración o signos de degradación en un estado de México llamado Michoacán. Tambien cargaremos el paisaje de estudio donde se encuentran los parches y que fue delimitado usando el limite politico del estado y la región fisiográfica denominada Eje Neovolcánico.
El shapefile lo pueden encontrar en la siguiente carpeta del drive:
https://drive.google.com/drive/folders/1yJcxk2JsEfVjqBx7QM6SV5sIbq7YD1iX?usp=sharing
#> Cargando paquete requerido: igraph
#>
#> Adjuntando el paquete: 'igraph'
#> The following objects are masked from 'package:stats':
#>
#> decompose, spectrum
#> The following object is masked from 'package:base':
#>
#> union
#> Cargando paquete requerido: cppRouting
#> Linking to GEOS 3.13.0, GDAL 3.10.1, PROJ 9.5.1;
#> sf_use_s2() is TRUE
#> [1] 404
library(Makurhini)
library(sf)
habitat_nodes <- read_sf("C:/Users/habitat_nodes.shp")
nrow(habitat_nodes)
paisaje <- read_sf("C:/Users/paisaje.shp")
Para gráficarlo necesitamos ggplot2, favor de instalarlo si no lo tiene entre sus paquetes.
install.packages("ggplot2"), dependencies = TRUE)
install.packages("RColorBrewer"), dependencies = TRUE)
library(ggplot2)
library(RColorBrewer)
ggplot() +
geom_sf(data = paisaje, aes(color = "Study area"), fill = NA, color = "black") +
geom_sf(data = habitat_nodes, aes(color = "Parches"), fill = "forestgreen", linewidth = 0.5) +
scale_color_manual(name = "", values = "black")+
theme_minimal() +
theme(axis.title.x = element_blank(),
axis.title.y = element_blank())

En caso de necesitar abrir otro vector (e.g., .shp, .gpkg) necesitan usar la fución read_sf()
del paquete sf
, la función shapefile()
del paquete raster
, o la funcion vect()
del paquete terra
.
Para abrirlo solo necesitan colocar la dirección de su archivo, el nombre y la extensión, ejemplo:
vegetation_patches <- sf::read_sf("D:/Datos/vegetation_patches.shp")
vegetation_patches <- raster::shapefile("D:/Datos/vegetation_patches.shp")
vegetation_patches <- terra::vect("D:/Datos/vegetation_patches.shp")
Para definir el borde usaremos una distancia de 500 m a partir del límite de los parches (Haddad et al. 2015).

2.2 Funcion
MK_Fragmentation(
nodes = NULL,
edge_distance = 500,
min_node_area = 100,
landscape_area = NULL,
area_unit = "ha",
perimeter_unit = "km",
plot = FALSE,
write = NULL
)
Los argumento de la función que usaremos son:
- nodes = objeto con los parches,
- edge_distance = profundidad del efecto de borde.
- min_node_area = Área mínima del nodo utilizada para calcular el número de nodos con un área menor a la proporcionada. Por defecto igual a 100 km² (Haddad et al. 2015).
- landscape_area = Área total del paisaje de estudio (opcional). Si se deja como NULL, se utilizará el área total de los nodos. La unidad de área debe ser igual a la seleccionada en el párametro area_unit.
- area_unit = Puedes establecer una unidad de área (por ejemplo, “km2”, “cm2”, “m2”, “ha”; ver unit_convert). Por defecto es kilómetros cuadrados “km2”.
- perimeter_unit = Puedes establecer una unidad de perímetro (por ejemplo, “km”, “cm”, “m”, “ha”; ver unit_convert). Por defecto es kilómetros “km”.
- plot = Genera histogramas básicos y un mapa de área núcleo - borde.
- write = Guarda la tabla (estadísticas del paisaje), el objeto sf (estadísticas de parches/nodos) y las gráficas. Es necesario especificar la ruta y el prefijo. Por ejemplo, para guardar en la ruta “C:/Folder” con el prefijo “Fragmentation”: “C:/Folder/Fragmentation”
2.3 Ejercicio 1
Estimamos el área del paisaje de estudio.
area_paisaje <- st_area(paisaje)
area_paisaje <- unit_convert(area_paisaje, "m2", "ha")
Aplicamos la función.
Fragmentacion <- MK_Fragmentation(nodes = habitat_nodes,
edge_distance = 500,
min_node_area = 100,
landscape_area = area_paisaje,
area_unit = "ha",
perimeter_unit = "km",
plot = TRUE)
2.3.1 Estadisticos a nivel de parche
El primer resultado “Patch statistics shapefile” es un shapefile con estadísticos de fragmentación a nivel de parche.
Fragmentacion$`Patch statistics shapefile`
#> Simple feature collection with 404 features and 9 fields
#> Geometry type: POLYGON
#> Dimension: XY
#> Bounding box: xmin: -108954 ymin: 2025032 xmax: 202330.2 ymax: 2198936
#> Projected CRS: NAD_1927_Albers
#> First 10 features:
#> Id Area CA CAPercent Perimeter EdgePercent
#> 1 1 85.8368 0.000 0.0000 5.989 100.0000
#> 2 2 220.2168 0.000 0.0000 11.346 100.0000
#> 3 3 11019.9668 5337.795 48.4375 184.969 51.5625
#> 4 4 121.0018 0.000 0.0000 6.974 100.0000
#> 5 5 184.7226 0.000 0.0000 14.452 100.0000
#> 6 6 26.3052 0.000 0.0000 4.685 100.0000
#> 7 7 43.4931 0.000 0.0000 6.066 100.0000
#> 8 8 57.5414 0.000 0.0000 8.119 100.0000
#> 9 9 203.4670 0.000 0.0000 14.309 100.0000
#> 10 10 29440.4346 12326.275 41.8685 444.203 58.1315
#> PARA ShapeIndex FRAC geometry
#> 1 14.3324 0.1824 0.8040 POLYGON ((54911.05 2035815,...
#> 2 19.4092 0.2157 0.9005 POLYGON ((44591.28 2042209,...
#> 3 59.5774 0.4971 1.1217 POLYGON ((46491.11 2042467,...
#> 4 17.3504 0.1788 0.8100 POLYGON ((54944.49 2048163,...
#> 5 12.7818 0.3000 1.0235 POLYGON ((80094.28 2064140,...
#> 6 5.6148 0.2577 0.9446 POLYGON ((69205.24 2066394,...
#> 7 7.1700 0.2595 0.9557 POLYGON ((68554.2 2066632, ...
#> 8 7.0873 0.3019 1.0335 POLYGON ((69995.53 2066880,...
#> 9 14.2195 0.2830 1.0012 POLYGON ((79368.68 2067324,...
#> 10 66.2770 0.7303 1.1849 POLYGON ((23378.32 2067554,...
Son espacialmente explicitos y podemos visualizarlos con librerias como ggplot2
- % de área núcleo:
ggplot() +
geom_sf(data = paisaje, aes(color = "Study area"), fill = NA, color = "black") +
geom_sf(data = Fragmentacion$`Patch statistics shapefile`, aes(fill = CAPercent), color = "black", size = 0.1) +
scale_fill_distiller(
palette = "RdYlGn",
direction = 1,
name = "% Área Núcleo"
) +
theme_minimal() +
labs(
title = "Fragmentación a nivel de parche",
fill = "% Área Núcleo"
) +
theme(
legend.position = "right",
plot.title = element_text(hjust = 0.5)
)

- % de borde
ggplot() +
geom_sf(data = paisaje, aes(color = "Study area"), fill = NA, color = "black") +
geom_sf(data = Fragmentacion$`Patch statistics shapefile`, aes(fill = EdgePercent), color = "black", size = 0.1) +
scale_fill_distiller(
palette = "RdYlGn",
direction = -1,
name = "% Borde"
) +
theme_minimal() +
labs(
title = "Fragmentación a nivel de parche",
fill = "% Borde"
) +
theme(
legend.position = "right",
plot.title = element_text(hjust = 0.5)
)

- Perimeter
ggplot() +
geom_sf(data = paisaje, aes(color = "Study area"), fill = NA, color = "black") +
geom_sf(data = Fragmentacion$`Patch statistics shapefile`, aes(fill = Perimeter), color = "black", size = 0.1) +
scale_fill_distiller(
palette = "RdYlGn",
direction = -1,
name = "Perímetro"
) +
theme_minimal() +
labs(
title = "Fragmentación a nivel de parche",
fill = "Perímetro"
) +
theme(
legend.position = "right",
plot.title = element_text(hjust = 0.5)
)

- Perimeter-Area Ratio
ggplot() +
geom_sf(data = paisaje, aes(color = "Study area"), fill = NA, color = "black") +
geom_sf(data = Fragmentacion$`Patch statistics shapefile`, aes(fill = PARA), color = "black", size = 0.1) +
scale_fill_distiller(
palette = "RdYlGn",
direction = -1,
name = "PARA"
) +
theme_minimal() +
labs(
title = "Fragmentación a nivel de parche",
fill = "PARA"
) +
theme(
legend.position = "right",
plot.title = element_text(hjust = 0.5)
)

- Shape Index
ggplot() +
geom_sf(data = paisaje, aes(color = "Study area"), fill = NA, color = "black") +
geom_sf(data = Fragmentacion$`Patch statistics shapefile`, aes(fill = ShapeIndex), color = "black", size = 0.1) +
scale_fill_distiller(
palette = "PiYG",
direction = -1,
name = "Shape Index"
) +
theme_minimal() +
labs(
title = "Fragmentación a nivel de parche",
fill = "Shape Index"
) +
theme(
legend.position = "right",
plot.title = element_text(hjust = 0.5)
)

- Fractal Dimension Index
ggplot() +
geom_sf(data = paisaje, aes(color = "Study area"), fill = NA, color = "black") +
geom_sf(data = Fragmentacion$`Patch statistics shapefile`, aes(fill = FRAC), color = "black", size = 0.1) +
scale_fill_distiller(
palette = "PiYG",
direction = -1,
name = "FRAC"
) +
theme_minimal() +
labs(
title = "Fragmentación a nivel de parche",
fill = "FRAC"
) +
theme(
legend.position = "right",
plot.title = element_text(hjust = 0.5)
)

2.3.2 Estadísticos a nivel de paisaje
Los resultados se presentan a manera de una lista, el primer resultado se llama “Summary landscape metrics (Viewer Panel)” y tiene estadisticos de fragmentación a nivel de paisaje.
class(Fragmentacion)
#> [1] "list"
Fragmentacion$`Summary landscape metrics (Viewer Panel)`
Metric | Value |
---|---|
Patch area (ha) | 1273573.9249 |
Number of patches | 404.0000 |
Size (mean) | 3152.4107 |
Patches < minimum patch area | 40.0000 |
Patches < minimum patch area (%) | 0.1992 |
Total edge | 17920.4740 |
Edge density | 0.0141 |
Patch density | 0.0146 |
Total Core Area (ha) | 631595.3522 |
Cority | 0.6064 |
Shape Index (mean) | 0.2207 |
FRAC (mean) | 0.8536 |
MESH (ha) | 66572.5742 |
La densidad de malla efectiva (MESH) es una medida del grado en que el movimiento entre diferentes partes del paisaje se ve interrumpido por una Fragmentación. El índice MESH se ha popularizado debido a su facilidad de interpretación. Si conocemos el área de nuestro paisaje, entonces podemos estimar el porcentage de fragmentación:
mesh <- as.data.frame(Fragmentacion[[1]])
mesh <- mesh[13,2]
mesh_porcentage <- (area_paisaje - mesh) * 100 / area_paisaje
mesh_porcentage
#> [1] 97.58915
2.4 Ejercicio 2
Hagamos un loop en donde exploramos distintas distancias de profundidad del efecto borde.
#Loop edge distance
library(purrr)
Fragmentacion.2 <- map_dfr(seq(100, 1000, 100), function(x){
x.1 <- MK_Fragmentation(nodes = habitat_nodes,
edge_distance = x, plot = FALSE)[[2]]
CA <- mean(x.1$CAPercent)
Edge <- mean(x.1$EdgePercent)
x.2 <- rbind(data.frame('Edge distance' = x, Type = "Core Area", Percentage = CA),
data.frame('Edge distance' = x, Type = "Edge", Percentage = Edge))
return(x.2)
}, .progress = TRUE)
Fragmentacion.2
#> Edge.distance Type Percentage
#> 1 100 Core Area 65.761207
#> 2 100 Edge 34.238793
#> 3 200 Core Area 41.980654
#> 4 200 Edge 58.019346
#> 5 300 Core Area 26.853211
#> 6 300 Edge 73.146789
#> 7 400 Core Area 18.110913
#> 8 400 Edge 81.889087
#> 9 500 Core Area 12.863545
#> 10 500 Edge 87.136455
#> 11 600 Core Area 9.554117
#> 12 600 Edge 90.445883
#> 13 700 Core Area 7.347448
#> 14 700 Edge 92.652552
#> 15 800 Core Area 5.767296
#> 16 800 Edge 94.232704
#> 17 900 Core Area 4.564680
#> 18 900 Edge 95.435320
#> 19 1000 Core Area 3.633780
#> 20 1000 Edge 96.366220
El porcentaje promedio de área núcleo (ausencia de efecto de borde) para todos los parches disminuye en más del 70% cuando se considera un efecto de borde con una penetración de 1 km.
Distancia de profundidad | %Área Núcleo |
---|---|
100 | 65.76% |
500 | 12.86% |
1000 | 3.63% |
Podemos gráficar el promedio del porcentaje de área npucleo de los parches y el porcentaje del borde de los parches (%área núcleo + % de borde = 100%).
library(ggplot2)
ggplot(Fragmentacion.2, aes(x=Edge.distance, y=Percentage, group=Type)) +
geom_line(aes(color=Type))+
geom_point(aes(color=Type))+ ylim(0,100)+
scale_x_continuous("Distancia", labels = as.character(Fragmentacion.2$Edge.distance), breaks = Fragmentacion.2$Edge.distance)+
scale_color_brewer(palette="Dark2")+
theme_classic()

2.5 Ejercicio 3
Ahora probemos los alcances de la función estimando el índice MESH sobre un grid.
Grid de 40 km2
Grid_test <- make_grid(x = paisaje, hexagonal = FALSE,
cell_area = unit_convert(40, "km2", "m2"),
clip = TRUE)
plot(Grid_test)

Estimar MESH usando un loop sencillo tipo for()
#Variable dummy
Grid_test$MESH <- 0
for(i in 1:nrow(Grid_test)){
cat(paste0(i, " de ", nrow(Grid_test), "\r"))
grid.i <- Grid_test[i,]
nodes.i <- suppressWarnings(st_intersection(habitat_nodes, grid.i))
if(nrow(nodes.i) > 0){
area_paisaje.i <- st_area(grid.i)
area_paisaje.i <- unit_convert(area_paisaje.i, "m2", "ha")
Fragmentacion.i <- MK_Fragmentation(nodes = nodes.i,
edge_distance = 500,
min_node_area = 100,
landscape_area = ,
area_unit = "ha",
perimeter_unit = "km",
plot = FALSE)
mesh <- as.data.frame(Fragmentacion.i[[1]])
mesh <- mesh[13,2]
mesh_porcentage <- (area_paisaje.i - mesh)*100/area_paisaje.i
Grid_test$MESH[i] <- mesh_porcentage
} else {
Grid_test$MESH[i] <- 100
}
}
Lo podemos visualizar con ggplot2
ggplot() +
geom_sf(data = paisaje, aes(color = "Study area"), fill = NA, color = "black") +
geom_sf(data = Grid_test, aes(fill = MESH), color = "black", size = 0.1) +
scale_fill_distiller(
palette = "RdYlGn",
direction = -1,
name = "% Fragmentación"
) +
theme_minimal() +
labs(
title = "GRID fragmentación (MESH)",
fill = "% Fragmentación"
) +
theme(
legend.position = "right",
plot.title = element_text(hjust = 0.5)
)
