Script de calcul de champ autonome à l'aide du bloc de code pour IMG Raster en Python

Sep 03 2020

Je connais un peu l'utilisation du langage python dans l'outil Calculer le champ d'ArcGIS Pro, mais je me demandais comment cela se faisait dans un script Python autonome avec un fichier raster .img (Combine20012004FltPths.img).

J'essaie de reclasser un nouveau champ que j'ai créé en utilisant des valeurs entières d'un autre champ. Cependant, quand j'essaye d'exécuter le code dans IDLE, j'obtiens un "SyntaxError: syntaxe invalide".

Voici mon script python pour le bloc de code et l'outil de calcul de champ de gestion arcpy:

# Code Block for Calculate Field
codeBlock = def reclass(FlightPat1):
                if (FlightPat1 == 0):
                    return "Unclassified"
                elif (FlightPat1 == 11):
                    return "Open Water"
                elif (FlightPat1 == 12):
                    return "Perennial Snow/Ice"
                elif (FlightPat1 == 21):
                    return "Developed, Open Space"
                elif (FlightPat1 == 22):
                    return "Developed, Low Intensity"
                elif (FlightPat1 == 23):
                    return "Developed, Medium Intensity"
                elif (FlightPat1 == 24):
                    return "Developed, High Intensity"
                elif (FlightPat1 == 31):
                    return "Barren Land"
                elif (FlightPat1 == 41):
                    return "Deciduous Forest"
                elif (FlightPat1 == 42):
                    return "Evergreen Forest"
                elif (FlightPat1 == 43):
                    return "Mixed Forest"
                elif (FlightPat1 == 52):
                    return "Shrub/Scrub"
                elif (FlightPat1 == 71):
                    return "Herbaceuous"
                elif (FlightPat1 == 81):
                    return "Hay/Pasture"
                elif (FlightPat1 == 82):
                    return "Cultivated Crops"
                elif (FlightPat1 == 90):
                    return "Woody Wetlands"
                elif (FlightPat1 == 95):
                    return "Emergent Herbaceuous Wetlands"


#Reclassify field based off another field
arcpy.CalculateField_management("Combine20012004FltPths.img", "NLCD01Clss",
                                "Reclass(!FlightPat1!)", expression_type = "PYTHON3",
                                code_block = codeBlock, field_type = "TEXT")

Aurais-je besoin de convertir la table attributaire de mon fichier .img (Combine20012004FltPths.img) en une table dBASE ou de géodatabase ou dans un autre format de table, puis exécuter l'outil Bloc de code et calculer le champ pour que cela fonctionne?

Réponses

3 Vince Sep 04 2020 at 16:07

La clé pour fournir un bloc de code à CalculateFieldest de comprendre qu'un analyseur Python distinct est utilisé dans l'utilitaire. Le code_blockdoit donc être une chaîne contenant du code viable. Vous pouvez accomplir cela en utilisant des guillemets triples autour du texte, afin que Python gère correctement la continuation de ligne:

# Code Block for Calculate Field
codeBlock = """
def reclass(flightPat1):   # Note lowercase variable name -- upcase is for Classes
   {rest of function}
"""

Mais ce n'est que la première itération de l'amélioration. Il existe deux approches de base pour coder une fonction de poste de départ. Le premier utilise une cascade de tests conditionnels et se présente sous deux formes principales: avec et sans sortie anticipée. D'abord sans:

# Code Block for Calculate Field
codeBlock = """
def reclass(flightPat1):
    result = None        #! Initialize so that it always returns a default value
    if (flightPat1 == 0):
        result = "Unclassified"
    elif (flightPat1 == 11):
        result = "Open Water"
    ...
    return result
"""

Le formulaire de sortie anticipée doit être familier, mais étant donné qu'il returnest utilisé, aucun elsen'est nécessaire:

# Code Block for Calculate Field
codeBlock = """
def reclass(flightPat1):
    if (flightPat1 == 0):
        return "Unclassified"
    if (flightPat1 == 11):
        return "Open Water"
    ...
    return None    #! Suffices for final else
"""

La deuxième approche exploite le type de données dictionnaire. C'est plus rapide et plus pythonique:

# Code Block for Calculate Field
codeBlock = """
lookup = {
     0 : "Unclassified",
    11 : "Open Water",
    ...
}
def reclass(flightPat1):
    return lookup[flightPat1] if flightPat1 in lookup else None
"""

La partie sexy de l'utilisation du dictionnaire est que vous pouvez combiner cela avec le fait que vous ne faites que compiler une chaîne ici, afin de pouvoir l'assembler dynamiquement (dans ce cas, à partir d'une table de géodatabase fichier):

# Code Block for Calculate Field
lookupSrc = r"C:\Temp\gis_se.gdb\answer_lookup"
codeBlock = """
def reclass(flightPat1):
    lookup = {
@TERMS
    }
    return lookup[flightPat1] if flightPat1 in lookup else None
""".replace('@TERMS',',\n'.join(
    ["{:10d} : '{:s}'".format(rec[0],rec[1].replace("'","\\'")) 
        for rec in arcpy.da.SearchCursor(lookupSrc,['ival','sval'])]))

D'accord, alors oui, c'est un peu chaud, mais combien de fois pouvez-vous faire une compréhension de liste sur un curseur, un format et deux remplacements dans une ligne étendue? Et ça marche:

>>> print(codeBlock)

def reclass(flightPat1):
    lookup = {
         0 : 'Unclassified',
        11 : 'Open Water',
        12 : 'Perennial Snow/Ice',
        21 : 'Developed, Open Space',
        22 : 'Developed, Low Intensity',
        23 : 'Developed, Medium Intensity',
        24 : 'Developed, High Intensity',
        31 : 'Barren Land',
        41 : 'Deciduous Forest',
        42 : 'Evergreen Forest',
        43 : 'Mixed Forest',
        52 : 'Shrub/Scrub',
        71 : 'Herbaceuous',
        81 : 'Hay/Pasture',
        82 : 'Cultivated Crops',
        90 : 'Woody Wetlands',
        94 : 'Apostrophe\'s Example',
        95 : 'Emergent Herbaceuous Wetlands'
    }
    return lookup[flightPat1] if flightPat1 in lookup else None

La partie obtuse pourrait être désinscrite pour s'auto-documenter:

# Code Block for Calculate Field
lookupSrc = r"C:\Temp\gis_se.gdb\answer_lookup"
codeFormat = """
def reclass(flightPat1):
    lookup = {
@TERMS
    }
    return lookup[flightPat1] if flightPat1 in lookup else None
"""
termList = []
with arcpy.da.SearchCursor(lookupSrc,['ival','sval']) as cursor:
    for row in cursor:
        ival = row[0]
        sval = row[1].replace("'","\\'")    #! Handle case where sval contains apostrophe
        term = "{:10d} : '{:s}'".format(ival,sval)
        termList.append(term)

termString = ',\n'.join(termList)    #! str.join() adds text between list elements
codeBlock = codeFormat.replace('@TERMS',termString)