# Snap points to polygon/lines in python shapely?

I have a shapefile of point features

And a shapefile of polygons features

I would like to snap these points to the polygons, as they are often just outside the polygons and cannot be spatially joined.

How do I snap the points to the polygon edge if they are within a range of around 100m or so? One thing I tried was to convert the polygon boundary into a line feature and then snap(), but it didn't modify the geometry no mater what the tolerance was

``````res = point
lines2_union = parcel_as_lines.geometry.unary_union
res.geometry = point.geometry.apply(lambda x: snap(x, lines2_union, 999999999999999999999999999))
``````

sjoin_nearest to find any polygons within your tolerance. Measure distance from point to polygon. If the distance is below your tolerance and more than 0, snap. Else leave the point unchanged:

``````import geopandas as gpd
from shapely.ops import snap, nearest_points

snapdist = 100 #The distance from point to polygon to search and snap
output = r"/home/bera/Desktop/GIStest/500_points_snapped.geojson"

#To measure distances in meters, the data needs to be in a projected crs with meters as units.
#  My data is in Sweden so I choose EPSG:3006
originalcrs = point.crs
poly = poly.to_crs(3006)
point = point.to_crs(3006)

#Create unique ids
poly["polyid"] = range(poly.shape[0])
point["pointid"] = range(point.shape[0])

#For each point find the closest polygon(s)
#  If there are more than one polygon within snapdistance, the points will be duplicated
poly["polygeom"] = poly.geometry #Save the geometry, or it is lost in sjoin_nearest
sj = gpd.sjoin_nearest(left_df=point, right_df=poly, how="left", max_distance=snapdist)

#Measure distances. If there is no polygon within snapdistance, return None
sj["distance"] = sj.apply(lambda x: x.geometry.distance(x.polygeom) if x.polygeom is not None else None, axis=1)

#Sort by distance and drop any duplicated points
sj = sj.sort_values(by=["pointid","distance"], ascending=True, na_position="last")
sj = sj.drop_duplicates(subset="pointid", keep="first")

#    pointid  polyid  distance
# 0        0  1422.0  47.02335
# 1        1     NaN       NaN

#So point 0 should snap to polygon 1422 if the distance < snapdist.
#Point 1 should not snap. Any other points with 0 distance (they are already intersecting a polygon) should
#  stay unchanged

#Create/find the point on the polygon to snap to
sj["nearestpoint"] = sj.apply(lambda x: nearest_points(x.geometry, x.polygeom)[1] if (x.polygeom is not None or x.distance==0) else None, axis=1)