I have multiple-point data and polygon data. All the points in the point data layers are supposed to lie within the polygon. However, some of the points are clustered at one XY position (about 10% of all the point data), for the purpose of this question LAT=0 and LONG=0. However, the attribute data for the points contain a field at indicates which region in the polygon the point can be found.
I would like to move the clustered points to a random XY location in their corresponding region (based on the geographic information from the polygon data). Does anyone have an idea of how to do this efficiently in ArcGIS Pro?
The attached figure shows the points and the polygon. The point in the gulf is the location of all the points that needs to be moved.
Are you comfortable using Python/cursors?
Either way, the first step I can see is generating those random points. It would be more efficient and robust to generate only those you need, so I would summarize the table of 0,0 values and create a dictionary, key=region value=number of occurences
then iterate over your region polygons to generate x number of random points in each, with x being the value of the dictionary region key.
when this is done, spatial join those points to append the region attribute to them.
then it comes down to running a cursor on all the points, with another loop of the 0,0 points - running a match against the same region attribute, when this happens you transfer the random point geometry token to the 0,0 point. You'll need some if logic like if @shapexy != (0,0) that ((NB that syntax is going to be wrong!)) to ensure the same point isn't picked again after the new xy is transferred of course.
Thank you, David. I am not conversant with python but I can do it. Is there a simple code or script for implementing your recommendation in python?
Similarly to @DavidPike 's answer, I would summarize the points by their polygon attribute and generate random point for each region your problematic points belong to. But I would skip the spatial join and just update the geometry directly.
Steps to use:
# names of the point and polygon layers in the current map
point_layer = "TestPoints"
polygon_layer = "TestPolygons"
# names of the relationship fields
polygon_id = "TextField" # primary key of the polygon layer
point_polygon_id = "TextField" # foreign key that links the points to the polygons
# get the regions where the points should be
point_regions = [row[0] for row in arcpy.da.SearchCursor(point_layer, [point_polygon_id])]
regions = {pr for pr in point_regions}
# loop over the regions
for region in regions:
# get the count of points that belong in that region
point_count = len([pr for pr in point_regions if pr == region])
# select the region polygon
query = f"{polygon_id} = '{region}'" # my id fields are text fields. if yours are not, remove the single quotes around {region}
arcpy.management.SelectLayerByAttribute(polygon_layer, "NEW_SELECTION", query)
# generate random points in that region and extract their geometries
random_points = arcpy.management.CreateRandomPoints("memory", "RandomPoints", polygon_layer, None, point_count)
new_shapes = [row[0] for row in arcpy.da.SearchCursor(random_points, ["SHAPE@"])]
# start updating the points that belong in this region
query = f"{point_polygon_id} = '{region}'" # again, remove the single quotes if you're working with numbers
with arcpy.da.UpdateCursor(point_layer, ["SHAPE@"], query) as u_cursor:
# loop over the points
for i, row in enumerate(u_cursor):
# copy the new geometries
u_cursor.updateRow([new_shapes[i]])
Before:
After:
Thank you Johannes.