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_simplifysupposed to do that? (didn't use it, yet) – lbusett Jun 12 '17 at 05:43sfanswer. Thanks. – Phil Jun 12 '17 at 09:57st_simplify, thanks for pointing it out. I do prefer the algorithm thatrmapshaper::ms_simplifydefaults 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 = TRUEdefinitely doesn't work properly yet) – obrl_soil Jun 12 '17 at 10:13preserveTopology = TRUEseemed to work fortolup to about 1000 (of course YMMV), after that things got a bit psychedelic – Phil Jun 12 '17 at 12:33regions) but beyond that it no longer preserves topology. As it breaks at a certain point I'd say that's not intended behaviour – Phil Jun 12 '17 at 12:44