3

I have set up a program that calculates the relationship between a point and the first point of a polyline. The aim of the program is to run this calculation and then copy the result to a certain field in the attribute table. However, if the cell/field is already occupied it copies to the next field in line and so on.

This runs pretty smoothly in most cases. However, if the result/calculation happens to return a negative number all hell breaks loose. When the negative number is returned the loop registers the result in the correct up/down link column but seems to ignore the command to check if the cell is already occupied. This leads to other valid data being overwritten.

I'm not sure whether this is a result of the way I have set up my 'and'/'or' operators or whether I modify the way I use negative numbers in python.

Below is an example of the trouble I have been having. If anyone has any ideas please let me know.

q_fid = 1
calculation = -30
linkup = "EDRN21"
linkup2 = "EDRN03"
linkup3 = " "
linkdown = "EDRN10"
linkdown2 = " "
linkdown3 = " "
link_id = "EDRN44"

arcpy.MakeFeatureLayer_management("uk_cities", "node_feature") 
arcpy.SelectLayerByAttribute_management ("node_feature", "NEW_SELECTION", '\"FID\" =  {0}'.format(q_fid))

rows = arcpy.UpdateCursor("node_feature")
for row in rows:
    if calculation < -0.001 or calculation > 0.001 and linkup == " ":
        row.setValue("Up_LinkA", link_id)
    elif calculation < -0.001 or calculation > 0.001 and linkup2 == " ":
        row.setValue("Up_LinkB", link_id)
    elif calculation < -0.001 or calculation > 0.001 and linkup3 == " ":
        row.setValue("Up_LinkC", link_id)
    elif calculation > -0.001 and calculation < 0.001 and linkdown == " ":
        row.setValue("Down_LinkA", link_id)
    elif calculation > -0.001 and calculation < 0.001 and linkdown2 == " ":
        row.setValue("Down_LinkB", link_id)
    elif calculation > -0.001 and calculation < 0.001 and linkdown3 == " ":
        row.setValue("Down_LinkC", link_id)
    rows.updateRow(row)

4 Answers 4

8

I would group with parens as follows

if (calculation < -0.001 or calculation > 0.001) and linkup == " ":
3
  • 4
    +1 Mixing or and and without explicit parenthesis is a recipe for inconsistent results across languages
    – Vince
    Commented Sep 26, 2014 at 17:40
  • A better condition to use is Commented Sep 26, 2014 at 18:06
  • Thanks, I've tested the above code with the suggested parenthesis and it seems to work.
    – Geord359
    Commented Sep 27, 2014 at 18:25
5

The current conditional seems to be interpreted as "if the condition is less than -0.001, or if condition is > 0.001 as well as linkup being blank".

If the condition is negative (e.g. calculation = -30) then Python is essentially deciding it's met the first condition and it therefore does not need to look at the subsequent conditions.

if (calculation < -0.001 or calculation > 0.001) and linkup == " ":

By explicitly grouping the calculation conditions, you mandate the linkup condition has to be considered along with either calculation condition, not just the second one.


As an alternative to grouping with parentheses, you could break the conditions down further. It's less compact (and probably less Pythonic) but I find it more readable. Just an idea.

for row in rows:
    if (calculation < -0.001 or calculation > 0.001):
        if linkup == " ":
            row.setValue("Up_LinkA", link_id)
        elif linkup2 == " ":
            row.setValue("Up_LinkB", link_id)
        elif linkup3 == " ":
            row.setValue("Up_LinkB", link_id)
    elif (calculation > -0.001 and calculation < 0.001):
        if linkdown == " ":
            row.setValue("Down_LinkA", link_id)
        elif linkdown2 == " ":
            row.setValue("Down_LinkB", link_id)
        elif linkdown3 == " ":
            row.setValue("Down_LinkC", link_id)
    rows.updateRow(row)
4
  • I think the real problem is that in Python "and" has a higher operator precedence than "or" so the implicit grouping of "if A or B and C" is "if A or (B and C)" Commented Sep 26, 2014 at 18:22
  • True. You expressed that much better than I managed to.
    – Erica
    Commented Sep 26, 2014 at 18:23
  • Your nesting (and Curtis below) eliminates repeated evaluation of the same condition. Commented Sep 26, 2014 at 18:26
  • Thanks for the suggestion. I agree, the way you have set it out is more readable and initially I thought this would be the most likely answer. However, It seems to run into difficulties in the linkup2 line. It, again, ignores the instruction to only write the data if the cell is empty. No idea why that's happening.
    – Geord359
    Commented Sep 27, 2014 at 18:35
2

I would change your cursor syntax to the following:

with arcpy.da.UpdateCursor("node feature") as cursor:
    for row in cursor:
         - your existing code here --

    cursor.updateRow(row)    

This syntax does a much better job of releasing the cursor when your'e done with it. Also. the data access module or "arcpy.da." is much faster. Is the problem with an attribute field properties?

Are you creating variables for each field? If so you could use arcpy.ListFields() to generate a list of them and add delimiters to ensure your queries work properly.

1
  • I agree. Unfortunately, the poster tagged the question as 10.0 -- arcpy.da cursors were added at 10.1. Commented Sep 26, 2014 at 18:10
2

You left out the case where calculation == .001. I also recommend trying the abs function to simplify your logic:

if abs(calculation) <= 0.001:
    # ...
else:
    # ...

Side note: you don't need a layer to be created - cursors (both flavors) support defining a where expression when you create them.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.