Calculer la surface dans un script Python dans ArcMap

14

J'essaie de calculer l'aire d'un polygone dans mon script Python. Je crée un nouveau polygone en fusionnant deux et j'aimerais ajouter la zone du polygone résultant à un champ dans le fichier de sortie. Le polygone est stocké dans un fichier de formes régulier et est projeté. Zone de préférence en unités de carte.

J'aurais pensé que c'était une tâche assez courante et simple, mais malgré beaucoup de recherches sur Google, je n'ai pas pu trouver de solutions de travail jusqu'à présent.

J'avais l'intention d'utiliser arcpy.updateCursorpour insérer la valeur une fois qu'elle est calculée (il n'y a qu'une seule fonctionnalité dans le FC à ce stade), donc le plus simple est de savoir si elle peut être retournée sous forme de variable. Toute solution alternative qui accomplit la même tâche (obtenir la valeur de la zone dans le champ correct) fonctionnera également.

J'ai également essayé la calculatrice Field de Python. Modifié à partir des pages d'aide, j'ai pensé que ce qui suit fonctionnerait, mais jusqu'à présent, pas de chance.

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

Exécution d'ArcGIS Basic 10.1 SP1 avec Python 2.7 sous Windows 7.

Les parties pertinentes de mon code actuel ressemblent à ceci:

#/.../
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
la source
Quel est votre type de sortie? Shapefile, fichier géodatabase, autre chose? Votre fichier de sortie est-il projeté ou non projeté?
blord-castillo
Pourriez-vous également publier un peu plus de l'exemple de code, en particulier le curseur que vous utilisez pour effectuer la mise à jour? Vous pouvez très probablement réaliser ce que vous voulez en utilisant le SHAPE@AREAdans le cadre de votre curseur pour lire la zone; mais la structure du code dépend si votre région est dans les mêmes unités que ce que vous voulez écrire.
blord-castillo

Réponses:

29

Il existe trois façons différentes de rechercher et de stocker une zone de polygone dans une classe d'entités avec arcpy: 1) une calculatrice de champ, 2) des curseurs arcpy "classiques" et 3) des arcpy.dacurseurs. Une partie de cela est empruntée à ma réponse précédente sur l'utilisation de SearchCursor .


1. Calculatrice de terrain

  • Lors de l'utilisation de la calculatrice de champ, il existe trois types d'expression différents qui utilisent des analyseurs d'expression différents. Ceci est spécifié dans le troisième paramètre de l' outil de géotraitement Calculer le champ . Lorsque vous accédez aux propriétés de l'objet Geometry en utilisant comme dans !shape.area!, vous devez utiliser l'analyseur Python 9.3.

  • L'expression que vous aviez auparavant a exécuté une split()commande sur le résultat de !SHAPE.AREA!. Cela renvoie un listobjet Python , qui ne peut pas être converti en floatobjet.

  • Dans votre expression, vous pouvez spécifier l'unité de la zone retournée en utilisant l' @SQUAREKILOMETERSindicateur, en le remplaçant SQUAREKILOMETERSpar les unités sur la page d'aide Calculer le champ .

Voici le code Python que j'utiliserais pour cette méthode:

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 - Curseurs "classiques"

  • Lors de l'utilisation de curseurs classiques (ie arcpy.UpdateCursor), l'objet curseur est un objet contenant des itérables row. Vous devez utiliser les méthodes getValueet setValuepour obtenir la géométrie de la ligne (en tant qu'objet géométrique et définir la valeur de la zone en rowtant que flottant.

  • Votre ligne de sortie est stockée dans un espace de travail temporaire jusqu'à ce que vous appeliez la updateRowméthode sur le curseur. Cela enregistre les nouvelles données dans l'ensemble de données réel.

Voici le code Python que j'utiliserais pour cette méthode:

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 - curseurs arcpy.da

  • Lorsque vous utilisez les nouveaux curseurs dans le module d'accès aux données (c'est-à-dire arcpy.da.UpdateCursor), vous devez passer une liste de noms de champs comme deuxième paramètre dans le constructeur du curseur. Cela nécessite un peu plus de travail à l'avance, mais les rowobjets résultants sont des listes Python, ce qui facilite la lecture et l'écriture de données lors de l'itération dans les lignes du curseur. arcpy.da.UpdateCursora également de meilleures performances que arcpy.UpdateCursor, en partie parce qu'il ignore les champs sans importance, en particulier la géométrie.

  • Lorsque la géométrie de lecture, vous pouvez choisir l' un d'un certain nombre de jetons de géométrie, par exemple SHAPE@TRUECENTROID, SHAPE@AREAou SHAPE@. L'utilisation d'un jeton "plus simple" améliore considérablement les performances par rapport à SHAPE@, qui contient toutes les informations de géométrie. La liste complète des jetons se trouve sur la arcpy.da.UpdateCursorpage d'aide.

  • Comme précédemment, votre ligne de sortie est stockée dans un espace de travail temporaire jusqu'à ce que vous appeliez la updateRowméthode sur le curseur. Cela enregistre les nouvelles données dans l'ensemble de données réel.

Voici le code Python que j'utiliserais pour cette méthode:

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
la source
5
Magnifique réponse. Je voulais juste dire qu'à partir de 10.2, vous feriez simplement row[1] = row[0]car il n'y a plus d' areaattribut. Vous pouvez également utiliser le curseur comme gestionnaire de contexte dans une withinstruction et ne pas avoir à vous soucier de supprimer quoi que ce soit.
Paul H