How do I simplify an sf
polygon without introducing gaps and slivers?
With a shapefile, for example, I would use rmapshaper::ms_simplify()
:
library("pryr")
library("rgdal")
library("rmapshaper")
download.file("https://borders.ukdataservice.ac.uk/ukborders/easy_download/prebuilt/shape/England_gor_2011.zip",
destfile = "regions.zip")
unzip("regions.zip")
regions <- readOGR(".", "england_gor_2011")
object_size(regions)
# ~13MB
regions <- ms_simplify(regions)
object_size(regions)
# < 1MB
I've tried sf::st_cast()
which, from the man pages, states:
Cast geometry to another type: either simplify, or cast explicitly
and:
to argument: character; target type, if missing, simplification is tried; when x is of type sfg (i.e., a single geometry) then to needs to be specified.
When I've left to
as missing this hasn't worked as expected though (I knew it was too good to be true!):
library("sf")
regions <- sf::read_sf("england_gor_2011.shp")
object_size(regions)
# ~13MB
regions <- sf::st_cast(regions)
object_size(regions)
# Still 13MB
Currently I'm opening the file with rgdal::readOGR()
, simplifying it, saving this, then loading this again with sf
.
Is there a better way?
rgeos::gSimplify()
@s.k 's suggestion of rgeos::gSimplify()
can do topologically-aware simplifications (i.e. simplifies without creating slivers) when specified with the following arguments:
library("rgeos")
regions_gSimplify <- gSimplify(regions, tol = 0.05, topologyPreserve = TRUE)
gSimplify
doesn't preserve the @data
frame, though, so we should re-create it:
regions_df <- regions@data
regions_gSimplify <- sp::SpatialPolygonsDataFrame(regions_gSimplify, regions_df)
And this does indeed result in a smaller file size (can tweak tol
argument to get it smaller) and I confirmed this hadn't created any slivers by examining it in QGIS.
object_size(regions_gSimplify)
# ~8MB
So although this is a valid alternative to rmapshaper::ms_simplify()
I still have the same problem, namely that it doesn't work with sf
:
regions_sf <- sf::read_sf("england_gor_2011.shp")
object_size(regions_sf)
regions_gSimplify <- gSimplify(regions_sf, topologyPreserve = TRUE, tol = 0.05)
# Error in gSimplify(regions_sf, topologyPreserve = TRUE, tol = 0.05) :
# no slot of name "proj4string" for this object of class "sf"
@obrl_soil 's answer can also be applied to gSimplify()
, just use it in place of ms_simplify()
.
st_simplify
supposed to do that? (didn't use it, yet)st_simplify
, thanks for pointing it out. I do prefer the algorithm thatrmapshaper::ms_simplify
defaults to over all the others I've tried so far, but I'll have a play with the new option (update: whoa proceed with caution,preserveTopology = TRUE
definitely doesn't work properly yet)regions
) but beyond that it no longer preserves topology. As it breaks at a certain point I'd say that's not intended behaviour