Arcpy functions not recognizing each others results

875
3
08-19-2020 12:58 PM
MJChurchill
New Contributor III

Thank you in advance for any assistance.

My problem is that arcpy functions do not seem to recognize each others' results.

Specifically: arcpy.da.SearchCursor does not seem to recognize SelectLayerByAttribute having cleared the selection; and SelectLayerByLocation does not recognize either that SelectLayerByAtttribute cleared the selection or that it was then used to make a new selection.

The code sample below is from a longer script which iterates through features selected by the user then uses one of those features, given by the user as a parameter to the tool, to do further analysis. But I have limited the code sample below to the part that is a problem.

I am running the script as a tool in an ArcGIS Pro project. (2.5.0) & the data is a Shapefile of lines.

Note that in the full code, the argument rstart would be the parameter to the tool and would be selected by the user from a list created by the tool validation script (from ROUTENUM values of selected features).

However, for the example, assume that at least one record was selected before the tool was run and the function in the code was run with the call:

generateNewRoute(211)

Here is the code:

import arcpy

## Get references to ArcGIS Pro objects
pro_proj=arcpy.mp.ArcGISProject("CURRENT")
r_map = pro_proj.listMaps("Map")[0]

routelyr = r_map.listLayers("routes")[0]

def generateNewRoute(rstart):

   fields = ['ROUTENUM']
   wc="ROUTENUM = " + str(rstart)
   rnums=[]
   cnums=[]
   nnums=[]

   # correctly prints "ROUTENUM = 211" so SQL seems fine
   arcpy.AddMessage(wc)   

   # Clear any existing selection
   arcpy.SelectLayerByAttribute_management(routelyr, "CLEAR_SELECTION")

   # Check that no records are selected: (This should now return a 
   # list of all records (the behaviour of SearchCursor if no records
   # are selected) but instead returns a list of records that 
   # were selected prior to running the tool
   with arcpy.da.SearchCursor(routelyr, fields) as selectioncleared:
       for n in selectioncleared:
           nnums.append(n[0])
   arcpy.AddMessage("Should be all recs:" + str(nnums))

   # select the feature we want to use in SelectLayerByLocation
   # In this case the feature with ROUTENUM = 211:
   arcpy.SelectLayerByAttribute_management(routelyr, "NEW_SELECTION", where_clause=wc)

   # Check that the record was selected: This correctly prints the message
   # "Selected records: [211]"
   with arcpy.da.SearchCursor(routelyr, fields) as selectedrecs:
       for r in selectedrecs:
           rnums.append(r[0])
   arcpy.AddMessage("Selected records: " + str(rnums))

   # Select records touching the boundary of the selected record.
   arcpy.SelectLayerByLocation_management(routelyr, "boundary_touches", select_features=routelyr, selection_type="NEW_SELECTION")

   # Check the result: This should return a list of records touching 
   # the endpoints of record 211. But, instead it returns a list of 
   # records touching the endpoints of records selected prior to 
   # running the tool (or, if no records were previously selected, a 
   # list of all records that have any endpoints touching an endpoint 
   # of another feature)
   with arcpy.da.SearchCursor(routelyr, fields) as connectedrecs:
       for c in connectedrecs:
           cnums.append(c[0])
    arcpy.AddMessage("Connected records: " + str(rnums))
‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

What I need is a list of the features touching the boundary of a feature selected by SelectLayerByAttribute_management (in the example, record with ROUTENUM = 211 but ultimately with values that would be generated in the code, not from a preexisting selection.)

If someone could tell me what I am doing wrong here, I would be very appreciative.

Thanks,

M.J.

0 Kudos
3 Replies
JoshuaBixby
MVP Esteemed Contributor

Do the results change if you Line 07 is:

routelyr = r_map.listLayers("routes")[0].longName
0 Kudos
MJChurchill
New Contributor III

Yes, they change, but unfortunately not for the better.

With record with ROUTENUM = 218 selected prior to running the tool, the original messages returned by the arcpy.AddMessage lines in the code were:

ROUTENUM = 211

Should be all recs: [218]

Selected records: [211] (Which is the correct selection at this point)

Connected records: [217, 227, 266, 219] 

(Note that these are the records touching the boundaries of record 218 whereas it is a list of records touching the boundaries of record 211 that is needed.)

With line 7 changed to routelyr = r_map.listLayers("routes")[0].longName, messages returned are:

ROUTENUM=211

Should be all recs: [218]

Selected records: [218]

Connected records: [218]

Thank you for your suggestion anyway. Any other ideas?

0 Kudos
MJChurchill
New Contributor III

I think I have figured it out.

The answer is to use arcpy.MakeFeatureLayer_management to make temporary layers of user selected features and the feature passed as a parameter rather than trying to get the tool to recognize what SelectLayerByAttribute has done. So here is the corrected code:

def generateNewRoute(rstart):
   FC=r"C:\GIS_data\base\routes.shp""
   fields = ['ROUTENUM']
   wc="ROUTENUM = " + str(rstart)
        
   cnums=[]
   snums=[]

   # make a temporary layer from the source dataset using a where clause to 
   # select only the desired feature
   arcpy.MakeFeatureLayer_management(FC, "startroute", where_clause=wc)

   # clear any selected features
   arcpy.SelectLayerByAttribute_management(routelyr, "CLEAR_SELECTION")

   # select features touching boundaries of features in the temporary layer (contains only record 211)
   arcpy.SelectLayerByLocation_management(routelyr, "boundary_touches", "startroute", selection_type="NEW_SELECTION")

   # check result: this now outputs the correct list of features touching the 
   # boundaries of record 211
   with arcpy.da.SearchCursor(routelyr, fields) as connectedrecs:
       for c in connectedrecs:
           cnums.append(c[0])
   arcpy.AddMessage("Connected records: " + str(cnums))
‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

I knew there had to be a simple solution!

Thanks to anyone who considered the problem (but I beat you to it ).

Regards,

M.J.

0 Kudos