25

I have created 2 polygons in QGIS. Using them in R, polygons become automatically SpatialPolygonsDataFrame (SPDF). I would like to merge them into single SPDF (as is super easy in ArcGis using Tool Merge). I am sure that there should be simple way how to complete that in R, but I can't find how. the merge function seems to merge only data.frames, aggregate function dissolve multiple polygons into one shp, gIntersect (by typing join function) returns logical value, not at all the SPDF.

enter image description here

data are available here: http://ulozto.cz/xpoo5jfL/ab-zip

library(sp)
library(raster)
library(rgeos)
library(spatstat)
library(rgdal)     
library(maptools)

setwd("C:/...")
a<-readOGR(dsn=getwd(), layer="pol.a")
b<- readOGR(dsn=getwd(), layer="pol.b")

ab<-merge(a, b)  # what tool if not "merge" to use??
2

3 Answers 3

23

If you do not need to merge topology, but just add new polygons, you can simply use:

ab <- rbind(a,b)

If you get a "non-unique Polygons ID slot values" error it means that the rownames of the objects are the same. To fix this you can use spChFIDs to change the rownames and associated slot relationships. Since the slots in the object use the rownames to associate the object, you cannot just change row.names in the @data slot.

b <- spChFIDs(b, paste("b", row.names(b), sep="."))

The union (union_sp) function in the raster package is doing this, and calling gIntersects from rgeos, behind the scenes and is a very convenient helper function.

****Edit 08-06-2018 There is an undocumented argument that can be used to skip the duplicate ID issue.

ab <- rbind(a, b, makeUniqueIDs = TRUE) 
5
  • Hi, thank you, I tried this one but got an error: Error in validObject(res) : invalid class “SpatialPolygons” object: non-unique Polygons ID slot values. How can I deal with this error?
    – maycca
    Commented Jul 22, 2015 at 17:00
  • 4
    You can do: ab <- bind(a, b) to avoid that error Commented Dec 6, 2017 at 7:05
  • raster::union does not currently work with spatialPOINTSdataframes
    – Mox
    Commented Mar 13, 2018 at 23:08
  • Using R 3.6.3, rbind doesn't have a makeUniqueIDs argument. If I use it, I get 'Error: arguments have different crs' github.com/r-spatial/sf/issues/588#issuecomment-350054943
    – Lucas
    Commented Mar 24, 2022 at 9:55
  • 1
    @Lucas this answer is in reference to sp class objects not sf. Commented Mar 24, 2022 at 12:55
21

Super easy solution provided by @mdsumner:

library(sp)
library(raster)
library(rgeos)
library(spatstat)
library(rgdal)     
library(maptools)

setwd("C:/...")
a<-readOGR(dsn=getwd(), layer="pol.a")
b<- readOGR(dsn=getwd(), layer="pol.b")

# use union in {raster} package ?raster::union
ab<-union(a, b)

resulted in :

class(ab)

[1] "SpatialPolygonsDataFrame"
attr(,"package")
[1] "sp"

enter image description here

4
  • 8
    Super easy solution provided by Robert Hijmans, the author of raster :)
    – mdsumner
    Commented Jul 22, 2015 at 22:18
  • 'Union' does not (currently) work for spatialpointsdataframes, although I am told it will in the next release. @RobertH has suggested the use of rbind, although I'm not exactly clear on how that works.
    – Mox
    Commented Mar 13, 2018 at 23:01
  • Details here: gis.stackexchange.com/questions/274609/…
    – Mox
    Commented Mar 13, 2018 at 23:01
  • It looks like raster::union works for the SpatialLinesDataFrame class as well! Commented Nov 26, 2018 at 23:43
1
library(sp)
data(meuse)
plot(meuse)
slotNames(meuse) #".Data"     "names"     "row.names" ".S3Class" 
coordinates(meuse) <- ~x+y #Add "ID" column to "meuse"
slotNames(meuse) #[1] "data"        "coords.nrs"  "coords"      "bbox"        "proj4string"
class(meuse) #[1] "SpatialPointsDataFrame"
names(meuse@data)
#[1] "cadmium" "copper"  "lead"    "zinc"    "elev"    "dist"    "om"      "ffreq"   "soil"    "lime"   
#[11] "landuse" "dist.m"
meuse@data <- data.frame(ID=1:nrow(meuse), meuse@data) #adds an ID field
names(meuse@data)
#[1] "ID"      "cadmium" "copper"  "lead"    "zinc"    "elev"    "dist"    "om"      "ffreq"   "soil"   
#[11] "lime"    "landuse" "dist.m" 
#Create a data.frame "df.new" with "IDS" (note different name) and "y" columns.
meuse_table.df <- data.frame(IDS=1:nrow(meuse), y=runif(nrow(meuse)))
class(meuse_table.df) #"data.frame"
#Now we can merge "df.new" to "meuse" (@data slot)
meuse <- merge(meuse, meuse_table.df, by.x = "ID", by.y = "IDS")
#create a new file named meuse, consisting of a merge of:
#   the meuse spatial points (from the original)
#   the dataframe created from the original, using the data.frame command
#   BY the field "ID" in the spatialpointsdataframe
#   By the field "IDS" in the tabular dataframe (df.new) 
head(meuse@data)
# I think the source of unease is that adding an ID field to both files 
#is based on them having the same number of rows in the same order. 
#in ArcGIS, this would be an unreasonable and dangerous assumption.
#R seems to have some sort of 'innate' key field, based on the order read it. 
#This is all great when splitting one file, and merging it back together.
#but what about two files? 
#I think it can be done, but it's a three-step process. 
#First, merge the polygons. Add an ID field, as above.
#Second, merge the tables (as dataframes), and add ID's. as above. 
#Third, attach the merged tables to the merged polygons. 
#For it to work, the order of things in the merge (polgyons, dataframe) needs be identfical. 

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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