# Disperse overlapping points

A user recently asked if a geoprocessing tool existed to randomly disperse overlapping points inside an area or polygon. There is no specific tool, however, with a little Python code and the use of a geometry operator, this can be accomplished very quickly.

Here’s an illustration and the code recipe.

```import random
import arcpy

def point_in_poly(poly, x, y):
"""Returns if the point is inside the polygon.

Parameters:
poly: arcpy.Polygon() geometry
x:    x coordinate (float)
y:    y coordinate (float)

"""
pg = arcpy.PointGeometry(arcpy.Point(x, y), poly.spatialReference)
return poly.contains(pg)

def disperse_points(in_points, polygon):
"""Randomly disperse points inside a polygon.

Parameters:
in_points:  Point feature class/layer (with or without selection)
polygon:    arcpy.Polygon() geometry

"""

lenx = polygon.extent.width
leny = polygon.extent.height

with arcpy.da.UpdateCursor(in_points, "shape@xy") as points:
for p in points:
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)])
```

## 7 thoughts on “Disperse overlapping points”

1. ArcGIS Python Recipes says:

Hi everyone,

Although, there is no specific tool to disperse existing points within a feature and maintain the attributes, we do want to highlight the Create Random Points tool. This tool creates a specified number of random point features and these points can be generated within an extent, inside polygon features, on point features, or along line features. The tool’s help topic includes Python examples.

Thanks,
ArcGIS Team Python

2. Kirk Hayer says:

It appears the second function definition in the code sample is missing its “return” statement. I think It would also be helpful if the sample included how to call the function.

• ArcGIS Python Recipes says:

thanks for feedback. We will consider it for future posts where applicable.

3. MP says:

Hello,

I am quite new to scripting and have tried to use the script above and adjusted it. However, it is not working. Do you have any advice what should be changed?

Thank you very much and please excuse the noob question.
Best regards
MP

import random
import arcpy

arcpy.env.workspace = “D:\…\Supergrid\Daten\Anlagenregister\EEGAnlagen.gdb”

in_points = “D:\…\…\geodatabase.gdb\Geocoding_Results.shp”
polygon = “D:\…\geodatabase.gdb\zipcode.shp”

def point_in_poly(poly, x, y):
“””Returns if the point is inside the polygon.

Parameters:
poly: arcpy.Polygon() geometry
x: x coordinate (float)
y: y coordinate (float)

“””
pg = arcpy.PointGeometry(arcpy.Point(x, y), poly.spatialReference)
return poly.contains(pg)

def disperse_points(in_points, polygon):
“””Randomly disperse points inside a polygon.

Parameters:
in_points: Point feature class/layer (with or without selection)
polygon: arcpy.Polygon() geometry

“””

lenx = polygon.extent.width
leny = polygon.extent.height

with arcpy.da.UpdateCursor(in_points, “D:\…\geodatabase.gdb\DispPoints.shp”) as points:
for p in points:
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)])

• ArcGIS Python Recipes says:

Hi Martin,

This line is invalid in your code:
with arcpy.da.UpdateCursor(in_points, “D:\…\geodatabase.gdb\DispPoints.shp”) as points:

It must be the input and the list of fields. In this case, it should be “shape@xy”
with arcpy.da.UpdateCursor(in_points, “shape@xy”) as points:

http://resources.arcgis.com/en/help/main/10.2/#/UpdateCursor/018w00000014000000/

4. Ernest says:

Hello,
I am also quite new to Python scripting. I have tried the script above on my set of test points and test polygon, but I seem to be running into difficulties. My test points and test polygon were created in ArcMap Editor for the purpose of testing this code.

Here is my code:

#Import modules
import arcpy
import random
from arcpy import env

#define workspace
env.workspace = “C:\Users\eliu3\Desktop\Python 2.1 Tables”

#define inputs
in_points = “Test_points.shp”
polygon = “Test_Shape.shp”

#find points in polygon
def point_in_polygon(poly,x,y):
“””Returns if the point is inside the polygon.

Parameters:
poly: acrpy.Polygon()geometry
x: x coordinate (float)
y: y coordinate (float)

“””

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

#disperse points in polygon
def disperse_points(in_points, polygon):
“””Randomly disperse points inside a polygon.

Parameters:
in_points: Point feature class/layer (with or without)
polygon: arcpy.Polygon() geometry

“””

lenx = polygon.width
leny = polygon.height

with arcpy.da.UpdateCursor(in_points, “shape@xy”) as points:
for p in points:
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)])

#execute
disperse_points(in_points, polygon)

I keep running into this error:
Traceback (most recent call last):
File “C:\Users\eliu3\Desktop\Python 2.1 Tables\Disperse Tool”, line 53, in
disperse_points(in_points, polygon)
File “C:\Users\eliu3\Desktop\Python 2.1 Tables\Disperse Tool”, line 37, in disperse_points
lenx = polygon.width
AttributeError: ‘str’ object has no attribute ‘width’

I think the code can’t read my shapefile as a geometry and rather it seems to think it’s a string. I don’t really know what to do as I have searched all over the web for solutions to this problem. I would appreciate input and possibly a solution to my problem.

Thank you,
Ernest

• ArcGIS Python Recipes says:

Hi Ernest,
Just passing in a path to feature class as a string instead of a geometry object won’t work (as you’ve seen). The string itself doesn’t have any knowledge of what the shapefile is. I’m presuming you just want to disperse the points within the extent of this shapefile? Without changing disperse_points function, you could create a geometry from the shapefile and pass that in.

desc = arcpy.Describe(your_feature_class)
ext = desc.ext
poly = arcpy.Polygon(arcpy.Array([ext.upperLeft, ext.upperRight, ext.lowerRight, ext.lowerLeft, ext.upperLeft]), desc.spatialReference)
disperse_points(in_points, poly)