Select to view content in your preferred language

Use ArcGIS API for Python to snap points to nearest line?

03-03-2020 11:02 AM
Occasional Contributor

I'm trying to snap multiple point features to a line using the arcgis API for Python. The arcpy method isn't viable for the end-users of this tool as they don't have consistent access to an Advanced Use license.

What I'd like to be able to do is find the nearest line to each point, then snap that point to that nearest line. I've tried two methods here, iterating through the features in the feature service as below...

import arcgis
from arcgis.features import FeatureLayer, use_proximity
from arcgis.geometry import Geometry, Point, Polyline

point_svc = "service url"
line_svc = "service url"

point_ft = FeatureLayer(point_svc).query().features
line_ft = FeatureLayer(line_svc)

# Go through each point in the point feature layer, and find its nearest line feature. Then,
#snap that given point to the nearest line feature.
for p in point_ft:
    ## The FeatureInput documentation states that both the analysis and near 
    ##features need to   be items, a FeatureLayer or FeatureCollection instance, or a Feature 
    ##Service URL string. 
    nearest = use_proximity.find_nearest(p, line_ft)
    new_pt = p.snap_to_line(nearest)


This option, predictably according to the FeatureInput documentation, doesn't like the input layer formats.

What does work for at least creating a nearest line layer is using the point_svc and line_svc as inputs, but I'm very lost as to how I can use the resulting feature layer collections to snap the points to the lines...

nearest = use_proximity.find_nearest(point_svc, line_svc)
{'nearest_layer': <FeatureCollection>, 'connecting_lines_layer': <FeatureCollection>}‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

The 'nearest_layer' Feature Collection that's output has a "SNAP_" and "SNAP_ID" field that I would assume relate to the Object ID of the points in the analysis layer, but unfortunately, they don't relate, and I can find no other field in that output Feature Collection that relates to the point on which the find_nearest was based (unless find_nearest doesn't compare features to features, but rather entire services to services...).

Point service OIDs (three points in total):

find_nearest output Feature Collection item attributes:

Does anyone know any cleaner methods of accomplishing this task using the API, or how to then work with the nearest feature collection to then reference the points in the points feature service to those nearest lines and then snap them?

0 Kudos
2 Replies
Esri Contributor

Hi Emma!

Maybe look at this method (GeoSeriesAccessor.snap_to_line):

arcgis.features module — arcgis 1.7.1 documentation 

You may need to iterate over your points, find the nearest line to each point, and then run the snap_to_line function against it.  That is where I would start.  There are probably other ways as well, but I would try this and see what kind of results you get.


0 Kudos
Occasional Contributor

Hi Scott!

Thanks for the response! I'll try the GeoSeriesAccessor version of snap_to_line instead of Geometry & Features.

I described above the hang-up with the finding nearest line to each point step: the input layers for the both the analysis and use_proximity packages find_nearest tool require that the analysis_layer and near_ layer inputs both have to be in one of the following formats (not a geometry):

Feature Input

All GeoAnalytics Tools have input parameters that take features as their input. Features can be input as:

  • Big data file share layer. These can be obtained by using the layers property of big data file share items.

  • Item (of type Feature Layer Collection or Feature Collection) - only the first feature layer is used.

  • Instance of FeatureLayer, FeatureLayerCollection, FeatureCollection.

  • Feature Service URL as a string.

  • Python dict in the feature collection format

... it's so close, but those acceptable inputs for the find_nearest functions make it so far!

0 Kudos