Standalone Berechnen Sie das Feldskript mithilfe des Codeblocks für IMG Raster in Python

Sep 03 2020

Ich bin mit der Verwendung der Python-Sprache im Tool "Feld berechnen" in ArcGIS Pro einigermaßen vertraut, habe mich jedoch gefragt, wie dies in einem eigenständigen Python-Skript mit einer Raster-IMG-Datei (Combine20012004FltPths.img) erfolgt.

Ich versuche, ein neues Feld, das ich mit ganzzahligen Werten aus einem anderen Feld erstellt habe, neu zu klassifizieren. Wenn ich jedoch versuche, den Code in IDLE auszuführen, wird "SyntaxError: ungültige Syntax" angezeigt.

Hier ist mein Python-Skript für den Codeblock und das Arcpy-Management-Tool "Feld berechnen":

# 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")

Müsste ich die Attributtabelle meiner .img-Datei (Combine20012004FltPths.img) in eine dBASE- oder Geodatabase-Tabelle oder ein anderes Tabellenformat konvertieren und dann das Tool Codeblock und Feld berechnen ausführen, damit es funktioniert?

Antworten

3 Vince Sep 04 2020 at 16:07

Der Schlüssel zum Bereitstellen eines Codeblocks CalculateFieldbesteht darin, zu verstehen, dass im Dienstprogramm ein separater Python-Parser verwendet wird. Das code_blockmuss daher eine Zeichenfolge sein, die brauchbaren Code enthält. Sie können dies erreichen, indem Sie dreifache Anführungszeichen um den Text verwenden, damit Python die Zeilenfortsetzung korrekt behandelt:

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

Dies ist jedoch nur die erste Wiederholung der Verbesserung. Es gibt zwei grundlegende Ansätze zum Codieren einer Schaltanlagenfunktion. Die erste verwendet eine Kaskade von bedingten Tests und hat zwei Hauptformen: Mit und ohne vorzeitigen Ausstieg. Zuerst ohne:

# 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
"""

Das Formular für den vorzeitigen Ausstieg sollte bekannt sein, aber wenn returnes verwendet wird, ist kein elseerforderlich:

# 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
"""

Der zweite Ansatz nutzt den Datentyp des Wörterbuchs. Es ist schneller und pythonischer:

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

Das Sexy an der Verwendung von Wörterbüchern ist, dass Sie dies mit der Tatsache kombinieren können, dass Sie hier nur eine Zeichenfolge kompilieren, damit Sie sie dynamisch zusammenstellen können (in diesem Fall aus einer Datei-Geodatabase-Tabelle):

# 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'])]))

Okay, ja, das ist ein bisschen heiß und schwer, aber wie oft können Sie ein Listenverständnis für einen Cursor, ein Format und zwei Ersetzungen in einer erweiterten Zeile durchführen? Und es funktioniert:

>>> 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

Der stumpfe Teil könnte zur Selbstdokumentation de-inliniert werden:

# 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)