8  Operaciones geométricas

8.1 Introducción

Como ya comentamos en el anterior bloque, la librería sf(Pebesma, 2018, 2022) es una de las más utilizadas para el manejo, análisis y visualización de datos geoespaciales. Proporciona funciones para manipular geometrías espaciales, realizar operaciones geométricas y trabajar con sistemas de coordenadas, entre otras capacidades. En este apartado, veremos algunas de las funciones más comunes relacionadas con operaciones geométricas.

En esta práctica usaremos la librería mapSpain (Hernangómez, 2025) para obtener los límites de España por provincias y comunidades autónomas. Para su correcto funcionamiento, el autor recomienda instalar el paquete con dependencias:

install.packages("mapSpain", dependencies = TRUE)

Cargamos librerías:

library(tidyverse)
library(sf)
library(mapSpain)

Cargamos cartografía:

spain_ccaa <- mapSpain::esp_get_ccaa()
spain_prov <- mapSpain::esp_get_prov(moveCAN = F)
spain_mun <- mapSpain::esp_get_munic()
box_can <- mapSpain::esp_get_can_box()

8.1.1 st_geometry()

Esta función extrae o establece la geometría de un objeto sf o sfc (ya lo vimos en la práctica anterior).

class(spain_ccaa)
[1] "sf"         "data.frame"
head(spain_ccaa,10)
geometria <- st_geometry(spain_ccaa)
class(geometria)
[1] "sfc_MULTIPOLYGON" "sfc"             
head(geometria)
Geometry set for 6 features 
Geometry type: MULTIPOLYGON
Dimension:     XY
Bounding box:  xmin: -13.21924 ymin: 34.70209 xmax: 4.320511 ymax: 43.65841
Geodetic CRS:  ETRS89
First 5 geometries:
MULTIPOLYGON (((-4.275964 38.34999, -4.287161 3...
MULTIPOLYGON (((-0.74093 42.91957, -0.754975 42...
MULTIPOLYGON (((-4.536122 43.40053, -4.54544 43...
MULTIPOLYGON (((4.095952 40.08266, 4.091628 40....
MULTIPOLYGON (((-8.504825 36.09995, -8.487927 3...
ggplot() +
  geom_sf(data = spain_ccaa) +
  geom_sf(data = box_can, color = "grey50")

8.1.2 st_area()

Esta función calcula el área de cada elemento de un objeto sf o sfc.

gva <- spain_ccaa %>% filter(ine.ccaa.name=="Comunitat Valenciana")
ggplot() + geom_sf(data=gva)

area_gva <- sf::st_area(gva)
area_gva
23239151639 [m^2]
class(area_gva)
[1] "units"
units::set_units(area_gva, km^2)
23239.15 [km^2]
area_gva_num <- as.numeric(area_gva)
area_gva_num
[1] 23239151639
class(area_gva_num)
[1] "numeric"

8.1.3 st_length()

Esta función calcula la longitud de cada elemento de un objeto sf o sfc.

rios <- mapSpain::esp_get_rivers()
as.character(unique(sf::st_geometry_type(rios)))
[1] "LINESTRING"
head(rios,10)
ggplot() +
  geom_sf(data = spain_prov) +
  geom_sf(data = rios, color="blue")

turia <- rios %>% filter(rotulo == "Río Turia")
ggplot() +
  geom_sf(data=turia)

sf::st_length(turia)
Units: [m]
[1] 84185.014  9715.642
units::set_units(sf::st_length(turia),km)
Units: [km]
[1] 84.185014  9.715642
geom_turia1 <- st_geometry(turia[1,])
class(geom_turia1)
[1] "sfc_LINESTRING" "sfc"           
nrow(st_coordinates(geom_turia1))
[1] 83
p1 <- st_coordinates(geom_turia1)[1,]
class(p1)
[1] "numeric"
p1 <- st_point(p1)
class(p1)
[1] "XYZ"   "POINT" "sfg"  
p1 <- st_sfc(p1, crs=st_crs(turia))
class(p1)
[1] "sfc_POINT" "sfc"      
p2 <- st_sfc(st_point(st_coordinates(geom_turia1)[83,]), crs=st_crs(turia))
ggplot() +
  geom_sf(data = turia) +
  geom_sf(data = p1, size=2, color="blue") +
  geom_sf(data = p2, size=2, color="red")

8.1.4 st_distance()

Esta función calcula la distancia Euclídea entre pares de geometrías de dos objetos sf o sfc.

sf::st_distance(p1,p2)
st_as_s2(): dropping Z and/or M coordinate
st_as_s2(): dropping Z and/or M coordinate
Units: [m]
         [,1]
[1,] 50802.45
sf::st_length(turia[1,])
84185.01 [m]
Ejercicio
  1. Crea una línea l1 que vaya de p1 a p2.
  2. Comprueba que la longitud de l1 es igual a la distancia entre p1 y p2.

8.1.5 st_buffer()

Esta función crea un buffer, es decir, un área alrededor de cada geometría de un objeto sf o sfc.

ribera_turia <- sf::st_buffer(turia, dist = 5000)
class(ribera_turia)
[1] "sf"         "data.frame"
ggplot() +
  geom_sf(data = turia, color="blue") +
  geom_sf(data = ribera_turia, alpha=0.5, color="transparent", fill="#9BEAB9")

buffer_gva <- st_buffer(gva, 5000)

ggplot() +
  geom_sf(data = spain_ccaa) +
  geom_sf(data = box_can, color = "grey50") +
  geom_sf(data = buffer_gva, alpha=0.5, color="transparent", fill="#9BEAB9")

8.1.6 st_boundary()

Esta función se utiliza para obtener el límite de cualquier tipo de geometría espacial, entendiendo por límite la parte de la geometría que define su contorno externo.

Para un polígono, st_boundary() devuelve las líneas (o anillos) que forman el contorno externo del polígono, excluyendo su interior. Para una línea, devuelve los puntos de inicio y fin de la línea.

buffer_gva <- st_buffer(st_boundary(gva), 5000)
ggplot() +
  geom_sf(data = spain_ccaa) +
  geom_sf(data = box_can, color = "grey50") +
  geom_sf(data = buffer_gva, alpha=0.5, color="transparent", fill="#9BEAB9")

8.1.7 st_centroid()

Esta función calcula el centroide de cada geometría en un objeto sf o sfc. El centroide es el punto central de una geometría, que se calcula como el promedio de todas las coordenadas de los puntos que forman la geometría. En términos más simples, es el punto que se consideraría el centro geográfico de una forma.

Atención

A veces, el centroide (centro geográfico) queda fuera de los límites de sus objetos principales (imagina un polígono con forma de donut). En tales casos, se puede utilizar la función st_point_on_surface(), que garantiza que el punto esté dentro del objeto principal.

spain <- spain_ccaa %>% filter(!codauto %in% c("04","05","18","19"))
ggplot() +
  geom_sf(data = spain)

spain2 <- spain %>%
  group_by() %>% 
  summarise()
ggplot() + 
  geom_sf(data = spain2)

madrid <- spain %>% 
  filter(codauto == "13")
ggplot() +
  geom_sf(data = spain2) +
  geom_sf(data = madrid, fill = "blue", alpha = 0.5)

centro_madrid <- st_centroid(madrid$geometry)
ggplot() +
  geom_sf(data = spain2) +
  geom_sf(data = madrid, fill = "blue", alpha = 0.5) +
  geom_sf(data = centro_madrid, color = "red")

buffer <- st_buffer(centro_madrid, dist = 10^6) # buffer 1000 km desde centro madrid
class(buffer)
[1] "sfc_POLYGON" "sfc"        
ggplot() +
  geom_sf(data = buffer, fill = "orange", alpha = 0.2) +
  geom_sf(data = spain2) +
  geom_sf(data = madrid, fill = "blue", alpha = 0.5) +
  geom_sf(data = centro_madrid, color = "red")

8.1.8 st_sample()

La función st_sample() se usa para generar puntos aleatorios dentro de las geometrías de un objeto sf o sfc. Esta función permite especificar el número de puntos a generar y, opcionalmente, el tipo de distribución de los puntos (por ejemplo, uniforme) dentro de la geometría.

st_sample() es particularmente útil en varios contextos, como:

  • Crear muestras aleatorias para análisis espaciales, como estimar la densidad de características dentro de una región.
  • Generar puntos para simulaciones espaciales.
  • Visualización, para representar la extensión de una geometría mediante puntos aleatorios cuando el detalle completo de la geometría no es necesario.
set.seed(123)
puntos <- st_sample(buffer, size = 1000)
class(puntos)
[1] "sfc_POINT" "sfc"      
ggplot() +
  geom_sf(data = buffer, fill = "orange", alpha = 0.2) +
  geom_sf(data = spain2) +
  geom_sf(data = puntos, color = "green")

8.1.9 st_intersection()

Esta función calcula la geometría resultante de la intersección entre dos o más geometrías. Si dos polígonos se superponen, por ejemplo, st_intersection() devuelve un nuevo polígono que representa la zona de superposición. Si no hay intersección, el resultado debe ser una geometría vacía. Esta función es útil cuando el interés está en la forma o el área de la intersección.

puntos_spain <- st_intersection(puntos,spain2)
class(puntos_spain)
[1] "sfc_POINT" "sfc"      
ggplot() +
  geom_sf(data = buffer, fill = "orange", alpha = 0.2) +
  geom_sf(data = spain2) +
  geom_sf(data = puntos, color = "green") +
  geom_sf(data = puntos_spain, color = "red")

ggplot() +
  geom_sf(data = spain2) +
  geom_sf(data = puntos_spain, color = "red")

8.1.10 st_difference()

Función opuesta a st_intersection(). Encuentra la diferencia entre pares de geometrías de dos objetos sf o sfc.

puntos_out <- st_difference(puntos, spain2)
class(puntos_out)
[1] "sfc_POINT" "sfc"      
ggplot() +
  geom_sf(data = buffer, fill = "orange", alpha = 0.2) +
  geom_sf(data = spain2) +
  geom_sf(data = puntos, color = "green") +
  geom_sf(data = puntos_out, color = "blue")

Ejercicio
  1. ¿Cuántos puntos “han caído” dentro de la Península Ibérica?
  2. ¿Y en Galicia?
  3. ¿Y dentro de la provincia de Valencia?
  4. ¿Y a una distancia inferior o igual a 15 km de las playas de Asturias?

8.1.11 st_intersects()

Esta función se utiliza para evaluar si dos geometrías se intersectan, es decir, si comparten algún espacio en común. El resultado es un objeto lógico (verdadero/falso) o una matriz/lista que indica qué geometrías de los dos conjuntos de entrada se intersectan entre sí. Es útil para pruebas lógicas, como filtrar geometrías basadas en su intersección con otras.

ebro <- rios %>% filter(NOM_RIO == "Rio Ebro")
ggplot() +
  geom_sf(data = spain_ccaa) +
  geom_sf(data = box_can, color = "grey50") +
  geom_sf(data = ebro, color="blue")

ccaa_ebro <- st_intersects(ebro,spain_ccaa)
class(ccaa_ebro)
[1] "sgbp" "list"
ccaa_ebro <- unique(unlist(ccaa_ebro))

ggplot() +
  geom_sf(data = spain_ccaa) +
  geom_sf(data = mapSpain::esp_get_can_box(style = "box"), color="grey40", linewidth=0.5) +
  geom_sf(data = spain_ccaa[ccaa_ebro,], aes(fill=nuts2.name), color="white") +
  geom_sf(data = ebro, color="blue") +
  theme_minimal() +
  theme(legend.position = "bottom",
        legend.direction = "horizontal",
        legend.title = element_blank(),
        axis.title = element_blank(),
        panel.background = element_rect(fill="lightblue", color = "transparent"))

8.2 Centros educativos de la Comunitat Valenciana

Probemos ahora con datos reales… En el catálogo de descargas de la Infraestructura de Datos Espaciales Valenciana (IDEV) se ofrecen datos geográficos agrupados por diferentes temáticas. Dentro del bloque Educación existe la posibilidad de obtener/descargar diversa información espacial, como los Grados y Másteres universitarios que se imparten, mapas escolares de Parques Naturales o la ubicación de los centros de exámenes ordinarios de la Junta Qualificadora de Coneixements de Valencià (JQCV). En esta ocasión vamos a trabajar con la ubicación de los centros educativos de la GVA, disponibles para su descarga directa de aquí.

Importamos los datos:

centres_edu_gva <- sf::st_read("data/centres_educatius.gpkg", quiet=T)
head(centres_edu_gva,10)

Y calculamos, por ejemplo, las distancias entre cada para de puntos (centros educativos):

dist_edu <- sf::st_distance(centres_edu_gva)
class(dist_edu)
[1] "units"
dist_edu[1:6,1:6]
Units: [m]
           1          2        3         4         5        6
1     0.0000   397.3371 24598.17 35169.468 34302.365 31359.10
2   397.3371     0.0000 24838.28 34788.092 33911.817 31755.57
3 24598.1659 24838.2802     0.00 56780.701 54982.341 24166.79
4 35169.4675 34788.0919 56780.70     0.000  3536.969 66141.12
5 34302.3649 33911.8166 54982.34  3536.969     0.000 65548.32
6 31359.1018 31755.5715 24166.79 66141.119 65548.324     0.00
Ejercicio
  1. ¿Qué centros educativos están fuera de los límites de la Comunitat Valenciana?
  2. Sustituye las coordenadas por las correctas (las puedes obtener, por ejemplo, de Google Maps)
  3. ¿Has detectado algún otro error en el conjunto de datos original? De ser así, ¿qué propones hacer?
  4. Guarda el objeto sf resultante como “centres_educatius_bueno.gpkg”.

8.3 Resumen

En este apartado hemos visto las siguientes funciones del paquete sf:

  • st_area
  • st_length
  • st_distance
  • st_coordinates
  • st_buffer
  • st_boundary
  • st_centroid
  • st_sample
  • st_intersection
  • st_difference
  • st_intersects
  • st_bbox
  • st_read
  • st_write
Ejercicio

¿Para qué sirve cada una de estas funciones?