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
4 Answers 4
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– Tom2018年06月13日 14:44:32 +00:00Commented Jun 13, 2018 at 14:44
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– Andrew2018年06月12日 18:11:07 +00:00Commented Jun 12, 2018 at 18:11
-
1What 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– SMiller2018年06月13日 20:49:57 +00:00Commented Jun 13, 2018 at 20:49
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
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)
PATH TO FILE
, but to be sure, it's not actually a layer, is it?num = arcpy.GetCount_management(addrs)
will return a result object. You may instead wantnum = arcpy.GetCount_management(addrs).getOutput (0)
arcpy.da.SearchCursor
(which has a completely different syntax and use paradigm).