Convert SpatialPointsDataframe to SpatialPolygons in R

12,374

So here's another solution, conceptually similar to @JoshO'Brien's. This one accommodates sub-polygons (multiple groups for a given id) and creates an object of class SpatialPolygonsDataFrame, with included data section (e.g., the attributes table). This is fully exportable to an ESRI shapefile.

First, as an example, we create a SpatialPointsDataFrame with the same format as yours. The id column identifies Polygon ID and the group column identifies sub-polygons for a given polygon. In this example we have 3 polygons, two of which have 1 sub-Polygon, and the third which has 3 sub-Polygons. We also create a data frame data (the attributes table) which in this case associates polygon ID with box_id.

# this code just creates a sample SpatialPointsDataFrame 
x <- c(-10,-10,10,10,-10)
y <- c(-10,10,10,-10,-10)
df.1 <- data.frame(x,y,id=47, order=1:5,hole=F,piece=1,group=47.1,box_id=1)
coordinates(df.1)=c("x","y")
x <- c(+15+3*cos(2*pi/5*(0:5)))
y <- c(-15+3*sin(2*pi/5*(0:5)))
df.2 <- data.frame(x,y,id=48, order=1:6,hole=F,piece=1,group=48.1,box_id=2)
coordinates(df.2)=c("x","y")
x <- c(-15+2*cos(2*pi/8*(0:8)))
y <- c(+15+2*sin(2*pi/8*(0:8)))
df.3.1 <- data.frame(x,y,id=20, order=1:9,hole=F,piece=1,group=20.1,box_id=3)
coordinates(df.3.1)=c("x","y")
x <- c(0+2*cos(2*pi/8*(0:8)))
y <- c(+15+2*sin(2*pi/8*(0:8)))
df.3.2 <- data.frame(x,y,id=20, order=1:9,hole=F,piece=1,group=20.2,box_id=3)
coordinates(df.3.2)=c("x","y")
x <- c(+15+2*cos(2*pi/8*(0:8)))
y <- c(+15+2*sin(2*pi/8*(0:8)))
df.3.3 <- data.frame(x,y,id=20, order=1:9,hole=F,piece=1,group=20.3,box_id=3)
coordinates(df.3.3)=c("x","y")
df <- rbind(df.1,df.2,df.3.1,df.3.2,df.3.3)
df
#              coordinates id order  hole piece group box_id
# 1             (-10, -10) 47     1 FALSE     1  47.1      1
# 2              (-10, 10) 47     2 FALSE     1  47.1      1
# 3               (10, 10) 47     3 FALSE     1  47.1      1
# 4              (10, -10) 47     4 FALSE     1  47.1      1
# 5             (-10, -10) 47     5 FALSE     1  47.1      1
# 6              (18, -15) 48     1 FALSE     1  48.1      2
# 7  (15.92705, -12.14683) 48     2 FALSE     1  48.1      2
# 8  (12.57295, -13.23664) 48     3 FALSE     1  48.1      2
# ...
data <- data.frame(box_id=unique(df$box_id),row.names=unique(df$id))

Now, this is the code for points2polygons(...). With your existing SpatialPointsDataFrame, this is all you'd need.

points2polygons <- function(df,data) {
  get.grpPoly <- function(group,ID,df) {
         Polygon(coordinates(df[df$id==ID & df$group==group,]))
         }
  get.spPoly  <- function(ID,df) {
         Polygons(lapply(unique(df[df$id==ID,]$group),get.grpPoly,ID,df),ID)
         }
  spPolygons  <- SpatialPolygons(lapply(unique(df$id),get.spPoly,df))
  SpatialPolygonsDataFrame(spPolygons,match.ID=T,data=data)
}
spDF <- points2polygons(df,data)
plot(spDF,col=spDF$box_id+1)

library(rgdal)
writeOGR(spDF,dsn=".",layer="myShapefile", driver="ESRI Shapefile")

Share:
12,374
user3306720
Author by

user3306720

Updated on June 16, 2022

Comments

  • user3306720
    user3306720 almost 2 years

    I have a SpatialPointsDataFrame in R that looks like this:

                  coordinates id order  hole piece group box_id
        326  (-94.4, 27.6586) 47     1 FALSE     1  47.1      1
        327 (-93.64, 27.6232) 47     2 FALSE     1  47.1      1
        328 (-92.04, 27.7649) 47     3 FALSE     1  47.1      1
        329 (-90.36, 27.0903) 47     4 FALSE     1  47.1      1
        330 (-91.12, 25.6929) 47     5 FALSE     1  47.1      1
        331 (-92.92, 25.6569) 47     6 FALSE     1  47.1      1
        332 (-93.44, 26.0169) 47     7 FALSE     1  47.1      1
        333  (-94.4, 25.9809) 47     8 FALSE     1  47.1      1
        334  (-94.4, 27.6586) 47     9 FALSE     1  47.1      1
        335 (-92.04, 27.7649) 48     1 FALSE     1  48.1      2
        336 (-93.64, 27.6232) 48     2 FALSE     1  48.1      2
        337  (-94.4, 27.6586) 48     3 FALSE     1  48.1      2
        338  (-94.4, 27.8356) 48     4 FALSE     1  48.1      2
        339 (-93.64, 27.7649) 48     5 FALSE     1  48.1      2
        340 (-90.28, 28.1182) 48     6 FALSE     1  48.1      2
        341 (-90.56, 27.9417) 48     7 FALSE     1  48.1      2
        342 (-92.04, 27.7649) 48     8 FALSE     1  48.1      2
        100  (-94.4, 27.8356) 20     1 FALSE     1  20.1      3
        101  (-94.4, 28.0829) 20     2 FALSE     1  20.1      3
        102 (-90.28, 28.1182) 20     3 FALSE     1  20.1      3
        103 (-93.64, 27.7649) 20     4 FALSE     1  20.1      3
        104  (-94.4, 27.8356) 20     5 FALSE     1  20.1      3
    

    (row names/numbers are not in order because I sorted by box_id column)

    These points are nodes of polygons (identified by box_id). I want to write this as a polygon shape file to read into GIS programs, but I'm having trouble converting it into a SpatialPolygonDataFrame (to then use writeOGR) or to directly write it to a shp file. Any help would be appreciate. I'm new to GIS with R, so apologies if I'm missing something obvious.

  • user3306720
    user3306720 about 10 years
    Thanks for hte feedback.
  • user3306720
    user3306720 about 10 years
    I chose this one for including the full process for writing using writeOGR. I think the "(" at the end of line 2 needs to be a "{" but otherwise it runs perfectly