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.

dispersepoints

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)])
Advertisements

7 thoughts on “Disperse overlapping points

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

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

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

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

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s