Calcular área dentro do script Python no ArcMap

14

Estou tentando calcular a área de um polígono dentro do meu script Python. Crio um novo polígono a partir da mesclagem de dois e gostaria de adicionar a área do polígono resultante a um campo no arquivo de saída. O polígono é armazenado em um arquivo de forma regular e é projetado. Área preferencialmente em unidades de mapa.

Eu pensaria que essa é uma tarefa bastante comum e simples, mas apesar de muito Googleing, não consegui encontrar soluções funcionais até agora.

Eu estava pensando em usar arcpy.updateCursorpara inserir o valor uma vez calculado (há apenas um recurso no FC neste estágio), então é mais fácil se ele pode ser retornado como uma variável. Qualquer solução alternativa que realize a mesma tarefa (colocar o valor da área no campo correto) também funcionará.

Eu também tentei a calculadora de campo do Python. Modificado nas páginas de ajuda, pensei que o seguinte funcionaria, mas até agora não houve sorte.

arcpy.AddField_management(tempPgs, "Shape_area", 'DOUBLE')
exp = "float(!SHAPE.AREA!.split())"
arcpy.CalculateField_management(tempPgs, "Shape_area", exp)

Executando o ArcGIS Basic 10.1 SP1 com Python 2.7 no Windows 7.

Partes relevantes do meu código atual são assim:

#/.../
arcpy.Copy_management(inpgs, outpgs)
arcpy.AddField_management(outpgs, 'Shape_area', 'LONG')
fields = AM.FieldLst(outpgs)

#/.../

# Identify and search for shapes smaller than minimum area
where1 = '"' + 'Shape_Area' + '" < ' + str(msz)
polyrows = arcpy.SearchCursor(inpgs, where1)

for prow in polyrows:
    grd1 = prow.GridID   # GridID on the current polygon
    grd2 = nDD.get(grd1) # GridID on the polygon downstream

    # Update features
    if grd2
        geometry1 = prow.Shape
        geometry2 = geometryDictionary[grd2]

        # Update temporary features
        arcpy.Merge_management([geometry1, geometry2], tempMerged)
        arcpy.Dissolve_management(tempMerged, tempPgs)

        fds = AM.FieldLst(tempPgs)

        for field in fields[2:]:
            arcpy.AddField_management(tempPgs, field, 'DOUBLE')

        for fd in fds[2:]:
            arcpy.DeleteField_management(tempPgs, fd)

        exp = "float(!SHAPE.AREA!.split())"
        arcpy.CalculateField_management(tempPgs, "Shape_area", exp)

        # Append them to output FC
        try:
            arcpy.Append_management(tempPgs, outpgs, "TEST")
        except arcgisscripting.ExecuteError:
            arcpy.Append_management(tempPgs, outpgs, "NO_TEST")

    elif ...

    else ...
Martin
fonte
Qual é o seu tipo de saída? Shapefile, geodatabase de arquivo, outra coisa? O seu arquivo de saída é projetado ou não?
Black-castillo
Além disso, você poderia postar um pouco mais do exemplo de código, em particular o cursor que você está usando para fazer a atualização? Provavelmente, você pode conseguir o que deseja usando SHAPE@AREAcomo parte do seu cursor para ler a área; mas a estrutura do código depende se sua área está nas mesmas unidades que você deseja escrever.
Blord-castillo

Respostas:

29

Existem três maneiras diferentes de encontrar e armazenar a área de polígono em uma classe de recurso com arcpy: 1) calculadora de campo, 2) cursores arcpy "clássicos" e 3) arcpy.dacursores. Parte disso é emprestada da minha resposta anterior sobre o uso do SearchCursor .


