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
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
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
The "else" will never trigger an update of the row, with the code posted.
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?
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
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.
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
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)