1

I'm trying to loop through a set of lines and select points within .25 miles of them. I just need the count, so I'm trying to put the results into a list I can print out. The relevant code is below.

When I execute the code, it will loop through twice and then print the list called data. There are actually 35 rows it should loop through. If I comment out everything but printing out the name of the route (first line of the loop), it will successfully execute as I intended.

I found a similar question here: Select Layer By Attribute using loop. However, this question simply ended with the poster figuring out that their cursor was tied up. Not sure exactly what that means or how to resolve it.

Why would the loop execute less times than there are rows, but not produce an error?

fc = r'PATH TO FILE'
inlyr = r'PATH TO FILE'
data = {}
field = 'ROUTE'


arcpy.MakeFeatureLayer_management(fc, 'route')
route = 'route'

arcpy.MakeFeatureLayer_management(inlyr, 'addrs')
addrs = 'addrs'

cursor = arcpy.SearchCursor(fc)

for row in cursor:
    print "ROUTE = \'{}\'".format(row.getValue(field))
    arcpy.SelectLayerByAttribute_management(route, "NEW_SELECTION", "ROUTE = \'{}\'".format(row.getValue(field)))
    arcpy.SelectLayerByLocation_management(addrs, 'WITHIN_A_DISTANCE', route, '.25 Miles')
    num = arcpy.GetCount_management(addrs)
    data.update({row.getValue(field):num})
    del num
del cursor
print data
6
  • Can you provide more context for this code?
    – Tom
    Commented Jun 11, 2018 at 19:51
  • Sure. I edited my original post with the full code.
    – Andrew
    Commented Jun 11, 2018 at 19:56
  • 3
    Whenever I see "cursor only did this x times" my first thought is that the cursor is applied to a layer with a selection. you say fc is PATH TO FILE, but to be sure, it's not actually a layer, is it? Commented Jun 11, 2018 at 20:14
  • 2
    Also num = arcpy.GetCount_management(addrs) will return a result object. You may instead want num = arcpy.GetCount_management(addrs).getOutput (0) Commented Jun 11, 2018 at 20:15
  • 3
    "Old" cursors are effectively deprecated. You should be using arcpy.da.SearchCursor (which has a completely different syntax and use paradigm).
    – Vince
    Commented Jun 11, 2018 at 20:43

4 Answers 4

2

As a complement to the answer already given it is safer to use AddFieldDelimiters when constructing SQL queries. It could be the reason you are not getting expected outcome or there is something wrong with your data or your assumptions.

Adds field delimiters to a field name to allow for use in SQL expressions.

The field delimiters used in an SQL expression differ depending on the format of the queried data. For instance, file geodatabases and shapefiles use double quotation marks (" "), personal geodatabases use square brackets ([ ]), and enterprise geodatabases don't use field delimiters. The function can take away the guess work in ensuring that the field delimiters used with your SQL expression are the correct ones.

I am assuming ROUTE is a text field:

import arcpy

fc1 = r'C:\Path\to.gdb\feature_class'
fc1_fieldname = 'ROUTE'
fc2 = r'C:\Path\to.gdb\feature_class2'

arcpy.MakeFeatureLayer_management(in_features=fc2, out_layer='fc2lyr')
data = {}

with arcpy.da.SearchCursor(fc1,fc1_fieldname) as cursor:
    for row in cursor:
        arcpy.MakeFeatureLayer_management(in_features=fc1, out_layer='fc1lyr', 
                                         where_clause="""{0} = '{1}'""".format(
                                             arcpy.AddFieldDelimiters(datasource=fc1,field=fc1_fieldname), row[0]))
        arcpy.SelectLayerByLocation_management(in_layer='fc2lyr', overlap_type='WITHIN_A_DISTANCE', 
                                              select_features='fc1lyr', 
                                              search_distance='0.25 Miles')
        data[row[0]] = int(arcpy.GetCount_management(fc2lyr).getOutput(0))

