Simplifier les polygones de l'objet sf

14

Comment simplifier un sfpolygone sans introduire d'écarts et de rubans?

Avec un fichier de formes, par exemple, j'utiliserais 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

J'ai essayé sf::st_cast()ce qui, à partir des pages de manuel, déclare:

Transformer la géométrie en un autre type: simplifier ou convertir explicitement

et:

à l'argument: caractère; type cible, s'il est manquant, une simplification est tentée; lorsque x est de type sfg (c'est-à-dire une seule géométrie), alors to doit être spécifié.

Quand j'ai laissé tocomme manquant, cela n'a pas fonctionné comme prévu (je savais que c'était trop beau pour être vrai!):

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

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

Actuellement, j'ouvre le fichier avec rgdal::readOGR(), le simplifie, l'enregistre, puis le charge à nouveau avec sf.

Y a-t-il une meilleure façon?


rgeos::gSimplify()

La suggestion de @sk de rgeos::gSimplify()peut effectuer des simplifications tenant compte de la topologie (c'est-à-dire simplifie sans créer de fragments) lorsqu'elle est spécifiée avec les arguments suivants:

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

gSimplifyne conserve pas le @datacadre, nous devons donc le recréer:

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

Et cela entraîne en effet une taille de fichier plus petite (peut modifier l' tolargument pour le réduire) et j'ai confirmé que cela n'avait créé aucun éclat en l'examinant dans QGIS.

object_size(regions_gSimplify)
# ~8MB

Donc, bien que ce soit une alternative valable, rmapshaper::ms_simplify()j'ai toujours le même problème, à savoir qu'il ne fonctionne pas avec 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"

La réponse de @obrl_soil peut également être appliquée gSimplify(), utilisez-la simplement à la place de ms_simplify().

Phil
la source
1
Avez-vous accès à un algorithme Douglas-Peucker? Il est largement connu pour la simplification des fonctionnalités dans le monde SIG. stackoverflow.com/questions/17217413/… & r-bloggers.com/simplifying-spatial-polygons-in-r
sk
1
N'est-ce pas st_simplifycensé faire ça? (pas encore utilisé)
lbusett
2
ooh, je ne l'avais pas remarqué st_simplify, merci de l'avoir signalé. Je préfère l'algorithme par rmapshaper::ms_simplifydéfaut à tous les autres que j'ai essayés jusqu'à présent, mais je vais jouer avec la nouvelle option (mise à jour: whoa procéder avec prudence, preserveTopology = TRUEne fonctionne certainement pas encore correctement)
obrl_soil
1
Bon à savoir. Qu'en est-il de l'ouverture d'un rapport de bug à ce sujet?
lbusett
1
@obrl_soil Cela fonctionne pour des tolérances jusqu'à environ 1000 sur les polygones que j'ai utilisés dans la question ( regions) mais au-delà, il ne préserve plus la topologie. Comme il se casse à un certain point, je dirais que ce n'est pas un comportement voulu
Phil

Réponses:

16

Vous pouvez convertir un objet sf en sp, pour les packages qui ne prennent pas encore en charge sf - je le fais un peu pour les interactions raster / polygone. Vous pourriez donc faire:

simplepolys <- rmapshaper::ms_simplify(input = as(sfobj, 'Spatial')) %>%
  st_as_sf()
obrl_soil
la source
1
Cette technique - coulée en tant qu'objet spatial, simplification, puis refonte en tant sfqu'objet - fonctionnait parfaitement et peut être utilisée avec rmapshaper::ms_simplify()ou rgeos::gSimplify(). Merci pour la suggestion!
Phil
Cool cool, sachez que la topologie des polygones imbriqués n'est vraiment préservée qu'avec l'approche de rmapshaper. Si vos données d'entrée sont toutes des polygones isolés et non imbriqués, vous pouvez utiliser en toute sécurité n'importe laquelle des algs de simplification disponibles.
obrl_soil
J'accepte cela comme la réponse parce que le plus canonique sf::st_simplify()n'est pas robuste à des tolérances élevées au moment de la rédaction, bien que cela puisse évidemment changer.
Phil
8
Je travaille actuellement sur le support des sfobjets dans rmapshaper . ms_simplifyest disponible pour les sfobjets dans la version de développement. J'adorerais les premiers testeurs - si vous voulez l'essayer, vous pouvez installer avecdevtools::install_github("ateucher/rmapshaper", ref = "sf")
andyteucher
6
Depuis la rmapshaperversion 0.3.0, l'appel à as( , "Spatial")n'est plus requis.
Luke1018