Porcentagem de polígono em um shapefile dentro do polígono de outro

13

Sou novato, peço desculpas se isso for óbvio / já foi solicitado e respondido, mas não consegui encontrar nada.

Eu tenho dois arquivos de forma: 1. uma camada de limite administrativo para um condado do Reino Unido conhecido como limite de LSOA que possui 500 pequenas zonas 2. uma zona de inundação.

Idealmente, quero descobrir quais das pequenas zonas LSOA estão ≥50% dentro da zona de inundação e terminam com sim / não ou 1/0 para cada uma das 500 zonas LSOA.

Mas eu não sei como fazer isso. Imaginei que poderia juntar os dois shapefiles, mas não há atributo comum entre eles. Então pensei que poderia usar a função Join Attribute by Location, que funcionou e me mostrou quais LSOA estão na zona de inundação, mas são quase todas elas (veja a imagem 2).

Eu acho que isso é um problema de SQL, mas não sei. Eu sou novo no QGIS e nunca usei o PostgreSQL.

Qualquer ajuda seria muito apreciada. Posso fornecer qualquer informação que vocês, pessoas adoráveis, precisem para me ajudar.

insira a descrição da imagem aqui

insira a descrição da imagem aqui

KJGarbutt
fonte

Respostas:

11

Essa é uma tarefa relativamente simples, usando as ferramentas de geoprocessamento incluídas no QGIS.

  1. Calcule a área das suas zonas LSOA.

    • Abra a tabela de atributos da camada LSOA.
    • Ative o modo de edição.
    • Abra a calculadora de campo.
    • Crie um novo campo do tipo "Número decimal (real)" com a expressão "$ area".
    • Desative o modo de edição (salvando edições).
  2. Mesclar a camada da zona de inundação em um único recurso de várias partes.

    • Vector > Geometry Tools > Singleparts to Multipart.
    • Selecione "--- Mesclar tudo ---" para o campo ID exclusivo.
  3. Interseja a camada da zona LSOA com a camada da zona de inundação multipartes.

    • Vector > Geoprocessing Tools > Intersect.
    • Camada de entrada são as zonas LSOA, camada de interseção são as zonas de inundação.
  4. A camada resultante será as partes das zonas LSOA (com os atributos da camada de zonas LSOA) que se sobrepuseram à camada das zonas de inundação. Para calcular a proporção de cada zona LSOA dentro de uma zona de inundação:

    • Calcule a área dos recursos cruzados (como na etapa 1) e, em seguida,
    • Adicione outro campo, dividindo a área original (total) pela área cruzada. O resultado é um decimal entre 0 e 1. Multiplique por 100 para obter uma porcentagem.
  5. Associe a camada LSOA original à camada cruzada, usando o ID exclusivo compartilhado pelas duas camadas.

  6. Exporte a camada unida como um novo shapefile.

  7. Exclua os atributos duplicados.

Et voilà!

Sem a etapa 2, um recurso individual seria criado para cada recurso de zona de inundação diferente para cada recurso LSOA. Provavelmente, isso não é o que você deseja se estiver interessado apenas na cobertura total de cada zona LSOA. Se você quiser diferenciar entre inundação fluvial / de maré / pluvial (e os dados da zona de inundação suportam isso), poderá converter partes únicas em multipartes, especificando o campo "TYPE" como o campo Unique ID.

