Uprość wielokąty obiektu sf

14

Jak uprościć sfwielokąt bez wprowadzania przerw i fragmentów?

Na przykład z plikiem shapefile użyłbym 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

Próbowałem, sf::st_cast()który na stronach podręcznika stwierdza:

Rzuć geometrię na inny typ: uprość lub jawnie rzutuj

i:

do argumentu: znak; w przypadku braku typu docelowego próbowane jest uproszczenie; gdy x jest typu sfg (tj. pojedyncza geometria), to należy podać.

Kiedy odeszłam tojako zaginiona, nie działało to zgodnie z oczekiwaniami (wiedziałem, że to zbyt piękne, aby mogło być prawdziwe!):

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

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

Obecnie otwieram plik rgdal::readOGR(), upraszczając go, zapisując, a następnie ładując ponownie sf.

Czy jest lepszy sposób?


rgeos::gSimplify()

Sugestia @sk rgeos::gSimplify()może robić uproszczenia uwzględniające topologię (tj. upraszcza bez tworzenia warstw), jeśli podano następujące argumenty:

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

gSimplifynie zachowuje @dataramki, dlatego powinniśmy ją ponownie utworzyć:

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

I rzeczywiście powoduje to mniejszy rozmiar pliku (można dostosować tolargument, aby go zmniejszyć) i potwierdziłem, że nie stworzyłem żadnych fragmentów, badając go w QGIS.

object_size(regions_gSimplify)
# ~8MB

Chociaż jest to ważna alternatywa dla rmapshaper::ms_simplify()nadal mam ten sam problem, a mianowicie to, że nie działa z 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"

Odpowiedź @obrl_soil może być również zastosowana gSimplify(), wystarczy użyć jej zamiast ms_simplify().

Phil
źródło
1
Czy masz dostęp do algorytmu Douglasa – Peuckera? Jest powszechnie znany z uproszczenia funkcji w świecie GIS. stackoverflow.com/questions/17217413/… & r-bloggers.com/simplifying-spatial-polygons-in-r
sk
1
Czy nie st_simplifypowinien tego robić? (jeszcze go nie używał)
lbusett
2
ooh, nie zauważyłem st_simplify, dzięki za wskazanie tego. Wolę algorytm, który jest rmapshaper::ms_simplifydomyślny niż wszystkie inne, które próbowałem do tej pory, ale zagram z nową opcją (aktualizacja: whoa postępuj ostrożnie, preserveTopology = TRUEzdecydowanie jeszcze nie działa)
obrl_soil
1
Dobrze wiedzieć. Co powiesz na otwarcie raportu o błędzie?
lbusett
1
@obrl_soil Działa dla tolerancji do około 1000 na wielokątach, których użyłem w pytaniu ( regions), ale poza tym nie zachowuje już topologii. Gdy pęka w pewnym momencie, powiedziałbym, że to nie jest zamierzone zachowanie
Phil

Odpowiedzi:

16

Możesz rzucić obiekt sf na sp, dla pakietów, które jeszcze nie obsługują sf - robię to dość dobrze dla interakcji raster / wielokąt. Więc możesz zrobić:

simplepolys <- rmapshaper::ms_simplify(input = as(sfobj, 'Spatial')) %>%
  st_as_sf()
obrl_soil
źródło
1
Ta technika - rzucanie jako obiekt przestrzenny, upraszczanie, a następnie ponowne rzucanie jako sfobiekt - działała idealnie i może być używana z rmapshaper::ms_simplify()lub rgeos::gSimplify(). Dzieki za sugestie!
Phil
Fajne fajne, pamiętaj tylko, że topologia blokujących się wielokątów jest naprawdę zachowana tylko dzięki podejściu rmapshaper. Jeśli wszystkie twoje dane wejściowe są odizolowanymi, nie zazębiającymi się wielokątami, możesz bezpiecznie użyć dowolnego z dostępnych alg uproszczenia.
obrl_soil
Przyjmuję to jako odpowiedź, ponieważ bardziej kanoniczny sf::st_simplify()nie jest solidny przy wysokich tolerancjach w momencie pisania, chociaż oczywiście może się to zmienić.
Phil
8
Obecnie pracuję nad obsługą sfobiektów w rmapshaper . ms_simplifyjest dostępny dla sfobiektów w wersji rozwojowej. Chciałbym wczesnych testerów - jeśli chcesz to wypróbować, możesz zainstalować zdevtools::install_github("ateucher/rmapshaper", ref = "sf")
andyteucher
6
Począwszy od rmapshaperwersji 0.3.0, wywołanie do as( , "Spatial")nie jest już wymagane.
Łukasz 1018