Write geometries

Using insert and update cursors, you can use scripts to create features in a feature class or update existing ones. A script can define a feature by creating a Point object, populating its properties, and placing it in an Array. That array can then be used to set a feature's geometry using Polygon, Polyline, PointGeometry, or Multipoint geometry classes.


import arcpy

fc = "c:/data/gdb.gdb/roads"
cursor = arcpy.da.InsertCursor(fc, ["SHAPE@"])
array = arcpy.Array(
    [arcpy.Point(-77.4349451, 37.5408265), arcpy.Point(-78.6384349, 35.7780943)]
)
spatial_reference = arcpy.SpatialReference(4326)
polyline = arcpy.Polyline(array, spatial_reference)

cursor.insertRow([polyline])

As shown above, a single geometry part is defined by an array of points. Likewise, a multipart feature can be created from an array of arrays of points, as shown below using the same cursor.

import arcpy

first_part = arcpy.Array(
    [arcpy.Point(-77.4349451, 37.5408265), arcpy.Point(-78.6384349, 35.7780943)]
)
second_part = arcpy.Array(
    [arcpy.Point(-79.7910143, 36.0786785), arcpy.Point(-80.8546435, 35.2315402)]
)

array = arcpy.Array([first_part, second_part])
spatial_reference = arcpy.SpatialReference(4326)
multipart_feature = arcpy.Polyline(array, spatial_reference)

cursor.insertRow([multipart_feature])

When writing point features, only a single point object is used to set the geometry of a point feature. Points can be created more easily (and efficiently) using the SHAPE@XY token (and SHAPE@M and SHAPE@Z tokens, as needed).


import arcpy

# fc is a point feature class
fc = "c:/data/gdb.gdb/stops"
with arcpy.da.InsertCursor(fc, ["SHAPE@XY"]) as cursor:
    xy = (5997594.4753, 2069901.75682)

    cursor.insertRow([xy])

Points can also be written using the SHAPE@ token.


import arcpy

with arcpy.da.UpdateCursor(
    "Shops", ["SHAPE@", "ST_ADDRESS", "ZIP"], where_clause="NAME = 'The Cupcakery'"
) as cursor:
    for row in cursor:
        pt = arcpy.Point(-117.18854177699995, 34.06044265100007)
        row = [pt, "540 W Stuart Ave", 92374]
        cursor.updateRow(row)

All geometries are validated before they are written to a feature class. Issues—such as incorrect ring orientation and self-intersecting polygons, among others—are corrected when the geometry is simplified before its insertion.

The following example shows how to read a set of coordinates (defined by coords_list) containing a series of linear coordinates and use them to create a feature class:

# Create a new line feature class using a text file of coordinates.
# Each coordinate entry is semicolon delimited in the format of ID;X;Y
import arcpy
import os

# List of coordinates (ID, X, Y)
coords_list = [
    [1, -61845879.0968, 45047635.4861],
    [1, -3976119.96791, 46073695.0451],
    [1, 1154177.8272, -25134838.3511],
    [1, -62051091.0086, -26160897.9101],
    [2, 17365918.8598, 44431999.7507],
    [2, 39939229.1582, 45252847.3979],
    [2, 41170500.6291, 27194199.1591],
    [2, 17981554.5952, 27809834.8945],
    [3, 15519011.6535, 11598093.8619],
    [3, 52046731.9547, 13034577.2446],
    [3, 52867579.6019, -16105514.2317],
    [3, 17160706.948, -16515938.0553],
]

# The output feature class to be created
outFC = arcpy.GetParameterAsText(0)

# Get the template feature class
template = arcpy.GetParameterAsText(1)

cur = None
try:
    # Create the output feature class
    arcpy.management.CreateFeatureclass(
        os.path.dirname(outFC), os.path.basename(outFC), "POLYLINE", template
    )

    # Access spatial reference of template to define spatial
    # reference of geometries
    spatial_reference = arcpy.Describe(template).spatialReference

    # Open an insert cursor for the new feature class
    cur = arcpy.da.InsertCursor(outFC, ["SHAPE@"])

    # Create an array object needed to create features
    array = arcpy.Array()

    # Initialize a variable for keeping track of a feature's ID.
    ID = -1
    for coords in coords_list:
        if ID == -1:
            ID = coords[0]

        # Add the point to the feature's array of points
        #   If the ID has changed, create a new feature
        if ID != coords[0]:
            cur.insertRow([arcpy.Polyline(array)])
            array.removeAll()
        array.add(arcpy.Point(coords[1], coords[2], ID=coords[0]))
        ID = coords[0]

    # Add the last feature
    polyline = arcpy.Polyline(array, spatial_reference)
    cur.insertRow([polyline])


except Exception as e:
    print(e)
finally:
    # Clean up the cursor if necessary
    if cur:
        del cur

In the following example, an existing feature is combined with a new feature and the existing feature is updated with the combined feature.


import arcpy

array = arcpy.Array(
    [
        arcpy.Point(-117.1723261, 34.0240298),
        arcpy.Point(-117.1722951, 34.0240060),
        arcpy.Point(-117.1719831, 34.0240465),
        arcpy.Point(-117.1716733, 34.0241251),
    ]
)

with arcpy.da.UpdateCursor(
    "HikingTrails", ["SHAPE@"], where_clause="TRAILNAME = 'Sunset Ridge Trail'"
) as cursor:
    for row in cursor:
        new_polyline = arcpy.Polyline(array)
        row[0] = row[0].union(new_polyline)
        cursor.updateRow(row)

To create multipart polygon and polyline features and polygon features with interior rings, first create an array of arrays. Then pass that to the Polygon and Polyline classes.

Geometry creation from lists of coordinates

Geometry can also be created from a list of coordinates. This approach can provide performance gains, as it avoids the overhead of creating geometry objects. However, it is limited to only features that are singlepart, and in the case of polygons, without interior rings. All coordinates should be in the units of the feature class's spatial reference.

In the example below, a single polyline feature is created from a list of x,y pairs.


import arcpy

coordinates = [
    (-117.2000424, 34.0555514),
    (-117.2000788, 34.0592066),
    (-117.1957315, 34.0592309),
    (-117.1956951, 34.0556001),
]

# Create a feature class with a spatial reference of GCS WGS 1984
result = arcpy.management.CreateFeatureclass(
    arcpy.env.scratchGDB, "esri_square", "POLYLINE", spatial_reference=4326
)
feature_class = result[0]

# Write feature to new feature class
with arcpy.da.InsertCursor(feature_class, ["SHAPE@"]) as cursor:
    cursor.insertRow([coordinates])

Similarly, in the example below, a single 3D polyline feature is created from a list of x,y,z coordinates.


import arcpy

coordinates = [
    (-117.2000424, 34.0555514, 1),
    (-117.2000788, 34.0592066, 2),
    (-117.1957315, 34.0592309, 5),
    (-117.1956951, 34.0556001, 2),
]

# Create a feature class with a spatial reference of GCS WGS 1984
result = arcpy.management.CreateFeatureclass(
    arcpy.env.scratchGDB,
    "esri_square_z",
    "POLYLINE",
    has_z="ENABLED",
    spatial_reference=4326,
)
feature_class = result[0]

# Write feature to new feature class
with arcpy.da.InsertCursor(feature_class, ["SHAPE@"]) as cursor:
    cursor.insertRow([coordinates])