3

I have a data frame with a bunch of polygons, several points per polygon. How can I convert it to a SpatialPolygonsDataFrame object?

Here's my data frame:

> buildings_df
        lon      lat               id
1  96.13597 16.83363 convocation_hall
2  96.13580 16.83315 convocation_hall
3  96.13631 16.83298 convocation_hall
4  96.13656 16.83351 convocation_hall
5  96.13400 16.83104    judson_church
6  96.13392 16.83073    judson_church
7  96.13432 16.83064    judson_church
8  96.13444 16.83085    judson_church
9  96.13596 16.83074      the_library
10 96.13586 16.83044      the_library
11 96.13615 16.83035      the_library
12 96.13626 16.83065      the_library
13 96.13599 16.83073      the_library

This can be reproduced with:

> dput(buildings_df)
structure(list(lon = c(96.135972, 96.1358, 96.136315, 96.136562, 
96.133997, 96.133922, 96.134319, 96.134437, 96.135961, 96.135864, 
96.136154, 96.136261, 96.135993), lat = c(16.833625, 16.833153, 
16.832978, 16.833512, 16.831038, 16.830729, 16.830637, 16.830853, 
16.83074, 16.830442, 16.83035, 16.830647, 16.830729), id = structure(c(1L, 
1L, 1L, 1L, 2L, 2L, 2L, 2L, 3L, 3L, 3L, 3L, 3L), .Label = c("convocation_hall", 
"judson_church", "the_library"), class = "factor")), .Names = c("lon", 
"lat", "id"), row.names = c(NA, -13L), class = "data.frame")

From this data.frame, I then convert it to a list, then to polygons, then to a SpatialPolygons object

# make a list
buildings_list <- split(buildings_df, buildings_df$id)
# only want lon-lats in the list, not the names
buildings_list <- lapply(buildings_list, function(x) { x["id"] <- NULL; x })

#  make data.frame into spatial polygon, cf. http://jwhollister.com/iale_open_science/2015/07/05/03-Spatial-Data-In-R/

# create SpatialPolygons Object, convert coords to polygon
ps <- sapply(buildings_list, Polygon)

# add id variable 
p1 <- Polygons(ps, ID = 1) 

# create SpatialPolygons object
my_spatial_polys <- SpatialPolygons(list(p1), proj4string = CRS("+proj=longlat +datum=WGS84") ) 

# let's see them
plot(my_spatial_polys)

So far so good:

enter image description here

And each of the polygons seems to be in there...

> str(my_spatial_polys)
Formal class 'SpatialPolygons' [package "sp"] with 4 slots
  ..@ polygons   :List of 1
  .. ..$ :Formal class 'Polygons' [package "sp"] with 5 slots
  .. .. .. ..@ Polygons :List of 3
  .. .. .. .. ..$ convocation_hall:Formal class 'Polygon' [package "sp"] with 5 slots
  .. .. .. .. .. .. ..@ labpt  : num [1:2] 96.1 16.8
  .. .. .. .. .. .. ..@ area   : num 3.08e-07
  .. .. .. .. .. .. ..@ hole   : logi FALSE
  .. .. .. .. .. .. ..@ ringDir: int 1
  .. .. .. .. .. .. ..@ coords : num [1:5, 1:2] 96.1 96.1 96.1 96.1 96.1 ...
  .. .. .. .. ..$ judson_church   :Formal class 'Polygon' [package "sp"] with 5 slots
  .. .. .. .. .. .. ..@ labpt  : num [1:2] 96.1 43.3
  .. .. .. .. .. .. ..@ area   : num 0.0204
  .. .. .. .. .. .. ..@ hole   : logi TRUE
  .. .. .. .. .. .. ..@ ringDir: int -1
  .. .. .. .. .. .. ..@ coords : num [1:5, 1:2] 96.1 96.1 96.1 96.1 96.1 ...
  .. .. .. .. ..$ the_library     :Formal class 'Polygon' [package "sp"] with 5 slots
  .. .. .. .. .. .. ..@ labpt  : num [1:2] 96.1 43.3
  .. .. .. .. .. .. ..@ area   : num 0.00512
  .. .. .. .. .. .. ..@ hole   : logi TRUE
  .. .. .. .. .. .. ..@ ringDir: int -1
  .. .. .. .. .. .. ..@ coords : num [1:6, 1:2] 96.1 96.1 96.1 96.1 96.1 ...
  .. .. .. ..@ plotOrder: int [1:3] 1 2 3
  .. .. .. ..@ labpt    : num [1:2] 96.1 16.8
  .. .. .. ..@ ID       : chr "1"
  .. .. .. ..@ area     : num 0.0302
  ..@ plotOrder  : int 1
  ..@ bbox       : num [1:2, 1:2] 96.1 16.8 96.1 16.8
  .. ..- attr(*, "dimnames")=List of 2
  .. .. ..$ : chr [1:2] "x" "y"
  .. .. ..$ : chr [1:2] "min" "max"
  ..@ proj4string:Formal class 'CRS' [package "sp"] with 1 slot
  .. .. ..@ projargs: chr "+proj=longlat +datum=WGS84 +ellps=WGS84 +towgs84=0,0,0"

