1

I want to add a unique ID (row number) for each polygon in a SpatialPolygonsDataFrame. I'm new at working with spatial data (and programming) so bear with me please. The goal is to merge all polygons belonging to a single species.

This is what I run:

setwd("~/type1")
species <- 'speciesX'
list_shp <- list.files(path=species, pattern="*.shp", full.names = TRUE,
                   recursive = TRUE, include.dirs = FALSE)
shp_objects <- lapply(list_shp, function(x) {readOGR(dsn=x, layer=ogrListLayers(x))})

# See the row names (IDs)
lapply(shp_objects, function(x) row.names(x@data))

# Manually set unique row names (IDs)
shp_objects[[1]] <- spChFIDs(shp_objects[[1]], as.character(10)) # e.g. 10

But, since the SPDF for each species can have several polygons, I tried making a for loop, implementing a simple counter, adding a consecutive number to each as row names (IDs) using the spChFIDs function.

idx<-0
for(i in shp_objects){
 idx<-idx+1
 shp_objects <- spChFIDs(i, as.character(idx))
}

When running this, and then lapply(shp_objects, function(x) row.names(x@data)) to see if the row names have been updated accordingly, I get the error:

Error in as.list.default(X) : 
  no method for coercing this S4 class to a vector

How could I make this work? or how would I do the same thing using `sapply? Any pointer would be highly appreciated.

  • Welcome to gis.SE. When you say "this doesn't work", it usually helps to explain what happens instead. Remember we can't see your screen, so you have to describe it to us. You can easily update the question (just click edit below the question) to add this information, and anything else you think of. – BradHards Dec 13 '13 at 1:43
  • @BradHards: Thanks. Of course, sorry for that. Now updated. – jO. Dec 13 '13 at 2:01
  • @SlowLearner: the shapefiles comes from marineregions. Some contain several polygons, like the Mediterranean Sea while others only contain one. But if the loop would work for the second scenario, I guess it's easy to make it work for the first as well... – jO. Dec 16 '13 at 9:45
  • I mean, if it would work for the single polygon scenario as in the above example, it would be straight forward making it work for the cases with several polygons per shapefile – jO. Dec 16 '13 at 10:35
  • Ok, sorry for not being clear enough. I want to merge polygons for finding and comparing surface areas. In the drop-download menu I choose the shapefile option. There is different types of species distributions; EEZs, IHOs and MEOWs. They differ in the number of fields they have in the SPDFs. So, before merging (rbinding) I have to standardize these. In the above example, I use single polygon IHO shapefiles, e.g. 3314 and 3315. – jO. Dec 16 '13 at 20:05
2

The question as it stands is confused, ambiguous and is not reproducible. If it had been reproducible we would have been able to resolve it in minutes rather than in days. (Please read this post in its entirety as it is relevant to this GIS forum as well as to Stack Overflow.)

Essentially you were doing the right thing with the shapefiles, but your loop was not assigning values properly. Your code attempts to assign new id values to shp_objects which is a list, not an object. It should be assigning to a member of that list. Arguably it would be more idiomatic to use lapply than a for loop in any case. Code follows.

species <- "name_of_directory_holding_shapefiles_do_not_add_slash_to_end"

list_shp <- list.files(path = species, pattern = "*.shp", full.names = TRUE,
                   recursive = TRUE, include.dirs = FALSE)

shp_objects <- lapply(list_shp, function(x) {readOGR(dsn=x, layer=ogrListLayers(x))})

# See the row names (IDs)
lapply(shp_objects, function(x) row.names(x@data))

idx <- 0
for(i in seq_along(shp_objects)){
 idx <- idx + 1
 shp_objects[[i]] <- spChFIDs(shp_objects[[i]], as.character(idx))
}

lapply(shp_objects, function(x) row.names(x@data))

# or instead of for loop use lapply and generate unique id string on the fly
shp_objects <- lapply(shp_objects, function(x) {
    new.id <- paste0(x@data$id, sprintf("%03d", round(runif(1, 1, 999)),0))
    spChFIDs(x, new.id)
})

lapply(shp_objects, function(x) row.names(x@data))

This gives the following results:

> idx <- 0
> for(i in seq_along(shp_objects)){
+  idx <- idx + 1
+  shp_objects[[i]] <- spChFIDs(shp_objects[[i]], as.character(idx))
+ }
> 
> lapply(shp_objects, function(x) row.names(x@data))
[[1]]
[1] "1"

[[2]]
[1] "2"

> 
> # or use lapply and generate an unique id string on the fly
> set.seed(1234)
> shp_objects <- lapply(shp_objects, function(x) {
+     new.id <- paste0(x@data$id, sprintf("%03d", round(runif(1, 1, 999)),0))
+     spChFIDs(x, new.id)
+ })
> 
> lapply(shp_objects, function(x) row.names(x@data))
[[1]]
[1] "28g114"

[[2]]
[1] "28h622"
  • Thanks a lot! Im sorry the question wasn't clear enough from the beginning, I'll try to improve! Cheers – jO. Dec 17 '13 at 10:46
  • Most of us start like that - my first questions on Stack Overflow were rubbish. The point is to make each question a bit better/simpler than the previous one. – SlowLearner Dec 17 '13 at 20:55

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.