Select to view content in your preferred language

How to keep missing fields from crashing my code?

2321
13
06-12-2012 07:41 AM
RichardThurau
Deactivated User
Hi,
I have a very helpful code I use to run metrics between land cover and a bunch of assessment boundary feature classes using tabulate area. I put my land cover classes in a list and the field names that are calculated from the classes in another list. Update cursor fills in the rest.

The problem is, if I have an assessment boundary that does not intersect a land cover class, when update cursor goes to calculate the field from the class value, it crashes the code.

I will paste a sample code:

ClassList = ["Forest", "Vegetation"]
FieldList = ["Land_Acres","Forest_Acres", "Forest_Percent", "Veg_Acres", "Veg_Percent"]

m2ac = 0.0002471054

FcList = arcpy.ListFeatureClasses("*", "")   
for fc in FcList:
    areaTab1 = "Metrics_" + os.path.basename(fc)
    for field in FieldList:
        arcpy.AddField_management(fc, field, "DOUBLE")
    TabulateArea(fc, "GID", LC, "Class", areaTab1 , 1) #"UTC_Metrics_" + os.path.basename(fc)
    arcpy.JoinField_management(fc, "GID", areaTab1, "GID", ClassList)#"trees11_tab_" + os.path.basename(fc)
    rows = arcpy.UpdateCursor(fc)
    print str(fc)
    for row in rows:  
        row.setValue(FieldList[0], (row.Shape_Area * m2ac))#Total Acres
        rows.updateRow(row)
        row.setValue(FieldList[1], row.getValue(ClassList[0]) * m2ac) #Forest Acres
        rows.updateRow(row)
        row.setValue(FieldList[2], (row.getValue(FieldList[1]) / row.Land_Acres) * 100) #Forest Percent
        rows.updateRow(row)
        row.setValue(FieldList[3], row.getValue(ClassList[1]) * m2ac) #Veg Acres
        rows.updateRow(row)
        row.setValue(FieldList[4], (row.getValue(FieldList[3]) / row.Land_Acres) * 100) #Veg Percent
        rows.updateRow(row)
    del row
    del rows


So, this code runs great, unless one of the feature classes does not intersect with one of the land cover classes. Then, when the code calls the ClassList for that value, the code will crash in two spots:
1. At the joinfield, where it looking for all classes from the class list to join
2. In the update cursor when it calls the class name to calculate the fields.

Is there  a good way to make the code just skip the value rather than crashing the code?

Thanks

Rich
#
Tags (2)
0 Kudos
13 Replies
XanderBakker
Esri Esteemed Contributor

some pointers (without having seen the data):

  • are you sure that all double fields need to be updated?
  • the fldlist in your case is a list that contains field objects, but the cursor will need a list or tuple of field names. I changed this on line 4
  • for each row you will need to loop through the fields and calculate the new values (see line 8 - 11)

import arcpy

arcpy.env.workspace = r'G:\users\gis\gbacon\Watershed_Testing\valleyave\WatershedDelineation.gdb'

tbl = "TabSummary"

fldlist = [fld.name for fld in arcpy.ListFields(tbl,"","Double")]

with arcpy.da.UpdateCursor(tbl, fldlist) as cursor:

    for row in cursor:

        i = 0

        for fld in fldlist:

            row = row / 43560

            i += 1

        cursor.updateRow(row)

Haven't tested it though. Since you are changing the input data, test it with a copy of the data. Also don't run the code more than once on the same data...

Kind regards, Xander

0 Kudos
GregBacon
Deactivated User

This worked nicely! Thank you. In this case, all “double” fields needed the update. What would change if I had some “double” fields that needed to be left alone?

I just checked the forum and found that my table is in fact in the zip file attachment. I apologize for not having posted the code correctly. It seems like there’s a better way to do it.

0 Kudos
XanderBakker
Esri Esteemed Contributor

Hi Greg,

The only file in the ZIP file is an XML file called "TabSummary.dbf.xml" (or at least this is what passed my firewall).

In case you know the names of the double fields you want to maintain untouched, you would have to exclude those from the list of fieldnames. This can be done like this (see code below).

  • the flds_exclude contains a list of fieldnames that should remain untouched
  • flds_touse is a new list where all the items from the exclude list are remove from the list of double fields
  • set() is used to be able to do this type of comparisons with lists, after this the set is converted to a list again

import arcpy

arcpy.env.workspace = r'G:\users\gis\gbacon\Watershed_Testing\valleyave\WatershedDelineation.gdb'

tbl = "TabSummary"

fldlist = [fld.name for fld in arcpy.ListFields(tbl,"","Double")]

flds_exclude = ["myFieldname1", "myFieldname2", "myFieldname3"]

flds_touse = list(set(fldlist) - set(flds_exclude))

with arcpy.da.UpdateCursor(tbl, flds_touse) as cursor:

    for row in cursor:

        i = 0

        for fld in flds_touse:

            row = row / 43560

            i += 1

        cursor.updateRow(row)

Kind regards, Xander

0 Kudos
GregBacon
Deactivated User

Thanks again. Set() could be very useful to me.

0 Kudos