Arreglando agujeros huérfanos en R

18

Estoy tratando de realizar una unión en un campo común después de fusionar dos archivos de forma adyacentes. Los archivos de forma terminan con al menos una delgada franja de espacio entre ellos. Cuando intento una unión me sale el siguiente error de orfandad:

Error en createPolygonsComment (p): rgeos_PolyCreateComment: agujero huérfano, no se puede encontrar el polígono que contiene el agujero en el índice 17

He subido un ejemplo reproducible a Dropbox en este enlace .

Aquí está el código para recrear el problema:

#loading required packages
require(sp)    
require(rgdal)
require(maptools)
require(rgeos)

#load example data, set "dsn=" to your working directory or specify the path
example <- readOGR(dsn=".",layer="ReproducibleExample")

#Attempting a UnionSpatialPolygons based on the COUNTY field
example.df <- as(example, "data.frame")
countycol <- example.df$COUNTY
example.diss <- unionSpatialPolygons(example, countycol)

Devoluciones:

Error en createPolygonsComment (p): rgeos_PolyCreateComment: agujero huérfano, no se puede encontrar el polígono que contiene el agujero en el índice 17

Probar la solución propuesta aquí y aquí :

slot(example, "polygons") <- lapply(slot(example, "polygons"), checkPolygonsHoles)

Esto devuelve el mismo error que proviene del intento de unión pero con un número de índice diferente:

rgeos_PolyCreateComment: agujero huérfano, no se puede encontrar el polígono que contiene el agujero en el índice 30

Probar la solución propuesta en el útil tutorial de Roger Bivand

fix <- slot(example, "polygons")
fixa <- lapply(fix, checkPolygonsHoles)

Devuelve el mismo error en el índice 30 que el anterior.

Otros han planteado este problema aquí y aquí , y si bien las soluciones presentadas anteriormente parecen funcionar para algunos casos, otros casos no se resuelven. Un usuario usó QGIS para abordar el problema, y ​​el otro tenía 2 de 3 elementos corregidos, pero no había una resolución para el último.

Parece que las personas continúan teniendo problemas a pesar de que este código funciona de vez en cuando. ¿Alguien ha encontrado una solución dentro de R?

He realizado la herramienta "reparar geometría" en ArcGIS, y corrigió el problema, pero parece que debería haber una solución en R.

Luke Macaulay
fuente
Sin sus datos, es difícil decir dónde está el problema.
@Pascal, acabo de subir un enlace de Dropbox con un archivo de forma reducido de 10 MB con cremallera y 16 MB sin comprimir que reproducirá el problema. No estaba seguro de cómo proporcionar los datos, ya que el original era de 1,5 gb, pero logré usar ArcGIS para reducir el problema a un archivo más pequeño. ¿Existe un buen protocolo para crear y compartir ejemplos reproducibles de tamaño manejable?
Luke Macaulay
Intentar diferentes enfoques con R no funcionó. Y Qgis se congela al verificar geometrías.

Respuestas:

25

He analizado los problemas de geometría en los datos adjuntos, y parece que SÓLO no tiene orphaned holessino también geometry validity issues. Es cierto que de orphaned holealguna manera es un problema de validez de geometría, pero rgeos no lo maneja de la misma manera, ya que para agujeros huérfanos, se genera un error, en lugar de una simple advertencia. Como indica, son sugerencias para verificar los agujeros de polígono, pero no siempre es exitoso cuando se aplica para reparar agujeros huérfanos.

Entonces vamos:

  1. limpie sus datos (que es necesario si desea realizar un geoprocesamiento como union)

  2. use los datos limpios con su proceso de unión

