Instanciar polígonos espaciales sin usar un shapefile en R

22

Entonces, la forma habitual de leer un archivo de formas en R es a través del paquete maptools, de esta manera:

sfdata <- readShapeSpatial("/path/to/my/shapefile.shp", proj4string=CRS("+proj=longlat"))

Sin embargo, tengo un caso de uso por el cual no tengo un shapefile.shp sino que tengo una serie de coordenadas poligonales

16.484375 59.736328125,17.4951171875 55.1220703125,24.74609375 55.0341796875,22.5927734375 61.142578125,16.484375 59.736328125

y su proyección correspondiente

coord. ref. : +proj=longlat +datum=WGS84 +no_defs +ellps=WGS84 +towgs84=0,0,0 

¿Cómo "instanciar" sfdata (que será un "objeto de polígono") directamente de estos datos? (sin ir en una forma indirecta de crear un archivo de forma con estos datos y luego leer desde el archivo de forma recién creado)

Calvin Cheng
fuente

Respuestas:

35

Primero obtenga las coordenadas en una matriz de 2 columnas:

> xym
         [,1]     [,2]
[1,] 16.48438 59.73633
[2,] 17.49512 55.12207
[3,] 24.74609 55.03418
[4,] 22.59277 61.14258
[5,] 16.48438 59.73633

Luego crea un Polígono, envuélvelo en un objeto Polígonos, luego envuélvelo en un objeto SpatialPolygons:

> library(sp)
> p = Polygon(xym)
> ps = Polygons(list(p),1)
> sps = SpatialPolygons(list(ps))

La razón de este nivel de complejidad es que un Polígono es un anillo simple, un objeto Polígonos puede ser varios anillos con un ID (aquí configurado como 1) (por lo que es como una característica única en un SIG) y un SpatialPolygons puede tener un CRS . Ooh, probablemente debería configurarlo:

> proj4string(sps) = CRS("+proj=longlat +datum=WGS84 +no_defs +ellps=WGS84 +towgs84=0,0,0")

Si desea convertirlo en un SpatialPolygonsDataFrame (que es lo que viene de readShapeSpatial cuando el shapefile es polígonos), haga lo siguiente:

> data = data.frame(f=99.9)
> spdf = SpatialPolygonsDataFrame(sps,data)
> spdf

dando esto:

> summary(spdf)
Object of class SpatialPolygonsDataFrame
Coordinates:
       min      max
x 16.48438 24.74609
y 55.03418 61.14258
Is projected: FALSE 
proj4string :
[+proj=longlat +datum=WGS84 +no_defs +ellps=WGS84 +towgs84=0,0,0]
Data attributes:
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
   99.9    99.9    99.9    99.9    99.9    99.9 
Hombre espacial
fuente
+1 Muy bonita, clara exposición. ¡Es genial ver el código dividido por explicaciones en lugar de ser ofrecido como un bloque monolítico!
whuber
Excelente ... ¡genial ver cómo se juntan estos objetos! Necesito ver más de las páginas de ayuda de R escritas claramente así.
Simbamangu
Es algo que tengo que volver a enseñar cada vez que quiero hacerlo, ¡así que aprovecho cualquier oportunidad para enseñar a otras personas!
Spacedman
1
excelente ... ¿cómo haría para agregar múltiples polígonos de id (f) únicos al marco de datos?
mga
2
Para que esta respuesta tenga una validez más general, ¿podría mostrar cómo hacerlo en caso de múltiples polígonos? Esto es un poco complicado.
Tomás
2

Para completar la excelente respuesta de Spacedman para el caso donde sus datos contendrían múltiples polígonos, aquí hay un código que usa dplyr:

library(dplyr)
library(ggplot2)
library(sp)
## use data from ggplot2:::geom_polygon example:
positions <- data.frame(id = rep(factor(c("1.1", "2.1", "1.2", "2.2", "1.3", "2.3")), each = 4),
                    x = c(2, 1, 1.1, 2.2, 1, 0, 0.3, 1.1, 2.2, 1.1, 1.2, 2.5, 1.1, 0.3,
                          0.5, 1.2, 2.5, 1.2, 1.3, 2.7, 1.2, 0.5, 0.6, 1.3),
                    y = c(-0.5, 0, 1, 0.5, 0, 0.5, 1.5, 1, 0.5, 1, 2.1, 1.7, 1, 1.5,
                          2.2, 2.1, 1.7, 2.1, 3.2, 2.8, 2.1, 2.2, 3.3, 3.2)) %>% as.tbl


df_to_spp <- positions %>%
  group_by(id) %>%
  do(poly=select(., x, y) %>%Polygon()) %>%
  rowwise() %>%
  do(polys=Polygons(list(.$poly),.$id)) %>%
  {SpatialPolygons(.$polys)}

## plot it
plot(df_to_spp)

Solo por diversión, puede comparar con la trama obtenida con el ggplot2uso del marco de datos inicial:

ggplot(positions) + 
  geom_polygon(aes(x=x, y=y, group=id), colour="black", fill=NA)

Tenga en cuenta que el código anterior asume que solo tiene un polyogn por id. Si algunos identificadores tienen polígonos disjuntos, supongo que uno debería agregar otra columna en el conjunto de datos, primero group_byla sub-identificación, luego usegroup_by(upper-id) lugar derowwise

Mismo código usando la purrr::mapfunción:

df_to_spp <- positions %>%
  nest(-id) %>%
  mutate(Poly=purrr::map(data, ~select(., x, y)  %>% Polygon()),
         polys=map2(Poly, id, ~Polygons(list(.x),.y))) %>%
  {SpatialPolygons(.$polys)}
Matifou
fuente