Instanciation d'un polygone spatial sans utiliser de fichier de formes dans R

22

Ainsi, la façon habituelle de lire un fichier de formes dans R est via le package maptools, comme ceci:

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

Cependant, j'ai un cas d'utilisation où je n'ai pas de shapefile.shp mais à la place j'ai une série de coordonnées de polygone

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

et sa projection correspondante

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

Comment «instancier» des sfdata (qui seront un «objet polygone») directement à partir de ces données? (sans aller de manière détournée pour créer un fichier de formes avec ces données, puis lire à partir du fichier de formes nouvellement créé)

Calvin Cheng
la source

Réponses:

35

Obtenez d'abord les coordonnées dans une matrice à 2 colonnes:

> 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

Créez ensuite un polygone, enveloppez-le dans un objet Polygons, puis enveloppez-le dans un objet SpatialPolygons:

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

La raison de ce niveau de complexité est qu'un polygone est un simple anneau, un objet Polygones peut être composé de plusieurs anneaux avec un ID (défini ici à 1) (il en va de même pour une seule entité dans un SIG) et un SpatialPolygons peut avoir un CRS . Ooh, je devrais probablement le régler:

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

Si vous voulez le transformer en un SpatialPolygonsDataFrame (qui est ce qui vient de notre readShapeSpatial lorsque le fichier de formes est des polygones) alors faites:

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

donnant ceci:

> 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 
Spacedman
la source
+1 Très belle exposition claire. C'est super de voir le code décomposé par des explications plutôt que d'être proposé comme un bloc monolithique!
whuber
Excellent ... super de voir comment ces objets sont assemblés! Besoin de voir plus de pages d'aide R écrites clairement comme ceci.
Simbamangu
C'est quelque chose que je dois me réapprendre chaque fois que je veux le faire, alors je profite de l'occasion pour enseigner aux autres!
Spacedman
1
excellent ... comment pourrais-je ajouter plusieurs polygones id (f) uniques à la trame de données?
mga
2
Pour que cette réponse ait une validité plus générale, pourriez-vous montrer comment le faire en cas de polygones multiples? C'est un peu délicat.
Tomas
2

Pour compléter l'excellente réponse de Spacedman dans le cas où vos données contiendraient plusieurs polygones, voici un code utilisant 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)

Juste pour le plaisir, vous pouvez comparer avec l'intrigue obtenue en ggplot2utilisant la trame de données initiale:

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

Notez que le code ci-dessus suppose que vous n'avez qu'un seul polyogn par identifiant. Si certains identifiants avaient des polygones disjoints, je suppose que l'on devrait ajouter une autre colonne dans l'ensemble de données, d'abord group_byle sous-identifiant, puis utiliser à la group_by(upper-id)place derowwise

Même code en utilisant la purrr::mapfonction:

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
la source