4

I'm working on a project to identify points that fall along lengths of road. The roads are stored a single featureclass within a file geodatabase, as are the points. I'm using ArcGIS 10.3.

I'm trying to use an arcpy search cursor, configured with a for statement to iterate through my roads dataset. Within the for loop I'm using the function row.getValue to return a 3 digit short integer stored within a field called 'FacilityID' within the attributes of the roads layer. I wish to then use this value to select the appropriate row within the roads layer. Further down the line I would then use this selected row as the basis of a select by location query. At the moment my code doesn't iterate through selections. I can get it to print all the 3 digit integers within the 'FacilityID' field, but it ceases to work if I use the arcpy.SelectLayerByAttribute_management tool.

As I feel I'm not explaining all of this very well, I will include a cut down version of my code:

import arcpy, os
from arcpy import env
arcpy.env.workspace = "C:\Temp\Test.gdb"

env.overwriteOutput = True

ROADS = "Test_Roads"

FIELD = "FacilityID"

roadcursor = arcpy.SearchCursor(roads_lyr)

for row in roadcursor:
    ROADID = (row.getValue(FIELD))
    print ROADID, type(ROADID)

    expression1 = "\"FacilityID\" = " + str(ROADID)
    arcpy.SelectLayerByAttribute_management(roads_lyr, "NEW_SELECTION", expression1)

    arcpy.SelectLayerByAttribute_management(roads_lyr, "REMOVE_FROM_SELECTION", expression1)

I've changed the selection type to 'clear selection' in the second, and get the same result.

  • You are selecting records and then immediately removing those records from selection? You should just be able to use the NEW_SELECTION with each iteration and omit the next selection where you're calling REMOVE_FROM_SELECTION. – crmackey Jan 6 '16 at 16:02
  • Hello. I have the second selection function in there in a bid to get the search cursor to loop through my roads layer. Even if I leave the second function out of the code I get the same result, which is that my script only selects the first row in my roads layer and doesn't loop onto the next. – ABragg Jan 6 '16 at 16:10
  • The second REMOVE_FROM_SELECTION code would be better replaced by a CLEAR_SELECTION outside (after) your for loop. Selection won't affect iterating through a cursor. Also, make sure your layer doesn't have a selection applied to it before you create your cursor object. – Emil Brundage Jan 6 '16 at 16:56
  • It seems you are trying to identify incidents by roads, perhaps a hot spot analysis by determining how many accidents there are on any one given road and that's why you want to select by location, e.g. for road ID 999, select accidents that are within 30 feet (whatever the offset is). If this is the case is it possible to perform a spatial join with your street features as the target and the points layer as the join features and then doing a one to many join? – geoJshaun Jan 6 '16 at 17:31
  • 1
    Any particular reason why you are not using cursors from the arcpy.da module? – Nxaunxau Jan 7 '16 at 15:23
2

My preferred method for iterating through records and selecting each one is as follows. Kind of long winded here, but all the functions are very useful for this kind of thing.

import arcpy, os

# Create a script tool
roadFeatures = arcpy.GetParameterAsText(0)
field = arcpy.GetParameterAsText(0)  #in the tool setup, use the "obtain from" setting and set it to the road features

#Or, just assign your data, as you did previously
#
#roadFeatures = "Test_Roads"
#field = "FacilityID"

## I use these 3 functions all the time, very handy ##

def getFieldList(fc):  #return list of strings for field names
    fieldObjects = arcpy.ListFields(fc)
    fieldList = []
    for field in fieldObjects:
        fieldList.append(field.name)
    return fieldList

def createWhereClause(table, field, valueList):  #builds a where clause so you dont have to!                     
    fieldDelimited = arcpy.AddFieldDelimiters(arcpy.Describe(table).path, field) 
    fieldType = arcpy.ListFields(table, field)[0].type                            
    if str(fieldType) == 'String':                                                
        valueList = ["'%s'" % value for value in valueList]                             
    whereClause = "%s IN(%s)" % (fieldDelimited, ', '.join(map(str, valueList)))        
    return whereClause

def returnFieldIndex(inFC, fieldName):  #returns int index of specified field
    fieldList = getFieldList(inFC)
    index = 0
    try:
        for fld in fieldList:
            if fieldName == fld:
                return int(index)
                index += 1
            else:
                index += 1
    except:
        arcpy.AddMessage("Error in returning field index.")

################################################################


fieldList = getFieldList(roadFeatures)

fieldIndex = returnFieldIndex(roadFeatures, field)

arcpy.MakeFeatureLayer(roadFeatures, "roadsLayer")

with arcpy.da.SearchCursor("roadsLayer", (fieldList)) as cursor:
    for row in cursor:
        #This line creates a where clause that basically says, "make a clause for the row with the object ID
        #that I am currently iterating".
        whereClause = createWhereClause("roadsLayer", field, [row[fieldIndex]])
        arcpy.SelectLayerByAttribute_management("roadsLayer", "CLEAR_SELECTION")
        arcpy.SelectLayerByAttribute_management("roadsLayer", "NEW_SELECTION", whereClause)
        #Now perform all of the other code you need on the "roadsLayer" which will have the current row selected.

The script works by selecting each row based on the "field" index.

Psuedo: for each row in the dataset get the "field" value and then select the row with the field value (aka, the current row)

Note: If you are assigning a layer to the roadFeatures object, you will not need the MakeFeatureLayer line.

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.