print data
2
  • Good call! I never work outside of geodatabases (file/SDE), so I always forget about field delimiters.
    – Tom
    Commented Jun 13, 2018 at 14:44
  • +1 for the use of field delimiter
    – radouxju
    Commented Jun 14, 2018 at 5:20
1

I've rewritten your code using data access cursors and assigning values to variables, where appropriate. Try this, and see if you still get the same result. Don't forget to assign your paths to fc and inlyr.

import arcpy

fc = r'C:\Path\to.gdb\feature_class'
inlyr = r'C:\Path\to\layer.lyr'
data = {}
field = 'ROUTE'

route = 'route'
arcpy.MakeFeatureLayer_management(fc, route)

addrs = 'addrs'
arcpy.MakeFeatureLayer_management(inlyr, addrs)

with arcpy.da.SearchCursor(fc, [field]) as cur:
    for row in cur:
        value = row[0]
        where_clause = "ROUTE = '{}'".format(value)
        print(where_clause)
        arcpy.SelectLayerByAttribute_management(route, "NEW_SELECTION", where_clause)
        arcpy.SelectLayerByLocation_management(addrs, 'WITHIN_A_DISTANCE', route, '0.25 Miles')
        num = int(arcpy.GetCount_management(addrs).getOutput(0))
        data[value] = num

print data
2
  • Thanks for pointing out the usage of depreciated functions. Your code is definitely cleaner than mine. Unfortunately, I'm still getting two loops through the feature layer.
    – Andrew
    Commented Jun 12, 2018 at 18:11
  • 1
    What is the value of the Route field in the third record in the dataset? If you add additional print statements in between each stage, how far along into the second/third loop does it get? Is anything returned by print(arcpy.GetMessages())?
    – SMiller
    Commented Jun 13, 2018 at 20:49
0

Before looking at the technical issue, I should warn you that my proposed solution assumes that you have an unique value for each route. If this is not the case, it would be more efficient to create a list of unique field values, and then loop on this list instead of looping on all features (spatial queries can be heavy, so you should try and reduce their number as much as possible.

My solution is based on the use of geometry object instead of making a new layer feature.

import arcpy

fc1 = r'C:\Path\to.gdb\fc'
field = 'ROUTE'
inlyr = r'C:\Path\to.gdb\other2'#better to point to a feature class than a layer


arcpy.MakeFeatureLayer_management(inlyr, 'lyr')

with arcpy.da.SearchCursor(fc, ['SHAPE@', field]) as cur:
    for row in cur:        
        arcpy.SelectLayerByLocation_management('lyr', 'WITHIN_A_DISTANCE', row[0], '0.25 Miles','NEW_SELECTION')
        data[row[1]] = int(arcpy.GetCount_management('lyr').getOutput(0))
print data
0

Foolowing my first remark about the unicity of the features values, you could simply add one step to extract the unique values in your cursor instead of running several times on the duplicates.

import arcpy

fc = r'C:\Path\to.gdb\feature_class'
inlyr = r'C:\Path\to\layer.shp'
data = {}
field = 'ROUTE'


arcpy.MakeFeatureLayer_management(inlyr, 'lyr')
arcpy.env.overwriteOutput = True #Using overwrite output here to make sure that I create a new selection layer at each iteration



with arcpy.da.SearchCursor(fc, [ field]) as cur:
    uniCur = list(set((cur))) #a set is a collection of unique values, but I convert it back to a list for the iteration
    for row in uniCur:        
        arcpy.MakeFeatureLayer_management(fc , 'lyrroute',"""{0} = '{1}'""".format(arcpy.AddFieldDelimiters(fc,field), row[0])) #if route is not a string field, the use {1} instead of '{1}'
        arcpy.SelectLayerByLocation_management('lyr', 'WITHIN_A_DISTANCE', 'lyrroute' , '0.25 Miles','NEW_SELECTION')
        data[row[0]]= int(arcpy.GetCount_management('lyr').getOutput(0))
    del uniCur


print(data)

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.