Update Cursor Issue: Multiple nested If Elif Else

2226
8
09-06-2016 02:10 PM
KristaMerry
New Contributor

I am trying to work through an Update cursor issue. I have a forest stands shapefile with the following fields: Age, Historical Community (Hist_Comm), Pine Basal Area (PINE_BA), Fire Return Interval (FIRE_FRQ), Time Since Last Fire (LAST_YR), and then a Class (ECC). The goal is to use the AGE, Hist_Comm, FIRE_FRQ, and LAST_YR fields along with several user inputs to assign an ECC value. 

This is how it would work: 

If the Historical Community field (Hist_Comm) is greater than 3:

      and If the Age (Min_Age1) is greater than 80:

         and if the Pine Basal Area (Min_PineBA1) is greater than or equal to 40  or Pine Basal Area (Max_PineBA1) is less

          than or equal to 60:          

             and if the Fire Frequency (Max_FI1) is less than 3  and the Time Since Last Fire (Max_FY1) is less than 3:          

                then ECC = 1

             or elif the Fire Frequency (Min_FI1) is greater than or equal to 3  but less than or equal to 6 (Max_FI1) and the Time

             Since Last Fire (Max_FY1) is less than or equal to 6: 

                  then ECC = 3

It should search through the attribute table selecting the rows from the fields Hist_Comm, AGE, PINE_BA, FIRE_FRQ, and LAST_YR that fit the above criteria and assign then assign a value to the ECC field.

 

I think (stress think) I am having an issue with the user inputs working within multiple levels of nested if statements. 

The script has been added to a toolbox. Each input variable Data Type is defined as a string. Each input variable will be an integer value. 

Here's the code (also attached):

# Import arcpy module
import arcpy

# Set Workspace
arcpy.env.workspace = 'C:\\ECC_Test\\Output'

# Set Input Parameters
Min_Age1 = arcpy.GetParameterAsText(0) 
Min_PineBA1 = arcpy.GetParameterAsText(1) 
Max_PineBA1 = arcpy.GetParameterAsText(2)
Min_FI1 = arcpy.GetParameterAsText(3)
Max_FI1 = arcpy.GetParameterAsText(4)
Max_FY1 = arcpy.GetParameterAsText(5)

# Define Variables
fc = "C://ECC_Test//Output//Stands_2_t.shp"

#Update Cursor
with arcpy.da.UpdateCursor(fc, ["Hist_Comm", "FIRE_FRQ", "LAST_YR", "AGE", "PINE_BA", "ECC"]) as cursor:
    for row in cursor:
       if (row[0] >= 3) and (Min_Age1 >= 80) and (row[3] >= 80):
         if (Min_PineBA1 >= 40) and (Max_PineBA1 <= 60) and(row[4] >= 40) and (row[4] <= 60):
             if (Max_FI1 < 3) and (row[1] < 3) and (Max_FY1 < 3) and (row[2] < 3): 
                row[5] = 1 
             elif (Min_FI1 >= 3) and (row[1] >= 3) and (Max_FI1 <= 6) and (row[1] >= 3) and (Max_FY1 <= 6) and (row[2] <= 6): 
                row[5] = 3
             else:
                row[5] = 4
          cursor.updateRow(row)

 
 del cursor, row
0 Kudos
8 Replies
DanPatterson_Retired
MVP Esteemed Contributor

before my head bursts....

what are you supposed to do if this line fails?  there is no where to go

if (row[0] >= 3) and (Min_Age1 >= 80) and (row[3] >= 80):

PS  I took the liberty of formatting your code... follow the 3 dots on the editor bar, select More, then Syntax highlighting and paste your code and select Python

KristaMerry
New Contributor

Dan,

Thank you for reformatting the code. In my haste i didn't see the Python formatting.

I also forgot to include the final "else" in the code. So if the data doesn't meet those criteria it is assigned a zero.

#Update Cursor

with arcpy.da.UpdateCursor(fc, ["Hist_Comm", "FIRE_FRQ", "LAST_YR", "AGE", "PINE_BA", "ECC"]) as cursor:
    for row in cursor:
        if (row[0] >= 3) and (Min_Age1 >= 80) and (row[3] >= 80):
            if (Min_PineBA1 >= 40) and (Max_PineBA1 <= 60) and(row[4] >= 40) and (row[4] <= 60):
                if (Max_FI1 < 3) and (row[1] < 3) and (Max_FY1 < 3) and (row[2] < 3):                           
                    row[5] = 1                       
                elif (Min_FI1 >= 3) and (row[1] >= 3) and (Max_FI1 <= 6) and (row[1] >= 3) and (Max_FY1 <= 6) and (row[2] <= 6): 
                    row[5] = 3
                else:
                    row[5] = 4
            cursor.updateRow(row)       
        else:
            row[5] = 0
        
            
    del cursor, row
