22
coast<-readShapeSpatial("coastline.shp")
landc<-readShapeSpatial("landcover.shp")
ro<-readShapeSpatial("roads.shp")
bc<-gBuffer(ro,width=100)
landc$ratings=1
landc$ratings[landc$LANDUSE_ID==4]=0 

Above, I take any category that has 4 and in the new column put it as 0.

At this point, I want the column named ratings as well for the bc, where it will take 0 if it is inside the buffer and 1 if it is outside. The problem is that the bc is SpatialPolygons and it doesn't contain the attribute table.

Obviously to add a column to a SpatialPolygon object you have to convert it to a SpatialPolygonsDataFrame, but I don't know how.

I tried this:

buf_df<-as.data.frame(bc)
s_po<-SpatialPolygonsDataFrame(bc,buf_df)
s_po$ratings=0

but this error pops up:

row.names of data and Polygons IDs do not match 
1
  • 1
    Well, if you read the help for gBuffer you would know that if byid=TRUE the result is a SpatialPolygonsDataFrame. Apr 6, 2015 at 2:15

5 Answers 5

15

What do the "coast", "ro" and "bc" objects have to do with your problem? The issue may lie in that you are using "readShapeSpatial". Have you tried readOGR in rgdal? If you are reading a polygon shapefile, readOGR will result in a SpatialPolygonsDataFrame object.

If you in fact, do have a SpatialPolygons object and want to coerce into SpatialPolygonsDataFrame the specified dataframe will need to have its rownames match the polygon ID's in the polygons slot. Here is a quick example.

library(sp)

# create some SpatialPolygons with ID's "2" and "3"
( p <- SpatialPolygons(list(Polygons(list(Polygon(cbind(c(2,4,4,1,2),c(2,3,5,4,2)))), "2"),
     Polygons(list(Polygon(cbind(c(5,4,2,5),c(2,3,2,2)))), "3"))) )
class(p)    

# Create a dataframe and display default rownames
( p.df <- data.frame( ID=1:length(p)) ) 
rownames(p.df)

# Try to coerce to SpatialPolygonsDataFrame (will throw error)
p <- SpatialPolygonsDataFrame(p, p.df) 

# Extract polygon ID's
( pid <- sapply(slot(p, "polygons"), function(x) slot(x, "ID")) )

# Create dataframe with correct rownames
( p.df <- data.frame( ID=1:length(p), row.names = pid) )    

# Try coersion again and check class
 p <- SpatialPolygonsDataFrame(p, p.df)
 class(p) 

# Now we can add a column
p@data$ratings <- 1:2 

# Or modify an existing one
p[p$ID < 2 ,] <- 5
1
  • i showed the rest of the code like the "coast","ro" and "bc" to help you get the idea of what i am trying to do in general. i need to get a more to the point answer of what i'm asking and it would be wise to use my own variables in order to be more understandable.Plus, what is the deal with the readOGR and the readShapeSpatial? The "bc" contains the roads buffer which is the spatialpolygons object that i need to add the new column to, thus i have to convert it to a spatialPolygonsDataFrame first.
    – gsa
    Apr 5, 2015 at 15:35
10

Try:

#Code taken from the question:
s_po <- SpatialPolygonsDataFrame(bc, buf_df, match.ID = F) 

match.ID avoids the requirement of rownames for match polygons ID

1
  • 4
    Don't be contrary, it is not appreciated! The reason "complicated" answers were provided is because in 2015, when the question was addressed, the match.ID argument was not available in the coersion method. Feb 20, 2018 at 0:28
7

It is quite simple:

library("rgdal")
polygons <- readOGR('path_to/file.shp',
                      layer = 'file')
class(polygons)
>[1] "SpatialPolygonsDataFrame"
>attr(,"package")
>[1] "sp"

poly_df <- as.data.frame(polygons)
# do some staff with "poly_df" that doesn't support SpatialPolygonsDataFrame
# then convert it to SPDF back again
s_poly <- SpatialPolygonsDataFrame(polygons, poly_df)
# add new column to SPDF:
s_poly$new_column <- "some data" 

When the Error: "row.names of data and Polygons IDs do not match" arise this solution seems to be helpful: rename IDs of the dataframe to match IDs of the polygons:

newdata <- data.frame(whatever you want in here)
row.names(newdata) <- (however the new polygons are labeled)
polygons <- SpatialPolygonsDataFrame(polygons, newdata)
7
  • 2
    Not sure on a couple steps here. This coercion is dubious: as.data.frame(polygons). You example is coercing the object into the same class. Additionally, in a real example you would throw an error because the rownames of the dataframe would not match the ID in the polygon slot(s). You need to pull the polygon ID's and assign them to the rownames before coercion. Apr 4, 2015 at 15:33
  • @JeffreyEvans, this is a copy-paste from the working code. No errors, everything is working. Just read some documentation on how SpatialPolygonsDataFrame is created. Apr 4, 2015 at 21:39
  • 4
    But, since you use readOGR in your example, you are starting with a SpatialPolygonsDataFrame and the dataframe you subset already has the correct rownames because you pulled it from the original sp object. It is a strawman example. Apr 5, 2015 at 0:41
  • @JeffreyEvans, I edited my answer to clarify the meaning. Apr 5, 2015 at 12:07
  • see my last edit in the main post and tell me what i did wrong cause i think i made it according to your comment but it gives error. Use my own variables to make it more comprehensable. Thanks
    – gsa
    Apr 5, 2015 at 12:11
1

I find the following solution generally works.

First, create an empty dataframe with ID as field:

df <- data.frame(ID=character(), stringsAsFactors=FALSE )

Then get the IDs of spatial polygon bc:

for (i in bc@polygons ) { df <- rbind(df, data.frame(ID=i@ID, stringsAsFactors=FALSE))  }
# and set rowname=ID
row.names(df) <- df$ID

Then use df as the second argument to the spatial dataframe conversion function:

spatial_df <- SpatialPolygonsDataFrame(bc, df)

As df and spatial_df are dataframe objects, columns can be easily added

0

I used this solution from Roger B. https://stat.ethz.ch/pipermail/r-help/2005-December/085175.html

yourDF <- as.data.frame(yourPolygon)

set rowname=ID from polygon

row.names(yourDF) <- sapply(slot(yourPolygon, "polygons"), function(x) slot(x, "ID"))

Then creates back your Spatial Data Frame with:

yourNewPolygon<- SpatialPolygonsDataFrame(yourPolygon, yourDF)

Test any operation on it like

yourNewPolygon<- elide(yourNewPolygon, rotate=-50)

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.