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
  • Can you provide more context for this code? – Tom Jun 11 '18 at 19:51
  • Sure. I edited my original post with the full code. – Andrew Jun 11 '18 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? – Emil Brundage Jun 11 '18 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) – Emil Brundage Jun 11 '18 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 Jun 11 '18 at 20:43
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
  • Good call! I never work outside of geodatabases (file/SDE), so I always forget about field delimiters. – Tom Jun 13 '18 at 14:44
  • +1 for the use of field delimiter – radouxju Jun 14 '18 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
  • 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 Jun 12 '18 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 Jun 13 '18 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, privacy policy and cookie policy

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