0 Kudos
XanderBakker
Esri Esteemed Contributor

The "else" will never trigger an update of the row, with the code posted.

0 Kudos
NeilAyres
MVP Frequent Contributor

Sorry, but what do you mean by this :

"Each input variable Data Type is defined as a string. Each input variable will be an integer value." ??

Are the inputs strings or integers?

0 Kudos
KristaMerry
New Contributor

Neil,

Your question helped me with one issue and pointed out my boneheaded mistake. They are integers and are now defined as Long not String. 

Thanks!

Krista

0 Kudos
KristaMerry
New Contributor

With the String to Long fix, I am only getting the ECC classes of 0 and 4 being assigned. In querying the attribute table I can see that there are data that should be classified as class 3 but are classified as 4.

I am sure there is something pretty straight forward I am missing. I am new to using Cursors so bare with me. 

0 Kudos
XanderBakker
Esri Esteemed Contributor

You have to revise the logic of obtaining the ECC classes. See the example below. I have no idea where the values for in_Age1, Min_PineBA1, Max_PineBA1, Max_FY1, Min_FI1, Max_FI1 come from. 

I created a function to get the ECC class, but I see that you are checking twice on the same line for the fire frequency (see line 9). Furthermore, is last_yr really a value that low? You may want to include some print statements to see what happens. It has nothing to do with the update cursor.

def getECC(hist_comm, fire_frq, last_yr, age, pine_ba,
           Min_Age1, Min_PineBA1, Max_PineBA1, Max_FY1, Min_FI1, Max_FI1):
    ecc = -1
    try:
        if (hist_comm >= 3) and (Min_Age1 >= 80) and (age >= 80):
            if (Min_PineBA1 >= 40) and (Max_PineBA1 <= 60) and(pine_ba >= 40) and (pine_ba <= 60):
                if (Max_FI1 < 3) and (fire_frq < 3) and (Max_FY1 < 3) and (last_yr < 3):
                    ecc = 1
                elif (Min_FI1 >= 3) and (fire_frq >= 3) and (Max_FI1 <= 6) and (fire_frq >= 3) and (Max_FY1 <= 6) and (last_yr <= 6):
                    ecc = 3
                else:
                    ecc = 4
        else:
            ecc = 0
    except Exception as e:
        print(e)
        ecc = -1
    finally:
        return ecc

# where do these variables come from?
# Min_Age1, Min_PineBA1, Max_PineBA1, Max_FY1, Min_FI1, Max_FI1

#Update Cursor
with arcpy.da.UpdateCursor(fc, ["Hist_Comm", "FIRE_FRQ", "LAST_YR", "AGE", "PINE_BA", "ECC"]) as cursor:
    for row in cursor:
        ecc = getECC(row[0], row[1], row[2],row[3], row[4],
                     Min_Age1, Min_PineBA1, Max_PineBA1, Max_FY1, Min_FI1, Max_FI1)
        row[5] = ecc
        cursor.updateRow(row)


del cursor, row‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍
DarrenWiens2
MVP Honored Contributor

I believe your original explanation can be re-written like below (every 'if' should have a corresponding 'else').

However, I think the larger problem is that you probably want to compare the row values to the input values. So, rather than comparing the user input value (Min_Age1) to 80, you want to see if the current row age value is greater than the user input value: row[3] > Min_Age1.


# Import arcpy module
import arcpy

# Set Workspace
arcpy.env.workspace = 'C:\\ECC_Test\\Output'

# Set Input Parameters
Min_Age1 = arcpy.GetParameterAsText(0) 
Min_PineBA1 = arcpy.GetParameterAsText(1) 
Max_PineBA1 = arcpy.GetParameterAsText(2)
Min_FI1 = arcpy.GetParameterAsText(3)
Max_FI1 = arcpy.GetParameterAsText(4)
Max_FY1 = arcpy.GetParameterAsText(5)

# Define Variables
fc = "C://ECC_Test//Output//Stands_2_t.shp"

#Update Cursor
with arcpy.da.UpdateCursor(fc, ["Hist_Comm", "FIRE_FRQ", "LAST_YR", "AGE", "PINE_BA", "ECC"]) as cursor:
    for row in cursor:
        if (row[0] >= 3) and (Min_Age1 >= 80) and ((Min_PineBA1 >= 40) or (Max_PineBA1 <= 60)):
            if (Max_FI1 < 3) and ((Max_FY1 < 3)):
                row[5] = 1
            elif (Min_FI1 >= 3) and (Max_FI1 <= 6) and (Max_FY1 <= 6):
                row[5] = 3
            else:
                row[5] = 222
                print 'Did not pass second test'
        else:
            row[5] = 111
            print 'Did not pass first test'
        cursor.updateRow(row)