Altering spatial references in Python

With ArcGIS 10.1, a spatial reference object can be created using a name or well-known ID (WKID).

# By name
sr = arcpy.SpatialReference('WGS 1984 UTM Zone 11N')

# By WKID
sr = arcpy.SpatialReference(32611)

However, once a spatial reference is created, many of the properties cannot be altered because they are read-only.

# Not possible
sr.centralMeridian = -110.0

Instead, if you need to change a property, you will need to take advantage of Python’s string manipulation capabilities. Since spatial reference properties can be expressed as well known strings, one solution is to export the spatial reference to a string, modify that string, and then use the altered string to create a new spatial reference.

import arcpy
import re
sr = arcpy.SpatialReference('WGS 1984 UTM Zone 11N')

# Change the central meridian.
sr.loadFromString(re.sub('PARAMETER\[\'Central_Meridian\'\,.+?]',
                         'PARAMETER\[\'Central_Meridian\',-120.0]',
                         sr.exportToString()))

References:
Well-known text representation of spatial reference systems

In addition to the documentation above, storage parameters like the coordinate domains and resolution, as well as tolerances are included in the spatial reference string.

List of Projected Coordinate system well-known IDs
List of Geographic Coordinate System well-known IDs

Advertisements

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