I am using the following code to merged polygons from shapefiles for the purpose of calculating the surface area;
library(maptools)
library(rgdal)
library(rgeos)
#enter slots, e.g. area
shp_list[[3]]@polygons[[1]]@area
setwd("~/type1/speciesX1/")
# Select species
species <- 'speciesX1'
print(species)
# List shapefile-dirs for that species
shp_dir <- list.files(path=species, pattern="*.shp", full.names = TRUE, recursive = TRUE, include.dirs = FALSE)
# Read all the shapefiles and place them in a list
shp_list <- lapply(shp_dir, function(x) {readOGR(dsn=x, layer=ogrListLayers(x), verbose=T)})
# Check how many shapefiles have been loaded
number_of_loaded_shapefiles <- length(shp_list)
print(paste("Number of loaded shapefiles: ", number_of_loaded_shapefiles))
# Set the number of fields to 3, i.e. name, id, mrgid and set id and iso_3digit to id if present
set.seed(1234)
for(i in seq_along(shp_list)){
# EEZ
if('objectid' %in% colnames(shp_list[[i]]@data)==T){
shp_list[[i]]@data <- subset(shp_list[[i]]@data, select=-c(objectid, country, sovereign, remarks, sov_id, eez_id, iso_3digit, date_chang ,area_m2, longitude ,latitude))
shp_list[[i]]@data['id']<-paste0(shp_list[[i]]@data$id,shp_list[[i]]@data$iso_3digit)
colnames(shp_list[[i]]@data)[colnames(shp_list[[i]]@data) == 'eez'] <- 'name'
}else{
# IHO + EEZ (e.g. Mexican part of the North Pacific Ocean, 25569)
if('iho_id' %in% colnames(shp_list[[i]]@data)==T){
shp_list[[i]]@data<-subset(shp_list[[i]]@data, select=-c(objectid_1, iho_sea, iho_id, iho_mrgid, country, sovereign, sov_id, eez, eez_mrgid, longitude, latitude, area_m2))
colnames(shp_list[[i]]@data)[colnames(shp_list[[i]]@data) == 'marregion'] <- 'name'
colnames(shp_list[[i]]@data)[colnames(shp_list[[i]]@data) == 'eez_id'] <- 'id'
shp_list[[i]]@data['id']<-paste0(shp_list[[i]]@data$id, paste0(sprintf("%1s", sample(LETTERS,1)),sprintf("%1s", sample(LETTERS,1))))
shp_list[[i]]@data <- shp_list[[i]]@data[,c(1,3,2)]
}else{
# MEOW (ecoregion, e.g. Bahamian 21980)
if('eco_code' %in% colnames(shp_list[[i]]@data)==T){
shp_list[[i]]@data<-subset(shp_list[[i]]@data, select=-c(lat, long, placetype))
colnames(shp_list[[i]]@data)[colnames(shp_list[[i]]@data) == 'ecoregion'] <- 'name'
colnames(shp_list[[i]]@data)[colnames(shp_list[[i]]@data) == 'eco_code'] <- 'id'
shp_list[[i]]@data['id']<-paste0(shp_list[[i]]@data$id, paste0(sprintf("%1s", sample(LETTERS,1)),sprintf("%1s", sample(LETTERS,1))))
shp_list[[i]]@data <- shp_list[[i]]@data[,c(2,1,3)]
}
}
}
}
# See the row names (IDs)
lapply(shp_list, function(x) row.names(x@data))
# Generate unique id string on the fly
set.seed(1234)
shp_list <- lapply(shp_list, function(x) {
new.id <- paste0(x@data$id, sprintf("%03d", round(runif(1, 1, 999)),0))
spChFIDs(x, new.id)
})
# Print mrgids
for(i in seq_along(shp_list)){
print(shp_list[[i]]@data$mrgid)
}
# Merge the SPDF
merged_shp_list <- do.call("rbind", shp_list)
# Some of the polygons (areas) are the same in the two original SPDFs.
# Check the attribute data
attribute_data_in_merged_shp_list <- merged_shp_list@data
# E.g. Alboran sea (mrgid=3324) is present in both. Make a spatial union based on a common ID-value (mrgid)
union_polygons <- unionSpatialPolygons(merged_shp_list, IDs=merged_shp_list@data$mrgid)
# Check how many polygons are present in the original merge
number_of_polygons_before_merge <- nrow(merged_shp_list)
print(paste('Number of polygons before merge: ', number_of_polygons_before_merge))
# How many polygons are present after merge
number_of_polygons_after_merge <- length(union_polygons)
print(paste('Number of polygons after merge: ', number_of_polygons_after_merge))
# unionSpatialPolygons returns a SpatialPolygons object, but we want to retain the original attribute data as well. Get only the unique rows from the original attribute data
attribute_data <- unique(merged_shp_list@data)
# Row names (IDs) need to match the IDs in union_polygons
rownames(attribute_data) <- attribute_data$mrgid
# Create a new SPDF
final_shp_list <- SpatialPolygonsDataFrame(Sr=union_polygons, data=attribute_data)
# Checks
number_of_merged_polygons_final <- nrow(final_shp_list)
print(paste('Number of merged polygons: ', number_of_merged_polygons_final))
# Calculate area
area <- gArea(SpatialPolygons(final_shp_list@polygons))
print(paste('Area (',species,')',':',area))
# Plot marged polygons
final_shp_plot <- spplot(final_shp_list, "mrgid", colorkey=F, fill='cyan')
print(final_shp_plot)
The shapefiles I'm using are from Marineregions.org
In some cases, the merged polygons might overlap, depending on what type of shapefile have been used (e.g. EEZ, IHO, MEOW). I want to calculate the surface area of the merged polygons, but figured that as it currently is the calculated area includes potential intersections, so I wonder how to unionize these from a set of merged polygons. I've looked into the rgeos package; gUnion, gIntersection, gDifference etc
but these functions only works on a pair.
Below are links to two shapefiles (choose shapefile in the Download drop-menu). For the code, place the files in ~/type1/speciesX1/
and name e.g. the folders 1 and 2 and the files within correspondingly. Sorry, for this part.
Example Data
Comoran part of the Mozambique Channel is part of Mozambique Channel, thus we can see if the intersection is calculated twice for the merged polygon.
Output of Example Data
Plot of the merged polygons
Test
area
125.6221 (as its calculated from above code)
# Area of the two polygons
A1 <- gArea(SpatialPolygons(shp_list[[1]]@polygons))
A2 <- gArea(SpatialPolygons(shp_list[[2]]@polygons))
A1
6.807844
A2
118.8142
# Area of the union
u <- gUnion(shp_list[[1]], shp_list[[2]])
uA <- gArea(SpatialPolygons(u@polygons))
uA
118.8142
# Area of the intersection
i <- gIntersection(shp_list[[1]],shp_list[[2]])
iA <- gArea(SpatialPolygons(i@polygons))
iA
6.807844 (same as A1)
uA + iA
125.6221 (same as calculated by the above code)
So the area calculated by the code does in fact include the intersection twice, i.e. no union is created, since the unionSpatialPolygons
function creates unions based on IDs
.
Is there any function e.g. like gUnion
(or how can I use gUnion?) for multiple (>2) spgeom objects, which I can use and add to my workflow after creating unions based on IDs?