1
votes

This is my first time doing any sort of spatial data visualization in R, and I'm stuck on a particular issue. I would like to clip a spatial polygon (specified by a series of lat/long coordinates) according to a world map, such that any part of the polygon which overlaps with a map polygon is removed. Using what I have in the below code as an example, I want to clip the rectangular spatial polygon so that only oceanic portions of the polygon remain.

I've found examples of how to retain the intersection between two spatial polygons, but I want to do the opposite. Perhaps there is a way to define the intersection, then "subtract" that from the polygon I wish to clip?

This might be a really basic question, but any tips will be appreciated!

Specify lat/long data:

x_coord <- c(25, 25, 275, 275)
y_coord <- c(20, -50, -50, 20)
xy.mat <- cbind(x_coord, y_coord)
xy.mat

Convert to spatial polygons object:

library(sp)
poly = Polygon(xy.mat)
polys = Polygons(list(poly),1)
spatial.polys = SpatialPolygons(list(polys))
proj4string(spatial.polys) = CRS("+proj=longlat +datum=WGS84 +no_defs 
    +ellps=WGS84 +towgs84=0,0,0")

Convert to spatial polygons data frame and export as shapefile:

df = data.frame(f=99.9)
spatial.polys.df = SpatialPolygonsDataFrame(spatial.polys, df)
spatial.polys.df

library(GISTools)
library(rgdal)
writeOGR(obj=spatial.polys.df, dsn="tmp", layer="polygon", 
    driver="ESRI Shapefile")

Plot world map and add .shp file:

map("world", wrap=c(0,360), resolution=0, ylim=c(-60,60))
map.axes()
shp <- readOGR("polygon.shp")
plot(shp, add=TRUE, col="blue", border=FALSE)
2

2 Answers

5
votes

Here is a solution that stays in sf the entire time (I don't know sp), and illustrates constructing an sf object from scratch. st_difference create the geometry you want exactly, and then plotting can be done with the base plot method or the development version of ggplot which has geom_sf. I used map data from maps and rnaturalearth for this, you can adapt to your particular situation. Wrapping around the dateline is a little finicky regardless unfortunately.

library(tidyverse)
library(sf)
#> Linking to GEOS 3.6.1, GDAL 2.2.0, proj.4 4.9.3
library(rnaturalearth)
library(maps)
#> 
#> Attaching package: 'maps'
#> The following object is masked from 'package:purrr':
#> 
#>     map

x_coord <- c(25, 25, 275, 275)
y_coord <- c(20, -50, -50, 20)
polygon <-  cbind(x_coord, y_coord) %>%
  st_linestring() %>%
  st_cast("POLYGON") %>%
  st_sfc(crs = 4326, check_ring_dir = TRUE) %>%
  st_sf() %>%
  st_wrap_dateline(options = c("WRAPDATELINE=YES", "DATELINEOFFSET=180"))

land <- rnaturalearth::ne_countries(returnclass = "sf") %>%
  st_union()
ocean <- st_difference(polygon, land)
#> although coordinates are longitude/latitude, st_difference assumes that they are planar

plot(st_geometry(land))
plot(st_geometry(polygon), add = TRUE)
plot(st_geometry(ocean), add = TRUE, col = "blue")

ggplot() +
  theme_bw() +
  borders("world") +
  geom_sf(data = ocean)

Created on 2018-03-13 by the reprex package (v0.2.0).

2
votes

If I understand correctly what you want you can do it with the sf package using st_difference() and st_union()`.

Base on your code here is what you can do.

# world data
data("wrld_simpl", package = 'maptools')

# load sf package
library('sf')

# coerce sp object to sf
world <- st_as_sf(wrld_simpl)
rectangle <- st_as_sf(spatial.polys)

# difference between world polygons and the rectangle
difference <- st_difference(rectangle, st_union(world))

# coerce back to sp
difference <- as(difference, 'Spatial')

# plot the result
plot(difference)