1. Geometría de limpieza La fijación de geometrías en R a veces puede ser un desafío, por lo que he intentado construir un paquete R experimental (consulte https://github.com/eblondel/cleangeo ) que tiene la intención de facilitar la limpieza de spobjetos (ahora limitado en formas poligonales). Puede instalar el paquete con:

require(devtools)
install_github("eblondel/cleangeo")
require(cleangeo)

Para comenzar, es bueno que vea cuáles son los problemas de geometría con sus datos de origen. Para esto, puede ejecutar lo siguiente (sus datos son grandes, por lo que puede llevar algo de tiempo):

#get a report of geometry validity & issues for a sp spatial object
report <- clgeo_CollectionReport(sp)
summary <- clgeo_SummaryReport(report)
issues <- report[report$valid == FALSE,]

Con esto, verá que sus datos tienen 2 tipos de problemas: orphaned holesy geometry validity issues. Es probable que ambos (y no solo los agujeros huérfanos) hagan que el unionproceso falle, por lo que los datos deben limpiarse antes, de forma automática cuando sea posible. Para una reproducción rápida, el primer código de muestra a continuación solo toma el subconjunto de características etiquetadas como sospechosas (excepto la última, con índice = 9002 en los datos originales; consulte mi nota a continuación sobre esto)

#get suspicious features (indexes)
nv <- clgeo_SuspiciousFeatures(report)
mysp <- sp[nv[-14],]

#try to clean data
mysp.clean <- clgeo_Clean(mysp, print.log = TRUE)

#check if they are still errors
report.clean <- clgeo_CollectionReport(mysp.clean)
summary.clean <- clgeo_SummaryReport(report.clean)

Si clgeo_Cleanhace bien el trabajo, debería obtener todas las geometrías válidas ahora. Puede aplicar esto al conjunto de datos completo (excepto el índice de características = 9002)

#try to clean data
mysp <- sp[-9002,]
mysp.clean <- clgeo_Clean(mysp, print.log = TRUE)

#check if they are still errors
report.clean <- clgeo_CollectionReport(mysp.clean)
summary.clean <- clgeo_SummaryReport(report.clean)

2. Proceso de unión Ahora, veamos si unionfunciona en este conjunto de datos:

#Attempting a UnionSpatialPolygons based on the COUNTY field
mysp.df <- as(mysp, "data.frame")
countycol <- mysp.df$COUNTY
mysp.diss <- unionSpatialPolygons(mysp.clean, countycol)

Nota: como se dijo antes, eliminé una característica (índice = 9002). Al trazarla plot(sp[9002,]), verá que esta característica es muy (muy) compleja. Lo he excluido de la muestra solo porque verificar los agujeros tomaba demasiado tiempo. Veamos ahora si ocurre el mismo problema usando readShapePoly(from maptools) para leer los datos ...

3. Cambie a readShapePoly vs. readOGR para leer datos (ACTUALIZACIÓN)

readOGRno es la única función disponible para leer archivos de forma. También puede usar readShapePolydesde el maptoolspaquete, generalmente más eficiente que el primero:

require(maptools)
mysp <- readShapePoly("ReproducibleExample.shp")

Además de correr más rápido:

  • Si utiliza el código anterior basado en clgeo_CollectionReport, no hay problema de agujeros huérfanos, pero sí problemas de geometría.

  • La limpieza de la geometría clgeo_Cleantambién funciona bien, y ahora no se atasca con el índice de características 9002

  • Y ... el proceso sindical funciona.

Vea a continuación el resultado de la trama:

#plot the result
plot(mysp, border= "lightgray")
plot(mysp.diss, border="red", add = TRUE)

Resultado de la unión

Conclusión : prefiera maptools para leer sus datos de shapefile, y considere usar cleangeo para limpiar sus datos antes de cualquier geoprocesamiento.

eblondel
fuente
Gracias eblondel! Probaré esto. ¡Gracias por el desarrollo del paquete!
Luke Macaulay
Hola, Eblondel: Esto funcionó bien, pero quería hacerle saber que al corregir la geometría, a menudo crearía un polígono muy grande cuando se trata de características complejas y complejas. Por ejemplo, una red de carreteras se corrigió a un gran polígono que era básicamente el alcance de la red. No estoy seguro de lo fácil que es corregirlo, pero quería hacerle saber.
Luke Macaulay
Guau. Paquete muy impresionante. Eso debe haber sido mucho trabajo.
nograpes
3
Gracias @nograpes por sus comentarios. Construí este paquete desde cero cuando se publicó este problema, también porque limpiar geometrías no siempre es una tarea fácil. Si está en Github, agradecería su 'estrella' :-), me gustaría mejorar aún más el paquete en el futuro y posiblemente lanzarlo en CRAN.
eblondel
77
Solo para hacerle saber que cleangeo ha sido publicado en CRAN ( cran.r-project.org/package=cleangeo ), para todas las personas que lo usan, pueden informar sobre solicitudes de mejora o errores en Github.
eblondel
1

Una solución conveniente que sigue funcionando para mí en R es aplicar un búfer de ancho cero :

#loading required packages
require(sp)    
require(rgdal)
require(maptools)
require(rgeos)

#load example data, set "dsn=" to your working directory or specify the path
example <- readOGR(dsn=".",layer="ReproducibleExample")

#project your data (I'm using California Albers here) and apply a zero-width buffer
example <- spTransform(example, CRS("+init=epsg:3310"))
example <- gBuffer(example, byid = T, width = 0)

#Attempting a UnionSpatialPolygons based on the COUNTY field
example.df <- as(example, "data.frame")
countycol <- example.df$COUNTY
example.diss <- unionSpatialPolygons(example, countycol)

unionSpatialPolygons lleva un tiempo con este conjunto de datos, pero parece funcionar bien.

fgg
fuente