But they don't seem to be grouped in the way I'm expecting. When I try to set three ID variables, I get an error. How can I get the SpatialPolygons to have three polygons, each with its own ID?

1

One solution is to change p1 <- Polygons(ps, ID = 1) to an apply-like function so that the Polygons() function operates individually on each of the polygons in the ps object.

ps <- lapply(buildings_list, Polygon)

# add id variable
p1 <- lapply(seq_along(ps), function(i) Polygons(list(ps[[i]]), 
                                            ID = names(buildings_list)[i]  ))

# create SpatialPolygons object
my_spatial_polys <- SpatialPolygons(p1, proj4string = CRS("+proj=longlat +datum=WGS84") ) 

Then we can create the SpatialPolygonsDataFrame with the IDs as expected, one unique ID per polygon:

my_spatial_polys_df <- SpatialPolygonsDataFrame(my_spatial_polys, 
 data.frame(id = unique(buildings_df$id), 
            row.names = unique(buildings_df$id)))

> str(my_spatial_polys_df)
Formal class 'SpatialPolygonsDataFrame' [package "sp"] with 5 slots
  ..@ data       :'data.frame': 3 obs. of  1 variable:
  .. ..$ id: Factor w/ 3 levels "convocation_hall",..: 1 2 3
  ..@ polygons   :List of 3
  .. ..$ :Formal class 'Polygons' [package "sp"] with 5 slots
  .. .. .. ..@ Polygons :List of 1
  .. .. .. .. ..$ :Formal class 'Polygon' [package "sp"] with 5 slots
  .. .. .. .. .. .. ..@ labpt  : num [1:2] 96.1 16.8
  .. .. .. .. .. .. ..@ area   : num 3.08e-07
  .. .. .. .. .. .. ..@ hole   : logi FALSE
  .. .. .. .. .. .. ..@ ringDir: int 1
  .. .. .. .. .. .. ..@ coords : num [1:5, 1:2] 96.1 96.1 96.1 96.1 96.1 ...
  .. .. .. ..@ plotOrder: int 1
  .. .. .. ..@ labpt    : num [1:2] 96.1 16.8
  .. .. .. ..@ ID       : chr "convocation_hall"
  .. .. .. ..@ area     : num 0.0302
  .. ..$ :Formal class 'Polygons' [package "sp"] with 5 slots
  .. .. .. ..@ Polygons :List of 1
  .. .. .. .. ..$ :Formal class 'Polygon' [package "sp"] with 5 slots
  .. .. .. .. .. .. ..@ labpt  : num [1:2] 96.1 16.8
  .. .. .. .. .. .. ..@ area   : num 1.23e-07
  .. .. .. .. .. .. ..@ hole   : logi FALSE
  .. .. .. .. .. .. ..@ ringDir: int 1
  .. .. .. .. .. .. ..@ coords : num [1:5, 1:2] 96.1 96.1 96.1 96.1 96.1 ...
  .. .. .. ..@ plotOrder: int 1
  .. .. .. ..@ labpt    : num [1:2] 96.1 16.8
  .. .. .. ..@ ID       : chr "judson_church"
  .. .. .. ..@ area     : num 0.0204
  .. ..$ :Formal class 'Polygons' [package "sp"] with 5 slots
  .. .. .. ..@ Polygons :List of 1
  .. .. .. .. ..$ :Formal class 'Polygon' [package "sp"] with 5 slots
  .. .. .. .. .. .. ..@ labpt  : num [1:2] 96.1 16.8
  .. .. .. .. .. .. ..@ area   : num 9.7e-08
  .. .. .. .. .. .. ..@ hole   : logi FALSE
  .. .. .. .. .. .. ..@ ringDir: int 1
  .. .. .. .. .. .. ..@ coords : num [1:6, 1:2] 96.1 96.1 96.1 96.1 96.1 ...
  .. .. .. ..@ plotOrder: int 1
  .. .. .. ..@ labpt    : num [1:2] 96.1 16.8
  .. .. .. ..@ ID       : chr "the_library"
  .. .. .. ..@ area     : num 0.00512
  ..@ plotOrder  : int [1:3] 1 2 3
  ..@ bbox       : num [1:2, 1:2] 96.1 16.8 96.1 16.8
  .. ..- attr(*, "dimnames")=List of 2
  .. .. ..$ : chr [1:2] "x" "y"
  .. .. ..$ : chr [1:2] "min" "max"
  ..@ proj4string:Formal class 'CRS' [package "sp"] with 1 slot
  .. .. ..@ projargs: chr "+proj=longlat +datum=WGS84 +ellps=WGS84 +towgs84=0,0,0"

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.