Oblicz obszar w skrypcie Python w ArcMap

14

Próbuję obliczyć powierzchnię wielokąta w moim skrypcie Python. Tworzę nowy wielokąt z scalania dwóch razem i chciałbym dodać obszar wynikowego wielokąta do pola w pliku wyjściowym. Wielokąt jest przechowywany w regularnym pliku kształtu i jest rzutowany. Obszar najlepiej w jednostkach mapy.

Myślałbym, że jest to dość powszechne i proste zadanie, ale pomimo wielu Googleingów jak dotąd nie byłem w stanie znaleźć działających rozwiązań.

Miałem zamiar arcpy.updateCursorwstawić wartość po jej obliczeniu (na tym etapie jest tylko jedna funkcja w FC), więc najłatwiej jest, jeśli można ją zwrócić jako zmienną. Działa również każde alternatywne rozwiązanie, które spełnia to samo zadanie (przeniesienie wartości obszaru do właściwego pola).

Próbowałem także kalkulatora Field z Python. Zmodyfikowany ze stron pomocy, myślałem, że następujące będą działać, ale jak dotąd nie ma szczęścia.

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

Uruchamianie ArcGIS Basic 10.1 SP1 z Python 2.7 w systemie Windows 7.

Odpowiednie części mojego obecnego kodu wyglądają następująco:

#/.../
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 ...
Jaskółka oknówka
źródło
Jaki jest twój typ wyjścia? Plik kształtu, geobaza plików, coś jeszcze? Czy plik wyjściowy jest wyświetlany, czy nie jest projektowany?
blord-castillo
Czy możesz również opublikować trochę więcej kodu, w szczególności kursor, którego używasz do aktualizacji? Najprawdopodobniej możesz osiągnąć to, co chcesz, używając SHAPE@AREAczęści kursora do odczytu obszaru; ale struktura kodu zależy od tego, czy twój obszar jest w tych samych jednostkach, co to, co chcesz napisać.
blord-castillo

Odpowiedzi:

29

Istnieją trzy różne sposoby znajdowania i przechowywania obszaru wielokąta w klasie obiektów za pomocą arcpy: 1) kalkulator polowy, 2) „klasyczne” kursory arcpy i 3) arcpy.dakursory. Część tego zapożyczono z mojej poprzedniej odpowiedzi na temat korzystania z SearchCursor .


1. Kalkulator polowy

  • Podczas korzystania z kalkulatora pola istnieją trzy różne typy wyrażeń, które używają różnych analizatorów wyrażeń. Jest to określone w trzecim parametrze narzędzia geoprzetwarzania Oblicz pole . Podczas uzyskiwania dostępu do właściwości obiektu Geometry przy użyciu polecenia „podobnie jak” !shape.area!należy użyć analizatora składni Python 9.3.

  • Wyrażenie, które miałeś wcześniej, wykonało split()polecenie wyniku !SHAPE.AREA!. Zwraca listobiekt Python , którego nie można rzutować na floatobiekt.

  • W swoim wyrażeniu możesz określić jednostkę zwracanego obszaru za pomocą @SQUAREKILOMETERSflagi, zastępując SQUAREKILOMETERSje jednostkami na stronie pomocy Oblicz pole .

Oto kod Python, którego użyłbym dla tej metody:

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

2. Arc 10.0 - Kursory „klasyczne”

  • Podczas używania klasycznych kursorów (tj. arcpy.UpdateCursor) Obiekt kursora jest iterowalnym obiektem zawierającym rowobiekty. Musisz użyć metod getValuei setValue, aby uzyskać geometrię z wiersza (jako obiekt geometrii i ustawić wartość obszaru na rowliczbę zmiennoprzecinkową.

  • Twój wiersz wyjściowy jest przechowywany w tymczasowej przestrzeni do rysowania, dopóki nie wywołasz updateRowmetody na kursorze. Zapisuje to nowe dane w rzeczywistym zestawie danych.

Oto kod Python, którego użyłbym dla tej metody:

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. Arc 10.1 - kursory arcpy.da

  • Podczas korzystania z nowych kursorów w module dostępu do danych (tj. arcpy.da.UpdateCursor) Musisz przekazać listę nazw pól jako drugi parametr w konstruktorze kursora. Wymaga to nieco więcej pracy z góry, ale wynikowymi rowobiektami są listy w języku Python, co ułatwia odczyt i zapis danych podczas iteracji w wierszach kursora. arcpy.da.UpdateCursorma również lepszą wydajność niż arcpy.UpdateCursorczęściowo, ponieważ pomija nieistotne pola, zwłaszcza geometrię.

  • Podczas czytania geometrię, można wybrać jedną z wielu żetonów geometrii, na przykład SHAPE@TRUECENTROID, SHAPE@AREAalbo SHAPE@. Użycie „prostszego” tokena znacznie poprawia wydajność w porównaniu do SHAPE@, który zawiera wszystkie informacje o geometrii. Pełna lista tokenów znajduje się na stronie arcpy.da.UpdateCursorpomocy.

  • Tak jak poprzednio, wiersz wyjściowy jest przechowywany w tymczasowej przestrzeni do rysowania, dopóki nie wywołasz updateRowmetody na kursorze. Zapisuje to nowe dane w rzeczywistym zestawie danych.

Oto kod Python, którego użyłbym dla tej metody:

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
źródło
5
Cudowna odpowiedź. Chciałem tylko powiedzieć, że od 10.2 zrobiłbyś to, row[1] = row[0]ponieważ nie ma już areaatrybutu. Możesz także użyć kursora jako menedżera kontekstu w withinstrukcji i nie musisz się martwić o usunięcie czegokolwiek.
Paul H