Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Convert SpatialPointsDataframe to SpatialPolygons in R

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.

like image 662
user3306720 Avatar asked Feb 13 '14 15:02

user3306720


1 Answers

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")

like image 162
jlhoward Avatar answered Sep 30 '22 10:09

jlhoward