Simplificar polígonos do objeto sf

14

Como simplifico um sfpolígono sem introduzir espaços e lascas?

Com um shapefile, por exemplo, eu usaria 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

Eu tentei o sf::st_cast()que, nas páginas de manual, afirma:

Transmitir geometria para outro tipo: simplificar ou converter explicitamente

e:

argumentar: personagem; tipo de destino, se ausente, a simplificação é tentada; quando x é do tipo sfg (ou seja, uma única geometria), deve ser especificado.

Quando deixei tocomo falta, isso não funcionou como esperado (eu sabia que era bom demais para ser verdade!):

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

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

Atualmente, estou abrindo o arquivo rgdal::readOGR(), simplificando-o, salvando-o e carregando-o novamente com sf.

Existe uma maneira melhor?


rgeos::gSimplify()

A sugestão de @sk rgeos::gSimplify()pode fazer simplificações com reconhecimento topológico (isto é, simplifica sem criar lascas) quando especificada com os seguintes argumentos:

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

gSimplifynão preserva o @dataquadro, portanto, devemos recriá-lo:

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

E isso realmente resulta em um tamanho de arquivo menor (pode alterar o tolargumento para diminuí-lo) e eu confirmei que isso não havia criado lascas ao examiná-lo no QGIS.

object_size(regions_gSimplify)
# ~8MB

Portanto, embora essa seja uma alternativa válida, rmapshaper::ms_simplify()ainda tenho o mesmo problema, a saber, que não funciona com 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"

A resposta do @obrl_soil também pode ser aplicada gSimplify(), basta usá-la no lugar de ms_simplify().

Phil
fonte
1
Você tem acesso a um algoritmo Douglas – Peucker? É amplamente conhecido pela simplificação de recursos no mundo GIS. stackoverflow.com/questions/17217413/… & r-bloggers.com/simplifying-spatial-polygons-in-r
sk
1
Não st_simplifydeveria fazer isso? (não usá-lo, até o momento)
lbusett
2
ooh, eu não tinha notado st_simplify, obrigado por apontar. Eu prefiro o algoritmo que o rmapshaper::ms_simplifypadrão é sobre todos os outros que eu tentei até agora, mas vou jogar com a nova opção (atualização: whoa prossiga com cautela, preserveTopology = TRUEdefinitivamente ainda não funciona corretamente)
obrl_soil
1
Bom saber. Que tal abrir um relatório de bug sobre isso?
lbusett
1
@obrl_soil Ele funciona para tolerâncias de até 1000 nos polígonos que usei na pergunta ( regions), mas além disso não preserva mais a topologia. Como ele quebra em um certo ponto eu diria que o comportamento não se destina
Phil

Respostas:

16

Você pode converter um objeto sf em sp, para pacotes que ainda não suportam sf - eu faço isso bastante para interações raster / polígono. Então você poderia fazer:

simplepolys <- rmapshaper::ms_simplify(input = as(sfobj, 'Spatial')) %>%
  st_as_sf()
obrl_soil
fonte
1
Essa técnica - moldar como um objeto espacial, simplificar e depois moldar novamente como um sfobjeto - funcionou perfeitamente e pode ser usada com rmapshaper::ms_simplify()ou rgeos::gSimplify(). Obrigado pela sugestão!
Phil
Legal, lembre-se de que a topologia dos polígonos interligados só é realmente preservada com a abordagem do rmapshaper. Se seus dados de entrada forem todos polígonos isolados e sem intertravamento, você poderá usar com segurança qualquer um dos algs de simplificação disponíveis.
obrl_soil
Estou aceitando isso como a resposta, porque o mais canônico sf::st_simplify()não é robusto com altas tolerâncias no momento da redação, embora obviamente isso possa mudar.
Phil
8
Atualmente, estou trabalhando no suporte a sfobjetos no rmapshaper . ms_simplifyestá disponível para sfobjetos na versão de desenvolvimento. Eu adoraria primeiros testadores - se você quiser experimentá-lo, você pode instalar comdevtools::install_github("ateucher/rmapshaper", ref = "sf")
andyteucher
6
A partir da rmapshaperversão 0.3.0, a chamada para as( , "Spatial")não é mais necessária.
101110 Luke1018