1. Calculadora de campo

  • Ao usar a calculadora de campo, existem três tipos de expressão diferentes que usam analisadores de expressão diferentes. Isso é especificado no terceiro parâmetro da ferramenta de geoprocessamento Calculate Field . Ao acessar as propriedades do objeto Geometry usando like in !shape.area!, você deve usar o analisador Python 9.3.

  • A expressão que você tinha antes executou um split()comando no resultado de !SHAPE.AREA!. Isso retorna um listobjeto Python , que não pode ser convertido em um floatobjeto.

  • Na sua expressão, você pode especificar a unidade da área retornada usando o @SQUAREKILOMETERSsinalizador, substituindo SQUAREKILOMETERSpelas unidades na página de ajuda Calcular Campo .

Aqui está o código Python que eu usaria para este método:

tempPgs = "LayerName"
arcpy.AddField_management(tempPgs, "Shape_area", "DOUBLE")
exp = "!SHAPE.AREA@SQUAREKILOMETERS!"
arcpy.CalculateField_management(tempPgs, "Shape_area", exp, "PYTHON_9.3")

2. Arco 10.0 - cursores "clássicos"

  • Ao usar cursores clássicos (ou seja arcpy.UpdateCursor), o objeto cursor é um objeto iterável que contém rowobjetos. Você precisa usar os métodos getValuee setValuepara obter a geometria da linha (como um objeto de geometria e definir o valor da área rowcomo flutuador.

  • Sua linha de saída é armazenada em um espaço temporário temporário até você chamar o updateRowmétodo no cursor. Isso salva os novos dados no conjunto de dados real.

Aqui está o código Python que eu usaria para este método:

tempPgs = "LayerName"
arcpy.AddField_management(tempPgs, "Shape_area", "DOUBLE")
geometryField = arcpy.Describe(tempPgs).shapeFieldName #Get name of geometry field
cursor = arcpy.UpdateCursor(tempPgs)
for row in cursor:
    AreaValue = row.getValue(geometryField).area #Read area value as double
    row.setValue("Shape_area",AreaValue) #Write area value to field
    cursor.updateRow(row)
del row, cursor #Clean up cursor objects

3. Arco 10.1 - cursores do arcpy.da

  • Ao usar os novos cursores no módulo de acesso a dados (ou seja arcpy.da.UpdateCursor), é necessário passar uma lista de nomes de campos como o segundo parâmetro no construtor do cursor. Isso requer mais trabalho inicial, mas os rowobjetos resultantes são listas Python, o que facilita a leitura e gravação de dados ao percorrer as linhas do cursor. arcpy.da.UpdateCursortambém tem melhor desempenho do que arcpy.UpdateCursor, em parte porque ignora campos sem importância, principalmente geometria.

  • Ao ler a geometria, você pode escolher um de uma série de tokens de geometria, por exemplo SHAPE@TRUECENTROID, SHAPE@AREAou SHAPE@. O uso de um token "mais simples" melhora muito o desempenho em comparação com o SHAPE@que contém todas as informações de geometria. A lista completa de tokens está na arcpy.da.UpdateCursorpágina de ajuda.

  • Como antes, sua linha de saída é armazenada em um espaço temporário temporário até você chamar o updateRowmétodo no cursor. Isso salva os novos dados no conjunto de dados real.

Aqui está o código Python que eu usaria para este método:

tempPgs = "LayerName"
arcpy.AddField_management(tempPgs, "Shape_area", "DOUBLE")
CursorFieldNames = ["SHAPE@AREA","Shape_area"]
cursor = arcpy.da.UpdateCursor(tempPgs,CursorFieldNames)
for row in cursor:
    AreaValue = row[0].area #Read area value as double
    row[1] = AreaValue #Write area value to field
    cursor.updateRow(row)
del row, cursor #Clean up cursor objects
dmahr
fonte
5
Resposta maravilhosa. Só queria dizer que a partir do 10.2, você faria apenas row[1] = row[0]como não há mais um areaatributo. Você também pode usar o cursor como gerenciador de contexto em uma withinstrução e não precisa se preocupar em excluir nada.
Paul H