I am quite new to python.

As you can see from the image attached to this post. I have polylines with From junctions (fnode) and to junctions(tnode) field. My goal is as following:

To update draw order field of the path of the line from start point (from Links description field), through good links until I come across bad links. I wrote the following code but the loop stops at draw order 3 and doesn't continue, any idea what is wrong?

import arcpy # import moudle
from arcpy import env # import env
env.workspace = r"F:\onedrive\gtfsfilescut\3.3.16\bus289.gdb"
env.overwriteOutput = True

fields = ['FJUNCTION','TJUNCTION', 'freq_fnode' , 'freq_tnode','Links_Description','Draw_Order','Was_Used','Test_Field' ,'USERID' ]

ctr = 1

with arcpy.da.UpdateCursor(fcName, fields) as cursor:

for row in cursor:

    if (row[4] == "Start"): # check if link description is start
        row[5]  = ctr # update draw order
        row[6] = "Yes" # update was used

        for row2 in cursor:
            if (row[8] != row2[8]):
                if (row[0] == row2[0] or row[0] == row2[1] or row[1] == row2[1] or row[1] == row2[0]):
                    row2[6] = "Yes"
                    ctr = ctr + 1
                    row2[5] =  ctr

  with arcpy.da.UpdateCursor(fcName, fields) as cursor2:

for row in cursor2:

    if (row[4] == "Good" and row[5] == ctr): # check if link description is start

        for row2 in cursor2:
            if row[8] != row2[8]:
                if (row[0] == row2[0] or row[0] == row2[1] or row[1] == row2[0] or row[1] == row2[1] or row2[0] == row[0] or row2[0] == row[1]):
                    row2[6] = "Yes"
                    ctr = ctr +1
                    row2[5] =  ctr

alsot tried this code based on @richard suggestion to use a dict key but it doesn't seem to work for me the code does nothing when I run it:

 fields = ['FJUNCTION','TJUNCTION','freq_fnode','freq_tnode','Links_Description','Draw_Order','Was_Used','Test_Field' ,'USERID','OBJECTID' ]

def rows_as_update_dicts(cursor):
   colnames = cursor.fields
   for row in cursor:
       row_object = dict(zip(colnames, row))
       yield row_object
       cursor.updateRow([row_object[colname] for colname in colnames])

with arcpy.da.UpdateCursor(fcName, fields) as cursor:
    for row in rows_as_update_dicts(cursor):
       if (row['Links_Description'] == "Good" and row['Draw_Order'] == ctr): 
         for row2 in rows_as_update_dicts(cursor):
           if row['USERID'] != row['USERID']:
              if (row['FJUNCTION'] == row2['FJUNCTION'] or row['FJUNCTION'] == row2['TJUNCTION'] or row['TJUNCTION'] == row2['FJUNCTION'] or row[1] == row2['TJUNCTION'] or row2['FJUNCTION'] == row['FJUNCTION'] or row2['FJUNCTION'] == row['TJUNCTION']):
                row2['Was_Used'] = "Yes"
                ctr = ctr +1
                row2['Draw_Order'] =  ctr

