Calculating field value based on other fields

2861
6
Jump to solution
02-16-2013 04:40 PM
AlastairFitzmaurice
New Contributor II
Hello All,

I am very new to Python, I am trying to calculate a field based on the values of three other fields.

I have been able get the process to work in Model Builder but when I export the model to Python and import the line of code that calculates the last field to the rest of the script it runs but does not populate the field. (000405 error)

My code looks like this:
## Add field - Wall_mm  arcpy.AddField_management("Svy_Pt","Wall_mm","FLOAT")  # Select Class (SDR) and Diameter then Calculate wall thickness  arcpy.SelectLayerByAttribute_management("Svy_Pt", "NEW_SELECTION", "\"Class\" = 'SDR 9' OR \"Class\" = 'SDR9' AND \"Diameter\" =  450") arcpy.CalculateField_management("Svy_Pt", "Wall_mm", "52.8", "VB", "")  # Add field - Invert_RL  arcpy.AddField_management("Svy_Pt","Invert_RL","FLOAT")  #Calculate Invert_RL  arcpy.CalculateField_management("Svy_Pt", "Invert_RL", "( [RL]-( [Diameter]/1000))+( [Wall_mm]/1000)", "VB", "")


There are 30 different combinations for the Class and Diameter that the code scrolls through before it gets to the second add field command. It works fine in the python window in ArcGIS 10.1 up to the last line where it runs but doesn't populate the table.

I've looked at the online help where it says to use "!" for field names in Python and tried that as well as triple quotes but I think the additional brackets are confusing the arguments for the tool.

Any assistance would be appreciated.
Tags (2)
0 Kudos
1 Solution

Accepted Solutions
T__WayneWhitley
Frequent Contributor
Although you may have achieved 'agreeable' results at the moment, your logic is faulty -- I have simulated a proof of sorts working from IDLE (explanatory comments are preceded by '#'):
# setting 2 variables as in your selection query, # "Class" (string) and "Diameter" (float):  >>> Class = 'SDR9'  # the Diameter value is purposely set up wrong # (not equal to the value in your query, 450):  >>> Diameter = float(500)  # just to check that the values were set properly, printing them...  >>> print Class, Diameter SDR9 500.0  # setting up an 'if' statement phrased similarly to your sel query, # with 'or' and 'and', no puctuation to separate clauses:  >>> if Class == 'SDR 9' or Class == 'SDR9' and Diameter == 450:                # case 1:  Class == 'SDR 9' evals FALSE               # case 2:  Class == 'SDR9' evals TRUE               # case 3:  Diameter == 450 evals FALSE  # The following statement will print 'yes' # if the above compound statement evals TRUE.  # The final eval of the compound statement can be TRUE only # if case 1 is TRUE or both case 2 and case 3 are TRUE.  # 'SDR9' is not equal to 'SDR 9' so case 1 is FALSE # 500.0 is not equal to 450 so case 3 is FALSE.  # Then, the compound statement is FALSE; # the print statement will not execute.   print 'yes'   # indeed, it is confirmed, the print statement did not execute.    # trying the alternate string, setting "Class" to 'SDR 9'  >>> Class = 'SDR 9'  >>> # trying the same 'if' statement:  >>> if Class == 'SDR 9' or Class == 'SDR9' and Diameter == 450:                # this time Class == 'SDR 9' evals true, of course...               # no need to go further, the print statement will execute.   print 'yes' yes  # the print statement executed due to the final eval TRUE, printed 'yes'. # however, was that the intended result???... # the Diameter is still 500 and intended to test it for the val 450, correct???  # the following shows how to correctly test for either 'SDR 9' or 'SDR9' first, # in addition to testing the Diameter:  >>> if (Class == 'SDR 9' or Class == 'SDR9') and Diameter == 450:  # now, the only way this compound statement can eval TRUE is if both 'clauses' # on either side of 'and' are TRUE.  # however, 500 is not equal to 450, so the final eval is FALSE; # the print statement cannot execute.   print 'yes'    # indeed, the print statement does not execute (as it shouldn't).


Hope that is clear.

Enjoy,
Wayne

View solution in original post

0 Kudos
6 Replies
DanPatterson_Retired
MVP Emeritus
Did you count them?  you have 4 ( , and 2 )
0 Kudos
T__WayneWhitley
Frequent Contributor
Your 000405 error isn't the only thing to look at but think it means 'no records' -- so that probably means your selection query returned nothing, no rows to executed the calculation on.  So check your query:

"\"Class\" = 'SDR 9' OR \"Class\" = 'SDR9' AND \"Diameter\" =  450"

Something you can add after executing the selecting is 'get count' (in the 'management' toolbox) to check if any selected rows resulted... can be tricky in a number of ways, such as if the layer is already 'filtered' somehow either by a def query or other means, could affect your expected output.

