HOW TO

Disperse geocoded point features within a polygon using ArcPy in ArcGIS Pro

Last Published: November 22, 2023

Summary

In ArcGIS Pro, dispersing points is a process to distribute a set of point features across a specific area. This is useful for a variety of reasons, such as to improve the visual representation of data from closely clustered points and for spatial modeling or simulation to create more realistic representations of features are distributed in the real world.

This article describes the workflow to disperse geocoded point features within a polygon using ArcPy in ArcGIS Pro.

Procedure

Note: 
This workflow requires the full script to run in the ArcGIS Pro Python window.
  1. In ArcGIS Pro, open the map containing the point and polygon feature classes.
  2. Open the Python window. Refer to ArcGIS Pro: Python window for more information.
  3. Run the following script:
    1. Import the necessary modules.
import arcpy
import random
  1. In the main() function definition, set up the necessary environment and file paths. Replace '<filePath1>' and '<filePath2>' with the paths of the point and polygon feature classes. Retrieve the shape of the polygon using the SearchCursor() function.
def main():   
    fcPoints = r"<filePath1>"   
    fcPolygon = r"<filePath2>"     
    arcpy.env.overwriteOutput = True
    
    with arcpy.da.SearchCursor(fcPolygon, ("SHAPE@")) as cursor:
        for row in cursor:
            polygon = row[0]
            disperse_points(fcPoints, polygon)
        del row
    print ("ready...")
  1. Create a point geometry at coordinates representing the point and check if it is within the polygon.
def point_in_poly(poly, x, y):
    pg = arcpy.PointGeometry(arcpy.Point(x, y), poly.spatialReference)
    return poly.contains(pg)
  1. Disperse the points within the provided polygon. If a point originally falls inside the polygon, it is moved to a new random location within the polygon. If a point originally does not fall inside the polygon, it remains in its original location.
def disperse_points(in_points, polygon):
    lenx = polygon.extent.width
    leny = polygon.extent.height
    with arcpy.da.UpdateCursor(in_points, "SHAPE@XY") as points:
        for p in points:
            if point_in_poly(polygon, p[0][0], p[0][1]):
                x = (random.random() * lenx) + polygon.extent.XMin
                y = (random.random() * leny) + polygon.extent.YMin
                inside = point_in_poly(polygon, x, y)
                while not inside:
                    x = (random.random() * lenx) + polygon.extent.XMin
                    y = (random.random() * leny) + polygon.extent.YMin
                    inside = point_in_poly(polygon, x, y)
                points.updateRow([(x, y)])
            else:
                pass
  1. Run a logic to call the main function created in Step 3b.
if __name__ == '__main__':
    main()‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

The code block below demonstrates the full working script.

import arcpy
import random

def main():
    fcPoints = r"C:\Users\Documents\ArcGIS\Projects\MyProject22\MyProject22.gdb\point"
    fcPolygon = r"C:\Users\Documents\ArcGIS\Projects\MyProject22\MyProject22.gdb\TestPolygons"
    arcpy.env.overwriteOutput = True

    with arcpy.da.SearchCursor(fcPolygon, ("SHAPE@")) as cursor:
        for row in cursor:
            polygon = row[0]
            disperse_points(fcPoints, polygon)
        del row
    print ("ready...")

def point_in_poly(poly, x, y):
    pg = arcpy.PointGeometry(arcpy.Point(x, y), poly.spatialReference)
    return poly.contains(pg)

def disperse_points(in_points, polygon):
    lenx = polygon.extent.width
    leny = polygon.extent.height
    with arcpy.da.UpdateCursor(in_points, "SHAPE@XY") as points:
        for p in points:
            if point_in_poly(polygon, p[0][0], p[0][1]):
                x = (random.random() * lenx) + polygon.extent.XMin
                y = (random.random() * leny) + polygon.extent.YMin
                inside = point_in_poly(polygon, x, y)
                while not inside:
                    x = (random.random() * lenx) + polygon.extent.XMin
                    y = (random.random() * leny) + polygon.extent.YMin
                    inside = point_in_poly(polygon, x, y)
                points.updateRow([(x, y)])
            else:
                pass

if __name__ == '__main__':
    main()
  1. Click Refresh The Refresh button to reflect the changes on the map.

The points are dispersed in the polygon as demonstrated in the image below.

The points are dispersed in the polygon

Article ID:000031489

Software:
  • ArcGIS Pro 3 1
  • ArcGIS Pro 3 0
  • ArcGIS Pro 3 2

Receive notifications and find solutions for new or common issues

Get summarized answers and video solutions from our new AI chatbot.

Download the Esri Support App

Related Information

Discover more on this topic

Get help from ArcGIS experts

Contact technical support

Download the Esri Support App

Go to download options