Hi all,
I'm running ArcGIS Pro 3.2. I have a feature class of point data that was geocoded successfully, for the most part. Most of the points lie neatly inside building footprints. However, a significant number of the points lie outside tax parcel polygons. My client wants all the points to be inside the parcels. The parcels and the points have a common attribute.
Below is a screenshot:
Is there a way to place the points in the center of the tax parcels? I've tried joining by attributes, I've tried near, and nothing seems to do the trick.
I'm looking forward to any help!
Solved! Go to Solution.
Copy/paste this script into the Python window, edit the first 5 lines, run it (this edits your feature class, make a backup!)
polygons = "TestPolygons" # name of the polygon layer / path to the fc
points = "TestPoints" # name of the point layer / path to the fc
poly_field = "IntegerField1" # name of the common field in the polygon fc
point_field = "IntegerField1" # name of the common field in the point fc
do_all = False # False: only non-intersecting points are moved. True: all points are moved to the centroid
# read the polygons into a dictionary {CommonField: Geometry}
poly_shapes = dict([row for row in arcpy.da.SearchCursor(polygons, [poly_field, "SHAPE@"])])
# Start editing the point fc
with arcpy.da.UpdateCursor(points, [point_field, "SHAPE@"]) as cursor:
for key, shp in cursor:
try:
# get the corresponding polygon
poly_shp = poly_shapes[key]
# check if the point has to be moved
if do_all or shp.disjoint(poly_shp):
try:
# set the point's geometry to the polygon's centroid
cursor.updateRow([key, poly_shp.centroid])
except:
print(f"Couldn't get the centroid of {key}, sklipping")
except KeyError:
print(f"No polygon found for {key}, skipping")
Before:
With do_all = False
With do_all = True
Is it a 1 to 1 join by attributes? I'd probably run a search cursor on the polygons and get their centroid mapped into a dictionary.
Next step would be an update cursor on the points to set the point geometry to that of the matching polygon.
Copy/paste this script into the Python window, edit the first 5 lines, run it (this edits your feature class, make a backup!)
polygons = "TestPolygons" # name of the polygon layer / path to the fc
points = "TestPoints" # name of the point layer / path to the fc
poly_field = "IntegerField1" # name of the common field in the polygon fc
point_field = "IntegerField1" # name of the common field in the point fc
do_all = False # False: only non-intersecting points are moved. True: all points are moved to the centroid
# read the polygons into a dictionary {CommonField: Geometry}
poly_shapes = dict([row for row in arcpy.da.SearchCursor(polygons, [poly_field, "SHAPE@"])])
# Start editing the point fc
with arcpy.da.UpdateCursor(points, [point_field, "SHAPE@"]) as cursor:
for key, shp in cursor:
try:
# get the corresponding polygon
poly_shp = poly_shapes[key]
# check if the point has to be moved
if do_all or shp.disjoint(poly_shp):
try:
# set the point's geometry to the polygon's centroid
cursor.updateRow([key, poly_shp.centroid])
except:
print(f"Couldn't get the centroid of {key}, sklipping")
except KeyError:
print(f"No polygon found for {key}, skipping")
Before:
With do_all = False
With do_all = True
Thank you for this great script! I gave it a go, but I am getting errors saying the centroids can't be found. I will keep trying!
Yeah, that one's on me... centroid is an attribute, not a method (I had the parentheses after centroid. I fixed it in my test code, but not here...)
Should be fixed, try it again, please.
This did the trick! I appreciate you taking the time to help me. If this were reddit, I'd give you gold!
Hi I'm not too sure on centroid() is that a database level function? Maybe I'm misreading it as a method but I don't quite understand.
Would SHAPE@XY do the same job?
I'm not sure either, I'm new to Python. Another error I get is the "no polygon found" error, and I'm quite sure the keys match and are the same field type. They're not integers, they're string - could that be an issue?
Yeah, it's an attribute, not a method, my bad.
SHAPE@XY should give the centroid, too, but only as coordinates, so you would probably have to construct the point geometry.
There may also be some edge cases where the polygon centroid isn't within the polygon. Depending on the size of your area it may be easier just to run a select by location, switch selection and then manually move those remaining points (if there are any).