A few other observations, if they apply to your problem:
- The logic of your query may be a little off, are these 2 queries below equivalent? (have to be careful about this):

"Class" = 'SDR 9' OR "Class" = 'SDR9' AND "Diameter" = 450
("Class" = 'SDR 9' OR "Class" = 'SDR9') AND "Diameter" = 450

- Looks like you are feeding a str val ("52.8") into a float field in your 1st calc statement - I'd be careful about that too.
- ....may just be semantics, but think the last 2 params in calc fld are optional ["VB", ""], with VB being the default, so you can knock them off.

Hope that helps,
Wayne
0 Kudos
AlastairFitzmaurice
New Contributor II
Thank you Gents,

@Dan, I'm not sure what you mean, within the expression part of the command there is an equal number of "(" and ")"

@Wayne, The two queries you picked up are to cover errors in the data input - one is with a space and one without. I ran the script in stages and checked the results in the attribute table to see if the "Wall_mm" field had been populated.

I have been able to run the code - as ugly as it is - and it runs successfully adding the Wall_mm field, selecting the SDR and Diameter, calculating Wall_mm and adding the Invert_RL field. But the line of code I am having problems with is this one:

# Process: Calculate Field
arcpy.CalculateField_management("Svy_Pt", "Invert_RL", "( [RL]-( [Diameter]/1000))+( [Wall_mm]/1000)", "VB", "")


This is a direct export from Model Builder,as are the other lines, and it works in Model Builder but doesn't work in Python.

I hope I've explained myself a bit better this time.

I'll also have a look at getcount and the float value.

regards
0 Kudos
AlastairFitzmaurice
New Contributor II
Gents,

I ended up finding a work around, it needed for the feature class to be selected before it would calculate the value.

#Calculate Invert_RL
arcpy.SelectLayerByAttribute_management("Svy_Pt")
arcpy.CalculateField_management("Svy_Pt", "Invert_RL", "( [RL]-( [Diameter]/1000))+( [Wall_mm]/1000)", "VB", "")
arcpy.SelectLayerByAttribute_management("Svy_Pt","CLEAR_SELECTION")


Thank you for your suggestions.

regards
0 Kudos
T__WayneWhitley
Frequent Contributor
Although you may have achieved 'agreeable' results at the moment, your logic is faulty -- I have simulated a proof of sorts working from IDLE (explanatory comments are preceded by '#'):
# setting 2 variables as in your selection query, # "Class" (string) and "Diameter" (float):  >>> Class = 'SDR9'  # the Diameter value is purposely set up wrong # (not equal to the value in your query, 450):  >>> Diameter = float(500)  # just to check that the values were set properly, printing them...  >>> print Class, Diameter SDR9 500.0  # setting up an 'if' statement phrased similarly to your sel query, # with 'or' and 'and', no puctuation to separate clauses:  >>> if Class == 'SDR 9' or Class == 'SDR9' and Diameter == 450:                # case 1:  Class == 'SDR 9' evals FALSE               # case 2:  Class == 'SDR9' evals TRUE               # case 3:  Diameter == 450 evals FALSE  # The following statement will print 'yes' # if the above compound statement evals TRUE.  # The final eval of the compound statement can be TRUE only # if case 1 is TRUE or both case 2 and case 3 are TRUE.  # 'SDR9' is not equal to 'SDR 9' so case 1 is FALSE # 500.0 is not equal to 450 so case 3 is FALSE.  # Then, the compound statement is FALSE; # the print statement will not execute.   print 'yes'   # indeed, it is confirmed, the print statement did not execute.    # trying the alternate string, setting "Class" to 'SDR 9'  >>> Class = 'SDR 9'  >>> # trying the same 'if' statement:  >>> if Class == 'SDR 9' or Class == 'SDR9' and Diameter == 450:                # this time Class == 'SDR 9' evals true, of course...               # no need to go further, the print statement will execute.   print 'yes' yes  # the print statement executed due to the final eval TRUE, printed 'yes'. # however, was that the intended result???... # the Diameter is still 500 and intended to test it for the val 450, correct???  # the following shows how to correctly test for either 'SDR 9' or 'SDR9' first, # in addition to testing the Diameter:  >>> if (Class == 'SDR 9' or Class == 'SDR9') and Diameter == 450:  # now, the only way this compound statement can eval TRUE is if both 'clauses' # on either side of 'and' are TRUE.  # however, 500 is not equal to 450, so the final eval is FALSE; # the print statement cannot execute.   print 'yes'    # indeed, the print statement does not execute (as it shouldn't).


Hope that is clear.

Enjoy,
Wayne
0 Kudos
AlastairFitzmaurice
New Contributor II
Thank you Wayne, I see what you mean.

All sorted.

regards
0 Kudos