Vereinfachen Sie Polygone von sf-Objekten

14

Wie kann ich ein sfPolygon vereinfachen, ohne Lücken und Splitter einzufügen?

Mit einem Shapefile würde ich zum Beispiel Folgendes verwenden 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

Ich habe ausprobiert, sf::st_cast()was aus den Manpages hervorgeht:

Geometrie in einen anderen Typ umwandeln: entweder vereinfachen oder explizit umwandeln

und:

zu argumentieren: Charakter; Zieltyp, falls fehlt, wird eine Vereinfachung versucht; Wenn x vom Typ sfg ist (dh eine einzelne Geometrie), muss to angegeben werden.

Wenn ich toals vermisst abgereist bin, hat dies jedoch nicht wie erwartet funktioniert (ich wusste, dass es zu gut ist, um wahr zu sein!):

library("sf")
regions <- sf::read_sf("england_gor_2011.shp")
object_size(regions)
# ~13MB

regions <- sf::st_cast(regions)
object_size(regions)
# Still 13MB

Momentan öffne ich die Datei mit rgdal::readOGR(), vereinfache sie, speichere sie und lade sie dann erneut mit sf.

Gibt es einen besseren Weg?


rgeos::gSimplify()

@sk 's Vorschlag von rgeos::gSimplify()kann topologisch bewusste Vereinfachungen (dh Vereinfachungen ohne das Erstellen von Splittern) durchführen, wenn er mit den folgenden Argumenten angegeben wird:

library("rgeos")
regions_gSimplify <- gSimplify(regions, tol = 0.05, topologyPreserve = TRUE)

gSimplifybehält den @dataRahmen jedoch nicht bei , daher sollten wir ihn neu erstellen:

regions_df <- regions@data
regions_gSimplify <- sp::SpatialPolygonsDataFrame(regions_gSimplify, regions_df)

Und dies führt in der Tat zu einer kleineren Dateigröße (kann das tolArgument optimieren , um es zu verkleinern), und ich bestätigte, dass dies keine Splitter erzeugt hat, indem ich es in QGIS untersuchte.

object_size(regions_gSimplify)
# ~8MB

Also, obwohl dies eine gültige Alternative zu ist, habe rmapshaper::ms_simplify()ich immer noch das gleiche Problem, nämlich dass es nicht funktioniert mit 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"

Die Antwort von @obrl_soil kann auch auf angewendet werden gSimplify(), verwenden Sie sie einfach anstelle von ms_simplify().

Phil
quelle
1
Haben Sie Zugang zu einem Douglas-Peucker-Algorithmus? Es ist allgemein bekannt für die Vereinfachung von Funktionen in der GIS-Welt. stackoverflow.com/questions/17217413/… & r-bloggers.com/simplifying-spatial-polygons-in-r
sk
1
Soll das nicht st_simplifysein? (habe es noch nicht benutzt)
lbusett
2
Oh, ich hatte es nicht bemerkt st_simplify, danke, dass du darauf hingewiesen hast . Ich bevorzuge den Algorithmus, der rmapshaper::ms_simplifystandardmäßig allen anderen verwendet wird, die ich bisher ausprobiert habe, aber ich werde mit der neuen Option spielen (Update: whoa mit Vorsicht vorgehen, preserveTopology = TRUEfunktioniert definitiv noch nicht richtig)
obrl_soil
1
Gut zu wissen. Was ist mit einem Fehlerbericht darüber?
lbusett
1
@obrl_soil Funktioniert mit Toleranzen von bis zu 1000 für die Polygone, die ich in der Frage ( regions) verwendet habe, behält aber darüber hinaus die Topologie nicht mehr bei. Da es an einem bestimmten Punkt kaputt geht, würde ich sagen, dass dies kein beabsichtigtes Verhalten ist
Phil

Antworten:

16

Sie können ein sf-Objekt in sp umwandeln, für Pakete, die sf noch nicht unterstützen - ich mache das ein gutes Stück für Raster / Polygon-Interaktionen. Sie könnten also Folgendes tun:

simplepolys <- rmapshaper::ms_simplify(input = as(sfobj, 'Spatial')) %>%
  st_as_sf()
obrl_soil
quelle
1
Diese Technik - Gießen als räumliches Objekt, Vereinfachen und erneutes Gießen als sfObjekt - funktionierte perfekt und kann mit rmapshaper::ms_simplify()oder verwendet werden rgeos::gSimplify(). Danke für den Vorschlag!
Phil
Cool, cool, sei dir nur bewusst, dass die Topologie von ineinandergreifenden Polygonen nur mit dem Ansatz von rmapshaper wirklich erhalten bleibt. Wenn es sich bei Ihren Eingabedaten ausschließlich um isolierte, nicht ineinander greifende Polygone handelt, können Sie sicher alle verfügbaren Vereinfachungsalgen verwenden.
obrl_soil
Ich akzeptiere dies als Antwort, da der kanonischere sf::st_simplify()bei hohen Toleranzen zum Zeitpunkt des Schreibens nicht robust ist, obwohl sich dies offensichtlich ändern kann.
Phil
8
Ich arbeite derzeit an der Unterstützung für sfObjekte in rmapshaper . ms_simplifyist für sfObjekte in der Entwicklungsversion verfügbar. Ich würde mich über frühe Tester devtools::install_github("ateucher/rmapshaper", ref = "sf")
freuen
6
Ab rmapshaperVersion 0.3.0 ist der Aufruf von as( , "Spatial")nicht mehr erforderlich.
Luke1018,