here is the data table: here is data table the

  • 1
    A couple of comments, firstly, it could be a copy/paste thing, but it doesn't look like your indentation is correct. Secondly, I'm not sure you're using cursors correctly. I'm a bit confused as to why you have a nested for loop in your UpdateCursor. Can you clarify what you mean by "Good links" and "bad links"? You could also try using the next() method to get the next row rather than the previous row.
    – Fezter
    Mar 23 '16 at 22:32
  • Hey, yea its a copy paste thing wil fix it. I have a nested loop because i need to traverse from the first node to the second and then to the fourth and so on with a condition of good links (bad ones are ones I wont be using). I think the problem is that that the update cursor doesn't go back only forward. each draw order is based on the previous link....
    – golan
    Mar 23 '16 at 22:50
  • Your cursor code will never work. Each pair of embedded cursor for loops will only compare one row to the rest of the rows after that row in the cursor and then stop, since the cursor only goes forward. One comparison per cursor is horrible. Anyway, the best approach is to use a dictionary loaded from a search cursor and then process a single updatecursor that references the dictionary as a look up. The dictionary key is critical, pointing to a list of lists of field values. The list of lists can be sorted if the field order is correct. To code this I'd need to see a record set example. Mar 24 '16 at 2:05
  • My script for creating intersection points from a line network uses basically the same matching technique I am describing, but outputs to an insert cursor rather than writing back to an update cursor. geonet.esri.com/thread/113984 Mar 24 '16 at 2:11
  • i have added the initial record set to my post @RichardFairhurst First of all thanks everyone! here is the initial record set example before using my code (keep in mind that my goal is to go from the first link to all the good links in a draw order based on the previous link -via "Link Descrpition field" and the values are "First" and "Good" : imgur.com/VUj3cGF and here is the record set after using the good (you can see the loop stops at draw order 3
    – golan
    Mar 26 '16 at 12:10

I only used the "Links_Description", "USERID", "FJUNCTION", TJUNCTION", and "Draw Order" fields. My "Links_Description" field only had "Start" and "Good" values since I was not sure how you might determine a "Bad" or a "Finish" link.

There was no Case field to separate any link where they formed branches, so the code treated all branched links as the same counter. Since the first "Start" link traced out all possible links, it assigned itself and all "Good" links (85 out of 92) with a draw order that originated from that link. The pictures illustrate the results. All "Start" links are thick lines.

  • The Following is Edited based on revised code posted March 27, 2016 at 6:40 AM

The code took only about 12 seconds to process my sample data. This may not be exactly what you are looking for, but something like this approach is the only way to deal with this problem. The code is not trivial. It uses recursion to deal with the "Good" links calling to other "Good" links. I had to struggle for quite a while with the branching, since many of my first attempts resulted in an infinite loop at the first 3 way branch. The inclusion of the traceDict Dictionary to keep track of previously traced links and counter was critical to avoid having the code loop back on itself and to assigning each link its own Draw_Order value.

There are some anomalies in the recursion logic that I have not figured out. The code manages to trace all of the links it should, but in some cases it does not seem to keep the counter in the expected order. When it skips an expected link it reaches the end of the other links and then traces the missed links in a backward order. There is a pattern, and I suspect it has to do with the USERID sequence being favored over the Junction numbering in my goodDict, but at the moment I cannot explain this behavior.

Let me know if you might create a case field that would create separate trace groupings which could be used to avoid certain branches that should favor another "Start" link.

import arcpy  
import os  
from arcpy import env  
from time import strftime  

print "Start script: " + strftime("%Y-%m-%d %H:%M:%S")  

def goodLinks(link, ctr, goodDict, tracedDict):
    if link in goodDict:
        for goodValues in goodDict[link][0]:
            if not goodValues[0] in tracedDict:
                ctr += 1
                tracedDict[goodValues[0]] = ctr
                print("Junction {0} is linked to link {1} Junction {2} counter {3}".format(link, goodValues[0], goodValues[1], ctr))
            for goodValue in goodDict[goodValues[1]][0]:
                if not goodValue[0] in tracedDict:
                    myValue = goodValue[1]
                    #if myValue != link:
                    if myValue in goodDict:
                        ctr = goodLinks(myValue, ctr, goodDict, tracedDict)
                        #print("Counter is {0}".format(ctr))
        return ctr
    return ctr

# Customize the workspace path to fit your data  
env.workspace = r"C:\Users\OWNER\Documents\ArcGIS\Default.gdb"  
env.overwriteOutput = True  

fc = r'Export_Output_4'

fields = ["Links_Description", "USERID", "FJUNCTION", "TJUNCTION", "Draw_Order"]
StartDict = {}
goodDict = {}
tracedDict = {}
with arcpy.da.SearchCursor(fc, fields) as searchRows:        
    for row in searchRows:
        if row[0] == "Start":
            if not row[1] in StartDict:
                StartDict[row[1]] = [[row[2], row[3]], 0]
            else:                if not row[2] in StartDict[row[1]][0]:
                if not row[3] in StartDict[row[1]][0]:
        elif row[0] == "Good":
            if not row[2] in goodDict:
            goodDict[row[2]] = [[[row[1], row[3]]], 0]
        elif not [row[1], row[3]] in goodDict[row[2]][0]:
            goodDict[row[2]][0].append([row[1], row[3]])
        if not row[3] in goodDict:
            goodDict[row[3]] = [[[row[1], row[2]]], 0]
        elif not [row[1], row[2]] in goodDict[row[3]][0]:
            goodDict[row[3]][0].append([row[1], row[2]])

for key in goodDict:
    goodDict[key][0] = sorted(goodDict[key][0])

ctr = 0
for keyValue in sorted(StartDict.keys()):
    StartValues = StartDict[keyValue][0]
    if not keyValue in tracedDict:
        ctr += 1
        tracedDict[keyValue] = ctr
        for StartValue in StartValues:
            print('link {0} Junction {1} is counter {2}'.format( keyValue, StartValue, ctr))
            for StartValue in StartDict[keyValue][0]:
                ctr = goodLinks(StartValue, ctr, goodDict, tracedDict)

with arcpy.da.UpdateCursor(fc, fields) as updateRows:        
    for row in updateRows:
        if row[1] in tracedDict:
            row[4] = tracedDict[row[1]]

print "Finished script: " + strftime("%Y-%m-%d %H:%M:%S")  

Tracing Results

Tracing Detail

Trace Table

Trace From First Start Link

  • Wow @RichardFairhurst this works perfect! you even fixed the counter problem! the code is a bit difficult for me to understand yet, since I have poor knowledge of pyhton. but I am doing my best to understand it line by line wish the code was simple for me but at least it works! my next step will be to stop at my first "bad link". after doing so to check another table of points for its "shape_pt_sequence" (kinda like draw order) and to check if there is a branch intersecting with "shape_pt_sequence" and to continue the draw order from there where - the lowest/next "shape_pt_sequence" is
    – golan
    Mar 30 '16 at 16:45
  • So in the first image (the bottom one) you can see the last "good link" before the first bad link (with draw order = 6 and with yellow color). you can see 3 bad links (in purple). I need to pick the side I want traverse to (left or right). To do so I am taking the upper table (from the img link) there you can see the points layer with its own Shape Sequence. Based on that I need to traverse to the from the intersection of the first table with this table via the draw order of next lower number. my draw order will traverse left (52-55) not right (222) in this example. imgur.com/a/PHk4S
    – golan
    Mar 30 '16 at 17:11
  • golan:I have looked at your picture, but I am not really understanding what you are describing that you want. Given that this code solved the original question in dealing with the Start and Good links, you should start a new question that has a link referencing this one and open a discussion on how to extend the code to deal with addition rules for the Bad links (and Finish links if necessary). This is especially true if you want to add some kind of compass/edge/turns awareness to the code. The code has no clue about the real world, just a set of numbers in your data connected to "objects". Mar 30 '16 at 19:39
  • I will do so! Thanks again you pointed me to the right direction with the code for sure!
    – golan
    Mar 30 '16 at 20:59

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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