Robin's Blog

How to: Snap points to lines in ArcGIS with Python

I’ve recently starting scripting ArcGIS using Python as part of one of my academic projects (about which I’ll post more later) and needed to be able to snap points to polylines – that is, move points so that they lie on the nearest polyline. An example would help to explain this:

Example image for Snap Point To Line

In the image above, the black line is the relevant polyline, and the blue point is the original point. I wanted this point to lie on the line itself, which it did after processing (the red point).

A number of forum posts I read on the internet about this directed me to Hawth’s Tools for ArcGIS, but sadly these don’t work with ArcGIS 9.3, which is the version I am using. Instead, I wrote the Python code below which does the job using the ArcGIS Near (Analysis) command. The Python code is shown below, and is well commented so that it should be relatively easy to understand.

# ------ Snap Point to Line ------
# Author: Robin Wilson ([email protected])
# Description: Move the points in points so that they
#              lie on top of the nearest line
# --------------------------------
def snap_point_to_line(points, lines):
    # Load the Analysis toolbox so that the Near tool is available
    gp.toolbox = "analysis"

    # Perform the Near operation looking for the nearest line
    # (from the lines Feature Class) to each point (from the
    # points Feature Class). The third argument is the search
    # radius - blank means to search as far as is needed. The
    # fourth argument instructs the command to output the
    # X and Y co-ordinates of the nearest point found to the
    # NEAR_X and NEAR_Y fields of the points Feature Class
    gp.near(points, lines, "", "LOCATION"

    # Create an update cursor for the points Feature Class
    # making sure that the NEAR_X and NEAR_Y fields are included
    # in the return data
    rows = gp.UpdateCursor(points, "", "", "NEAR_X, NEAR_Y")

    row = rows.Next()

    # For each row
    while row:
        # Get the location of the nearest point on one of the lines
        # (added to the file as fields by the Near operation above
        new_x = row.GetValue("NEAR_X")
        new_y = row.GetValue("NEAR_Y")

        # Create a new point object with the new x and y values
        point = gp.CreateObject("Point")
        point.x = new_x
        point.y = new_y

        # Assign it to the shape field
        row.shape = point

        # Update the row data and move to the next row
        rows.UpdateRow(row)
        row = rows.Next()

This script is included in RTWTools for ArcGIS, where it is integrated into an ArcGIS Toolbox.


Categorised as: Academic, GIS, How To


10 Comments

  1. black evony says:

    Searching for this for some time now – i guess luck is more advanced than search engines 🙂

  2. Ivan Villar says:

    Hello
    I served a lot of your audience, but still not solve a problmema I have.
    Let me explain:
    I have a Polyline Feature Class and want to move only the endpoint or the startpoint of each of the lines. You know how I can do this?.
    Thanks!

  3. Sandra says:

    Just great. It could be improve it, but I dont know how to 🙁 , if you make that a new point shapefile must be created (as result of the tool operation) instead of moving the original shapefile (just in case you need to have both of them, the original shapefile point and the snapped one). Greetings from Costa Rica and thank you very much!

  4. Robin Wilson says:

    Hi Sandra – Glad you found it useful. I was thinking of extending it to be able to do that too sometime – I’ll put it on my todo list! I originally implemented it so that it moved the original shapefile because that was the easiest way for me to do it for my project, but I think having the option would be good. i’ll drop you an email when I’ve done that (may be a while though). Cheers, Robin.

  5. Sarah Bergquist says:

    Hi Robin,

    I came across this script and I am curious if you have explored writing one that would snap a point to a line based on attribute information? Specifically I am interested in moving collision location points that were geocoded and offset (based on distance and direction from an intersection) back onto my centerline file. The problem is that sometimes when I do the snapping tool the points snap to other centerlines that are not the correct road (sometimes a perpendicular overhead freeway). Would this be hard to do? I think it would be something like snap to nearest ‘Collisions.PrimaryRd’ = ‘Streets.St_Name’ but I don’t know much about Python.

    Thanks,
    Sarah Bergquist
    San Francisco, Department of Public Health

  6. Robin Wilson says:

    Hi Sarah,

    I’ll have a look into this for you over the next few days and see what I can do.

    Cheers,

    Robin

  7. Bombyx says:

    Thanks a lot for this script! Works very well in ArcGIS 9.3.1.

  8. Rich S says:

    Hi Robin,

    Did you ever get chance to look into Sarah Bergquist’s question regarding a ‘snap by attribute’ tool?

  9. John S says:

    Hi Robin,

    Have you had a a chance to look at Sarah’s request to snap by attribute?

    Thanks

  10. Robin Wilson says:

    Unfortunately I haven’t had a chance, and I’m unlikely to be able to find time. Sorry about that – my PhD has to take priority at the moment.

Leave a Reply

Your email address will not be published. Required fields are marked *