Extraction de zones d'intersection dans R

19

J'ai deux polygones. L'un contient des champs (X, Y, Z) et l'autre contient des types de sols (A, B, C, D). Je veux savoir quelle zone de chaque champ contient quel type de sol. J'ai essayé ce qui suit:

entrez la description de l'image ici

library(rgdal)
library(rgeos)
Field<-readOGR("./","Field")
Soil<-readOGR("./","Soil")
Results<-gIntersects(Soil,Field,byid=TRUE)
rownames(Results)<-Field@data$FieldName
colnames(Results)<-Soil@data$SoilType

> Results
      A     B     C     D
Z  TRUE FALSE FALSE FALSE
Y FALSE  TRUE  TRUE FALSE
X  TRUE  TRUE  TRUE  TRUE

et obtenu de bons résultats en me disant quel champ contient quel type de sol. Cependant, comment puis-je obtenir la zone à la place?

user2386786
la source
1
Notez que st_intersection ne fonctionnera pas si vos points sont la latitude et la longitude. Vous n'avez pas précisé que vous aviez des coordonnées géographiques, bien que cela soit indiqué puisque vous parlez de types de sols.
Fourier

Réponses:

24

Cette méthode utilise la intersect()fonction du rasterpackage. Les exemples de données que j'ai utilisés ne sont pas idéaux (d'une part, ils sont en coordonnées non projetées), mais je pense que cela donne une idée.

library(sp)
library(raster)
library(rgdal)
library(rgeos)
library(maptools)

# Example data from raster package
p1 <- shapefile(system.file("external/lux.shp", package="raster"))
# Remove attribute data
p1 <- as(p1, 'SpatialPolygons')
# Add in some fake soil type data
soil <- SpatialPolygonsDataFrame(p1, data.frame(soil=LETTERS[1:12]), match.ID=F)

# Field polygons
p2 <- union(as(extent(6, 6.4, 49.75, 50), 'SpatialPolygons'),
             as(extent(5.8, 6.2, 49.5, 49.7), 'SpatialPolygons'))
field <- SpatialPolygonsDataFrame(p2, data.frame(field=c('x','y')), match.ID=F)
projection(field) <- projection(soil)

# intersect from raster package
pi <- intersect(soil, field)
plot(soil, axes=T); plot(field, add=T); plot(pi, add=T, col='red')

# Extract areas from polygon objects then attach as attribute
pi$area <- area(pi) / 1000000

# For each field, get area per soil type
aggregate(area~field + soil, data=pi, FUN=sum)

Imgur

Résultats:

    field soil         area
1      x    A 2.457226e+01
2      x    B 2.095659e+02
3      x    C 5.714943e+00
4      y    C 5.311882e-03
5      x    D 7.620041e+01
6      x    E 3.101547e+01
7      x    F 1.019455e+02
8      x    H 7.106824e-03
9      y    H 2.973232e+00
10     y    I 1.752702e+02
11     y    J 1.886562e+02
12     y    K 1.538229e+02
13     x    L 1.321748e+02
14     y    L 1.182670e+01
Matt SM
la source
2
Pour clarifier: je préfère raster::intersectplus rgeos::gIntersectionparce que le premier joint les données d'attribut des deux SpatialPolgonsDataFrameobjets, tandis que le second semble supprimer les données d'attribut.
Matt SM
Merci pour les nombreux détails et la bonne réponse. Tu m'as beaucoup aidé!!!
user2386786
4
Si vous utilisez byid = TRUE dans "gIntersection", il retournera l'attribut IDS qui peut être utilisé avec la fusion pour associer les attributs. Les fonctions sont différentes et il convient de noter comment. La fonction "intersection" utilise les extensions qui se chevauchent tandis que "gIntersection" est l'intersection explicite des géométries vectorielles. L'approche d'intersection est une intersection carrée / rectangulaire et non une intersection des polygones réels. L'étendue peut être redéfinie à l'aide de l'étendue et de la bbox. Les deux approches présentent des avantages.
Jeffrey Evans
1
@JeffreyEvans Bon point re gIntersection; cependant, les ID d'entité en entrée ne sont pas directement fournis, ils sont concaténés et stockés dans l'ID d'entité de la sortie. Cela signifie les étapes supplémentaires consistant à analyser les ID, puis à joindre les attributs. Je souhaite raster::intersectinclure ces ID d'entrée comme attributs supplémentaires dans la sortie.
Matt SM
1
Merci de l'avoir signalé, j'ai complètement raté intersect_sp. Fait intéressant, il utilise gIntersects. Joli raccourci si vous voulez que les attributs soient joints.
Jeffrey Evans
23

Voici une autre approche utilisant le nouveau sfpackage, qui est destiné à remplacer sp. Tout est beaucoup plus propre et compatible avec les tuyaux:

library(sf)
library(tidyverse)

# example data from raster package
soil <- st_read(system.file("external/lux.shp", package="raster")) %>% 
  # add in some fake soil type data
  mutate(soil = LETTERS[c(1:6,1:6)]) %>% 
  select(soil)

# field polygons
field <- c("POLYGON((6 49.75,6 50,6.4 50,6.4 49.75,6 49.75))",
        "POLYGON((5.8 49.5,5.8 49.7,6.2 49.7,6.2 49.5,5.8 49.5))") %>% 
  st_as_sfc(crs = st_crs(soil)) %>% 
  st_sf(field = c('x','y'), geoms = ., stringsAsFactors = FALSE)

# intersect - note that sf is intelligent with attribute data!
pi <- st_intersection(soil, field)
plot(soil$geometry, axes = TRUE)
plot(field$geoms, add = TRUE)
plot(pi$geometry, add = TRUE, col = 'red')

# add in areas in m2
attArea <- pi %>% 
  mutate(area = st_area(.) %>% as.numeric())

# for each field, get area per soil type
attArea %>% 
  as_tibble() %>% 
  group_by(field, soil) %>% 
  summarize(area = sum(area))

entrez la description de l'image ici

   field  soil      area
   <chr> <chr>     <dbl>
1      x     A  24572264
2      x     B 209573036
3      x     C   5714943
4      x     D  76200409
5      x     E  31015469
6      x     F 234120314
7      y     B   2973232
8      y     C 175275520
9      y     D 188656204
10     y     E 153822938
11     y     F  11826698
Matt SM
la source