A way to place a point inside a polygon with a common attribute?

1016
10
Jump to solution
12-01-2023 01:53 PM
azainomv
New Contributor II

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:

pointsandpolygons.PNG
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!

1 Solution

Accepted Solutions
JohannesLindner
MVP Frequent Contributor

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:

JohannesLindner_0-1701532038970.png

 

 

With do_all = False

JohannesLindner_1-1701532092816.png

 

With do_all = True

JohannesLindner_2-1701532115200.png

 

 


Have a great day!
Johannes

View solution in original post

10 Replies
DavidPike
MVP Frequent Contributor

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.

0 Kudos
JohannesLindner
MVP Frequent Contributor

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:

JohannesLindner_0-1701532038970.png

 

 

With do_all = False

JohannesLindner_1-1701532092816.png

 

With do_all = True

JohannesLindner_2-1701532115200.png

 

 


Have a great day!
Johannes
azainomv
New Contributor II

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!

0 Kudos
JohannesLindner
MVP Frequent Contributor

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.


Have a great day!
Johannes
0 Kudos
azainomv
New Contributor II

This did the trick! I appreciate you taking the time to help me. If this were reddit, I'd give you gold!

0 Kudos
DavidPike
MVP Frequent Contributor

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?

 

0 Kudos
azainomv
New Contributor II

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?

0 Kudos
JohannesLindner
MVP Frequent Contributor

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.


Have a great day!
Johannes
0 Kudos
DavidPike
MVP Frequent Contributor

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).