Reparando orifícios órfãos em R

18

Estou tentando realizar uma união em um campo comum após mesclar dois shapefiles adjacentes. Os arquivos de forma acabam com pelo menos um pedaço fino de espaço entre eles. Quando tento uma união, recebo o seguinte erro de orfão órfão:

Erro no createPolygonsComment (p): rgeos_PolyCreateComment: furo órfão, não é possível encontrar o polígono que contém o furo no índice 17

Fiz upload de um exemplo reproduzível para o Dropbox neste link .

Aqui está o código para recriar o 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)

Devoluções:

Erro no createPolygonsComment (p): rgeos_PolyCreateComment: furo órfão, não é possível encontrar o polígono que contém o furo no índice 17

Tentando a correção proposta aqui e aqui :

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

Isso retorna o mesmo erro que vem da tentativa de união, mas com número de índice diferente:

rgeos_PolyCreateComment: furo órfão, não é possível encontrar o polígono que contém o furo no índice 30

Tentando a correção proposta no útil tutorial de Roger Bivand

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

Retorna o mesmo erro no índice 30 como acima.

Outros têm levantado este problema aqui e aqui , e enquanto as soluções postuladas acima parecem funcionar para alguns casos, outros casos não são resolvidos. Um usuário usou o QGIS para solucionar o problema, e o outro teve 2 dos 3 itens corrigidos, mas nenhuma solução para o final.

Parece que as pessoas continuam tendo problemas, apesar desse código funcionar periodicamente. Alguém encontrou uma solução no R?

Eu executei a ferramenta "reparar geometria" no ArcGIS e corrigiu o problema, mas parece que deve haver uma correção no R.

Luke Macaulay
fonte
Sem seus dados, é difícil dizer onde está o problema.
@ Pascal, acabei de enviar um link do dropbox com um shapefile reduzido de 10mb compactado e 16mb descompactado, que reproduzirá o problema. Eu não tinha certeza de como fornecer os dados, pois o original era de 1,5 GB, mas consegui usar o ArcGIS para restringir o problema a um arquivo menor. Existe um bom protocolo para criar e compartilhar exemplos reproduzíveis de tamanho gerenciável?
Luke Macaulay
Tentar diferentes abordagens com R não funcionou. E o Qgis está congelando ao verificar geometrias.

Respostas:

25

Analisei os problemas de geometria nos dados anexados e parece que ele não tem SOMENTE, orphaned holesmas também geometry validity issues. É verdade que um orphaned holeé de alguma forma um problema de validade da geometria, mas o rgeos não lida com o mesmo problema, pois para orfãos órfãos, um erro é gerado, em vez de um simples aviso. Como você indica, são dicas para verificar orifícios de polígonos, mas nem sempre são bem-sucedidos quando aplicados para corrigir orifícios órfãos.

Então vamos:

  1. limpe seus dados (o que é necessário se você deseja fazer geoprocessamento como união)

  2. use os dados limpos com seu processo de união

1. Geometria de limpeza Às vezes, as geometrias de fixação no R podem ser um desafio, por isso tentei criar um pacote R experimental (consulte https://github.com/eblondel/cleangeo ) que pretende facilitar a limpeza de spobjetos (atualmente limitado a formas poligonais). Você pode instalar o pacote com:

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

Para começar, é bom que você veja quais são os problemas de geometria com seus dados de origem. Para isso, você pode executar o seguinte (seus dados são grandes e podem levar algum tempo):

#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,]

Com isso, você verá que seus dados têm 2 tipos de problemas: orphaned holese geometry validity issues. É provável que ambos (e não apenas os orfãos órfãos) façam com que o unionprocesso falhe; portanto, os dados devem ser limpos antes, de maneira automatizada, quando possível. Para uma reprodução rápida, o primeiro código de exemplo abaixo leva apenas o subconjunto de recursos que são marcados como suspeitos (exceto o mais recente, com índice = 9002 nos dados originais - veja minha nota abaixo)

#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)

Se clgeo_Cleano trabalho for bom, você deve obter todas as geometrias válidas agora. Você pode aplicar isso ao conjunto de dados completo (exceto o índice de recursos = 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. Processo de união Agora, vamos ver se unionfunciona neste conjunto de dados:

#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 dito anteriormente, removi um recurso (índice = 9002). Ao plotá-lo:, plot(sp[9002,])você verá que esse recurso é muito (muito) complexo. Eu o excluí da amostra apenas porque a verificação de buracos estava demorando muito. Vamos ver agora se o mesmo problema ocorre usando readShapePoly(de maptools) para ler os dados ...

3. Alterne para readShapePoly vs. readOGR para ler dados (UPDATE)

readOGRnão é a única função disponível para ler shapefiles. Você também pode usar readShapePolydo maptoolspacote, geralmente com melhor desempenho que o primeiro:

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

Além de correr mais rápido:

  • se você usar o código acima com base em clgeo_CollectionReport, não há problema de orfãos órfãos, mas ainda problemas de geometria.

  • A limpeza da geometria clgeo_Cleantambém funciona bem e agora não fica presa ao índice de recursos 9002

  • E ... o processo de união funciona.

Veja abaixo o resultado da plotagem:

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

Resultado da união

Conclusão : prefira maptools para ler seus dados do shapefile e considere usar o cleangeo para limpar seus dados antes de qualquer geoprocessamento.

eblondel
fonte
Obrigado eblondel! Eu vou tentar isso. Obrigado pelo desenvolvimento do pacote!
Luke Macaulay
Oi eblondel, Isso funcionou bem, mas eu queria que você soubesse que, ao corrigir a geometria, muitas vezes criava um polígono muito grande ao lidar com recursos complexos e complexos. Por exemplo, uma rede rodoviária foi corrigida para um grande polígono que era basicamente a extensão da rede. Não sei ao certo como é fácil corrigir isso, mas queria que você soubesse.
Luke Macaulay
Uau. Pacote muito impressionante. Isso deve ter sido muito trabalhoso.
nograpes
3
Obrigado @nograpes pelo seu feedback. Criei este pacote do zero quando esse problema foi publicado, também porque a limpeza de geometrias nem sempre é uma tarefa fácil. Se você estiver no Github, eu gostaria de receber sua 'estrela' :-), gostaria de melhorar ainda mais o pacote no futuro, e possivelmente lançá-lo no CRAN.
eblondel
7
Apenas para informar que o cleangeo foi publicado no CRAN ( cran.r-project.org/package=cleangeo ), para todas as pessoas que o usam, fique à vontade para relatar solicitações ou erros de aprimoramento no Github.
eblondel
1

Uma solução conveniente que continua trabalhando para mim no R é aplicar um buffer de largura zero :

#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 leva um tempo com esse conjunto de dados, mas parece funcionar muito bem.

fgg
fonte