Snapping Point Feature to Selected Line feature In Loop Using Search Cursor

551
5
03-11-2021 04:54 PM
ClintBoaz1
New Contributor III

I am trying to use the search cursor to read through a point shapefile's (road drainage pipes) attribute table and, when a condition is met (row[0] == 'yes'), select a separate line feature (roads) based on an attribute of the point feature (each road drainage pipe point has an attribute for the road it is on) to force the arcpy.edit.snap tool to snap that point to the nearest spot on the edge of that specific line (road).  The script runs but all points (not just the ones meeting the condition) are snapped to the nearest spot on nearest line (not the specified line).  Here is that part of my code so far.  Any help would be appreciated.  

RMapPts = outPutPath + '/Form_1.shp'
query = """'{0}' = '{1}'""".format(arcpy.AddFieldDelimiters(Roads, 'ROAD_MAP_LABEL'),
arcpy.AddFieldDelimiters(RMapPts, "WhatRoad"))
cursor = arcpy.da.SearchCursor(RMapPts, 'NewSite')

for row in cursor:
if row[0] == "yes":
arcpy.SelectLayerByAttribute_management(Roads, 'NEW_SELECTION', query)
arcpy.edit.Snap(RMapPts, [[Roads, "EDGE", "500 Feet"]])

 

0 Kudos
5 Replies
JeffK
by MVP Regular Contributor
MVP Regular Contributor

It looks like you are passing the whole point featureclass to the snap method without isolating the feature that is "yes".  You need to select the feature in that featureclass that satisfies the conditional and pass it to the snap method.  ... I am not sure if this will work since the documentation only provides Featureclass as input but its worth a shot.  Something like:

RMapPts = outPutPath + '/Form_1.shp'
query = """'{0}' = '{1}'""".format(arcpy.AddFieldDelimiters(Roads, 'ROAD_MAP_LABEL'),
                                   arcpy.AddFieldDelimiters(RMapPts, "WhatRoad"))
with arcpy.da.SearchCursor(RMapPts, 'NewSite', 'OBJECTID')as cur: # or FID? or ID?
    for row in cur:
        if row[0] == "yes":
            sqlQ = """OBJECTID = {}""".format(row[2]) # or FID? or ID?
            selPts = arcpy.SelectLayerbyAttribute_management(RMapPts, 'NEW_SELECTION', sqlQ)
            arcpy.SelectLayerByAttribute_management(Roads, 'NEW_SELECTION', query)
        arcpy.edit.Snap(selPts, [[Roads, "EDGE", "500 Feet"]])

 

0 Kudos
ClintBoaz1
New Contributor III

Hey Jeff,

Thanks for the reply.  With your help I am able to get the script to only snap those points meeting the condition, however it is continuing to snap them to the nearest road and not the specified road.  I have tried moving that query into the loop and also tried nesting another cursor loop, looking into the roads feature but both were unsuccessful.  Do you have any other ideas on getting the roads to select within the loop?  Here is my adjusted code:

RMapPts = outPutPath + '/Form_1.shp'
query = """'{}' = '{}'""".format(arcpy.AddFieldDelimiters(RMapPts, "WhatRoad"), arcpy.AddFieldDelimiters(Roads, 'ROAD_MAP_LABEL'))

with arcpy.da.SearchCursor(RMapPts,["NewSite", "globalid"]) as cur:
for row in cur:
if row[0] == 'yes':
sqlQ = """globalid = '{}'""".format(row[1])
selPts = arcpy.SelectLayerByAttribute_management(RMapPts, 'NEW_SELECTION', sqlQ)
selRoads = arcpy.SelectLayerByAttribute_management(Roads, "NEW_SELECTION", query)
arcpy.Snap_edit(selPts, [[selRoads, "EDGE", "500 Feet"]])

 

0 Kudos
JeffK
by MVP Regular Contributor
MVP Regular Contributor

Well that is cool!  I think that could be a limitation of the Snap process.  It defaults to the nearest feature regardless if the layer has features selected... So we might get around this by creating a pseudo featureclass in memory, that only has the selected road.  It will get overwritten in each iteration so it should limit the Snap method the option of what was selected by the query.

 

env.overwriteOutput = True
in_memory = "in_memory\\"

RMapPts = outPutPath + '/Form_1.shp'
query = """'{}' = '{}'""".format(arcpy.AddFieldDelimiters(RMapPts, "WhatRoad"), arcpy.AddFieldDelimiters(Roads, 'ROAD_MAP_LABEL'))


with arcpy.da.SearchCursor(RMapPts, ["NewSite", "globalid"]) as cur:
    for row in cur:
        if row[0] == 'yes':
            sqlQ = """globalid = '{}'""".format(row[1])
            selPts = arcpy.SelectLayerByAttribute_management(RMapPts, 'NEW_SELECTION', sqlQ)
            # selRoads = arcpy.SelectLayerByAttribute_management(Roads, "NEW_SELECTION", query)
            psedoLyr = arcpy.FeatureClassToFeatureClass_conversion(Roads, in_memory, 'SelRoads', query)

            arcpy.Snap_edit(selPts, [[psedoLyr, "EDGE", "500 Feet"]])

 

0 Kudos
ClintBoaz1
New Contributor III

Thanks for being so responsive Jeff.  I tried this method and none of the points were snapped...  A confusing change of output. I did test the Snap_edit functionality in ArcGIS Pro before starting to script (I work with the mapping software more than I work with Python as you can probably tell from my very rudimentary understands of Python) and it does recognize and move only selected points to the selected line feature.  I tried saving the FeatureClassToFeatureClass_conversion to a permanent location to see what it was doing and it was an empty feature.  There seems to be a problem with the query actually selecting the roads but after double checking the fields and trying some other tweaks with no success I am at a loss.  Any Ideas would again be much appreciated.

0 Kudos
JeffK
by MVP Regular Contributor
MVP Regular Contributor

I might have used the wrong method (FeatureClassToFeatureClass_conversion)...  We can try CopyFeatures and use the selection as an input.  You may need to check the output path to the in memory space- you might want to try to output it at a physical location to check if the selected road is being copied.  If it works with the physical save, you can use that output path as an input into the Snap.  I was trying to save a lot of write/read operations by using the memory space.

with arcpy.da.SearchCursor(RMapPts, ["NewSite", "globalid"]) as cur:
    for row in cur:
        if row[0] == 'yes':
            sqlQ = """globalid = '{}'""".format(row[1])
            selPts = arcpy.SelectLayerByAttribute_management(RMapPts, 'NEW_SELECTION', sqlQ)
            selRoads = arcpy.SelectLayerByAttribute_management(Roads, "NEW_SELECTION", query)
            psedoLyr = arcpy.CopyFeatures_management(query, in_memory + 'SelRoads')

            arcpy.Snap_edit(selPts, [[psedoLyr, "EDGE", "500 Feet"]])

 

0 Kudos