0

I've been trying to write an ArcPy script that gets the nearest point to the endpoint of a line feature and puts the value of a certain attribute into a field of the new layer and updates the row. Been trying to figure this out for weeks but nothing is working for me. I can't use Arcade, I've tried doing spatial join and that also didn't work. My path and everything works perfectly and the layer is being created just fine. but the problem is that the rows that I want updated in the new layer are not updating at all. Here is my code but please assume that all parameters and paths pertaining to things like MakeFeature and SelectByLocation are correct, because I believe that they are since the new layer is being created successfully. I believe there is a flaw with my logic for updating the cursor but I'm not sure where.

   import arcpy
   import numpy as np

   arcpy.MakeFeatureLayer_management(parameter_drop, new_layer)

   arcpy.SelectLayerByLocation_management(new_layer, "within", parameter_poly)
   arcpy.AddMessage("Number of selected features: " + str(arcpy.GetCount_management(new_layer)[0]))

  arcpy.CopyFeatures_management(new_layer, parameter_out)

  arcpy.SelectLayerByLocation_management(parameter_SA, "WITHIN_A_DISTANCE", new_layer, "50 Feet")

  with arcpy.da.UpdateCursor(new_layer, ["SHAPE@", "ADDRESS_TDS_LOCATION_ID"]) as cursor:
    #get XY of endpoints on drop layer and loop through
    for row in cursor:

        #SHAPE@ method
        drop = row[0]
        end_x = drop.lastPoint.X
        end_y = drop.lastPoint.Y
        
        min_distance = float("inf")

        #get XY of SA Layer and loop through features in SA layer
        with arcpy.da.SearchCursor(parameter_SA, ["SHAPE@XY", "ADDRESS_UUID"]) as SA_cursor:
            for SA_row in SA_cursor:
                SA_x, SA_y = SA_row[0]
                distance = np.sqrt((SA_x - end_x) ** 2 + (SA_y - end_y) ** 2)
                
                if distance < min_distance:
                    row[1] = SA_row[1]
                    min_distance = distance
                                   
        cursor.updateRow(row)
2
  • A quick review of your code it seems fine to me, but my question why always the lastpoint, what about the firstpoint? I think to improve this question you need to add some images of your data and a sketch of what YOU think should be correct?
    – Hornbydd
    Commented Feb 7, 2023 at 15:48
  • Numpy function might produce array not scalar value. Try [0] after it when computing distance. Much faster is using Near tool, selection and join field.
    – FelixIP
    Commented Feb 8, 2023 at 4:26

1 Answer 1

1

I would approach the problem in a different way were I you.

You could pull out the point geometry and whatever attributes you want into a list with a search cursor - creating something like [id,attribute1,x,y,z]. Then during the update cursor just go through each line's end point and find the closest point with good old-fashioned math (if it's all numeric data then using numpy arrays can make it faster and easier to find the closest point. Once you do that you've got the attributes in list format, so it should be faster than having nested cursors (I don't recommend doing this)

Here's the pseudocode:

    pointfeature = yourpointfeature
    pt_fields = ["OBJECTID", "feature1", "Shape@X", "Shape@Y"]
    pt_list = []
    with arcpy.da.SearchCursor(pointfeature, fields) as cursor:
        for row in cursor:
            pt_list.append([row[0],row[1], row[2]])
    #Then use this list during your main cursor loop:
    with arcpy.da.SearchCursor(parameter_SA, ["SHAPE@XY", "ADDRESS_UUID"]) as SA_cursor:
                for SA_row in SA_cursor:
                    SA_x, SA_y = SA_row[0]
                    min_dist = 1000.1
                    min_pt = "something"
                    for item in pt_list:
                        dist = sqrt( (SA_x - pt_list[1])**2 + (SA_y - pt_list[2])**2 )
                        if dist < min_dist:
                            min_dist = dist
                            min_pt = item

... and so on. (I'm too lazy to finish it out, but I think it would work - if it's only a slow implementation to solve the problem at hand)

2
  • Thank you. So far I did get it working but its fairly slow, depending how many rows it has to fill. What I do now is store the final value of row[1] in a list and then after I use an Update Cursor to put the contents of the list into the row of the new layer attribute table. I will try using numpy arrays for distance calculations and see if it runs faster. What exactly would I be storing in the numpy array? The data for calculating distance is all numeric. Commented Feb 7, 2023 at 20:35
  • I think after writing your list - "pt_list" in the above code, pt_array = np.asarray(pt_list), and try the same routines with the array instead of the list. I suspect the impact won't be that great. Beyond that you can try putting in timestamps in around your code to see where it slows down. Or a more sophisticated method of timing your code. Just thought of something - were you only looking at the end points of each line? In that case using some sophistication to only pull the first and last vertex from each line for comparison will save you time. Also, for giggles ask OpenAI's chatGPT
    – Smasher
    Commented Mar 13, 2023 at 17:48

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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