Snorfalorpagus
fonte
Obrigado pela ajuda! Muito apreciado. No entanto, estou tendo alguns problemas. Eu segui os passos. A Etapa 3, o Intersect, levou 10 horas para ser concluída e, quando tudo foi concluído, tudo o que recebi foi um shapefile vazio: i.imgur.com/QIM6Gtg.png Há algo que eu perdi? Tentei concluir o processo e executar a etapa 4, mas não há dados para calcular a área de interseção.
KJGarbutt
Eu tive problemas para fazer cruzamentos com camadas de inundação antes. Os recursos são grandes e complicados. A maneira como trabalhei com isso no passado é dividi-los em recursos menores, para que o índice espacial possa fazer mais do trabalho. Para fazer isso, crie uma grade vetorial da mesma extensão que a camada de inundação ( Vector > Research Tools > Vector Grid... Output grid as polygons) e intercepte a grade com a camada de inundação. Em seguida, use a saída em vez da camada de inundação na etapa 3. Acho que a razão pela qual a camada estava vazia é porque ela travou.
Snorfalorpagus
Obrigado novamente. O único problema agora é que o QGIS trava toda vez que tento criar a grade de vetores. Segui o conselho daqui, mas ele falha sempre. Alterei os parâmetros várias vezes e tentei usar apenas o shapefile da zona de inundação, em vez de abrir todo o arquivo do projeto e falhar sempre. Alguma ideia? ! Captura de tela aqui .
KJGarbutt
Os parâmetros X e Y que você especificou são muito pequenos. Tente algo como 1000 x 1000. Você pode fazer isso várias vezes, ou seja, faça 5000 x 5000 primeiro, use a saída para criar 500 x 500. Consulte a resposta relacionada aqui: gis.stackexchange.com/a/66319/12420
Snorfalorpagus
Eu quase rachei com a sua ajuda! No entanto, quando vou ingressar na camada LSOA original com a camada cruzada, perco muitos dados. Eu acho que é porque alguns dos quadrados da grade vetorial criados se enquadram na mesma área LSOA e, portanto, têm o mesmo código LSOA de cada um. Assim, acabo com mais de 2% de porcentagem para cada área da LSOA quando faço a junção e pareço obter apenas uma delas. Existe uma maneira de somar cada porcentagem para cada quadrado de grade vetorial com o mesmo LSOA?
KJGarbutt
6

Você pode usar spatialite e algumas funções SQL espaciais.

Select t1.geometry, t1.ID, area(t1.geometry), area(t2.geometry) ...... (anything you need to have in the table results)

(area(intersection(t1.geometry,t2.geometry))) as "Commun_AREA"

, ("Commun_AREA"*100/(area(t1.geometry))) as "Percent_AREA"

From lsoa as t1, flood_zone as t2

Where Intersects( t1.geometry,t2.geometry ) = 1
Cyrille
fonte
3

Parece algo que poderia ser feito muito mais fácil do que as respostas enviadas. Eu usaria um script python simples pessoalmente:

floodName = "the layer name here"
boundryName = "the layer name here"
fieldName = "the name of the field to contain the output 1/0"
minCoverage = 0.5 # the minimum amount of area covered to write 1
updateMap = [] # this will store values to be written    

# get layers
floodLayer = QgsMapLayerRegistry.instance().mapLayersByName(floodName)[0]
boundryLayer = QgsMapLayerRegistry.instance().mapLayersByName(boundryName)[0]
fieldIndex = boundryLayer.dataProvider().fieldNameIndex(fieldName)    

# iterate through boundries
for b in boundryLayer.getFeatures():
    # get only flood features that intersect with this feature's bounding box
    # this will make the script go way faster than it would otherwise
    request = QgsFeatureRequest().setFilterRect(b.geometry().boundingBox())
    floodGeom = geometry()
    floodFeat = QgsFeature()
    iter = floodLayer.getFeatures(request)
    iter.nextFeature(feat)
    while iter.nextFeature(feat):
        floodGeom = floodGeom.combine(feat.geometry())
    intersectGeom = b.geometry().intersection(feat.geometry())
    if intersectGeom.area() > minCoverage * b.geometry().area():
        updateMap[b.id()] = {fieldIndex : 1}
    else:
        updateMap[b.id()] = {fieldIndex : 0}

boundryLayer.dataProvider().changeAttributeValues(updateMap)

isso avalia apenas os polígonos de inundação que se cruzam com a caixa delimitadora de cada camada de delimitação, para que seja bastante rápido de executar e atualiza apenas um campo na camada existente (em vez de uma operação complexa de criar uma camada totalmente nova e copiar valores antigos excluindo)

Jesse McMillan
fonte
2

Eu tive o mesmo problema que KJ, seguindo as instruções de Snorfalorpagus, usando o método "Intersect" na Etapa 3. Demorou um pouco para calcular e o que me restou ficou em branco.

Tentei seguir as mesmas etapas, exceto usando o método "Clip" no QGIS em vez de Intersect - portanto, no seu exemplo, o que restaria seriam as partes das áreas que NÃO são cobertas pela zona de inundação. Isso pareceu funcionar por algum motivo e eu pude usar o cálculo do campo "Área" da etapa anterior, além de um novo cálculo de "Área" nas partes restantes de cada polígono, para descobrir a% de cada área que NÃO era coberto pela outra camada de polígono.

Isso é tecnicamente o contrário do que você pediu. Mas a partir daí é apenas uma questão de subtrair cada valor de 1 para obter o que é coberto pela zona de inundação.

muckraker
fonte