0

I have a script in ArcPy that iterates through a set of intersection points and determines if all intersecting streets have the same attribute value in the CROSSLTS field, and if they do, sets the the intersection point's MarkForProcessing field value to 1. if the intersecting segments do not have identical CROSSLTS values, it sets the MarkForProcessing field value to 0.

When I run this script from the Python window of ArcMap, it takes 2 hours and I get an "out of memory" message before it completes. when i run it from PyCharm, it takes roughly 10 minutes, but the MarkForProcessing field is never updated.

Can someone could take a look?

import arcpy
workspace = 'C:\SRC\Bikestress\LTS classification.gdb'
arcpy.env.overwriteOutput = True

##check if all elements in a list are identical, returns true if so.
def checkEqual(lst):
    return lst.count(lst[0]) == len(lst)

arcpy.MakeFeatureLayer_management(r'C:\SRC\Bikestress\LTS classification.gdb\Intersections','INTERSECTIONSLYR','',workspace)
arcpy.MakeFeatureLayer_management(r'C:\SRC\Bikestress\LTS classification.gdb\roadmidsplit2','STREETSLYR','',workspace)

Intersectionfields = ["CONTROLTYPE","GLOBALID","MarkForProcessing","SHAPE@"]
StreetsFields = ["CROSS_LTS"]

count = 0
with arcpy.da.UpdateCursor('INTERSECTIONSLYR', Intersectionfields) as IntersectionCursor:
    for Intersection in IntersectionCursor:
        count += 1
        if Intersection[0] not in ["4STOP", "PED", "TRAFFICSIG"]:

            # select the intersection of the current row, and all adjacent segments
            arcpy.SelectLayerByLocation_management('STREETSLYR', "INTERSECT", Intersection[3], "", "NEW_SELECTION")

            CROSSLIST = []

            #make sure selection is not empty
            desc = arcpy.Describe('STREETSLYR')

            if desc.FIDSet == '':

                with arcpy.da.SearchCursor('STREETSLYR', StreetsFields) as StreetCursor:
                    for Street in StreetCursor:
                        CROSSLIST.append(Street[0])

                if len(CROSSLIST) != 0:
                    if not checkEqual(CROSSLIST):
                        Intersection[2] = 1
                    else:
                        Intersection[2] = 0

            IntersectionCursor.updateRow(Intersection)
        if str(count)[-2:] == "00":
            print(str(count) + " records processed")
print('writing intersections layer...')
arcpy.CopyFeatures_management("INTERSECTIONSLYR", r'C:\SRC\Bikestress\LTS classification.gdb\IntersectionsUpdated')
print("done")
  • 1
    Have you tried testing your code from IDLE? – PolyGeo Oct 10 '18 at 19:23
  • 1
    Im pretty sure you cant use a geometry (SHAPE@) as selecting feature in SelectLayerByLocation. Instead create a feature layer for each row using object id and use the layer as selecting feature – BERA Oct 10 '18 at 19:31
  • 1
    What does this check?: if desc.FIDSet == '': – BERA Oct 10 '18 at 19:40
  • 1
    @BERA it checks that the street selection is not empty. i got an error about iterating through empty geometry before I put that line in – Alex Oct 10 '18 at 19:42
  • 1
    I cant find the help section for FIDSet but from other sources it looks like it should be a string holding the objectids of the selected features. So your if statements should not work as expected – BERA Oct 10 '18 at 20:09
1

Im not sure why your code does not work or why you get memory error but you could try some things:

  1. You dont need a function to check if all list elements are the same, use the set datatype which by definition cant contain duplicates. If len of the set is different from len of the list, you have duplicates
  2. A geometry (SHAPE@) cant be used as selecting features, it must be a layer. Create a layer for each row instead using OID.
  3. Indentent updateRow one level, no need to update row if you dont assign a new value.

Try using Spatial Join instead:

The reason your code is running so slow is that it has to execute Select By Location once for each row. Instead use Spatial Join to check the relationships once. Try:

enter image description here

Then:

import arcpy
from collections import defaultdict
arcpy.env.workspace = r'C:\Default.gdb'

spatjoin = 'Intersections_SpatialJoin_Roads'
spatjoinfields = ['TARGET_FID','Roadname']

intersections = 'Intersections'
field_to_update = 'Roadcheck'

d = defaultdict(list)

with arcpy.da.SearchCursor(spatjoin,spatjoinfields) as cursor:
    for target_fid, roadname in cursor:
        d[target_fid].append(roadname)

updatedict = {}
for key,value in d.items(): #d.iteritems() in python2
    if None in value: #If no roads are found
        updatedict[key] = 3
    elif len(set(value))==1:
        updatedict[key] = 1
    else:
        updatedict[key] = 0

with arcpy.da.UpdateCursor(intersections,['OID@',field_to_update]) as cursor:
    for row in cursor:
        if row[0] in updatedict:
            row[1] = updatedict[row[0]]
            cursor.updateRow(row)

enter image description here

  • thanks, trying this now. it should take about an hour and a half at this rate (~16,000 entries), however, so I will get back to you later. – Alex Oct 10 '18 at 20:07
  • 1
    @Alex i have deleted the first code and added a way using Spatial Join. Try this instead. – BERA Oct 11 '18 at 6:42
  • I will add that when I ran the script in the arcgis python console, using @SHAPE DID work, but it did not work outside of arcGIS. Thanks again! – Alex Oct 23 '18 at 14:09

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.