Hi Community,
I am attempting to use the arcpy.Geometry() objects .union() method to update records in a feature class that were appended but now need to be merged with an existing feature where appropriate (governed by a SQL expression). I am using the arcpy.da.UpdateCursor() to perform the updates. I am attempting to do something like the following, but I am getting an "AttributeError: 'Array' object has no attribute 'union'" error.
arcpy.MakeFeatureLayer_management(zoning, 'zoning_lyr')
arcpy.management.SelectLayerByAttribute('zoning_lyr', "NEW_SELECTION", "Zoning = 'A'")
selectCount = int(arcpy.GetCount_management('zoning_lyr')[0])
if selectCount >= 2:
zoningGeom = arcpy.CopyFeatures_management('zoning_lyr',arcpy.Geometry())
edit.startEditing(False, False)
edit.startOperation()
N = 1
with arcpy.da.UpdateCursor(zoning, "Shape@", "Zoning = 'A'") as cursor:
for row in cursor:
if N == selectCount:break
while N < selectCount:
row = row[0].union(zoningGeom[N]) # Fails here
cursor.updateRow([row])
N += 1
del row, cursor
edit.stopOperation()
edit.stopEditing(True)
arcpy.Delete_management('zoning_lyr')
The code below works without error, except it doesn't run through the whole list of zoningGeom features before moving to the next zoning record in the for loop. Ideally I would have it run through the records in the zoningGeom geometry object, unioning each one to the zoning layer before running out of features to union and exiting both loops.
N = 1
with arcpy.da.UpdateCursor(zoning, "Shape@", "Zoning = 'A'") as cursor:
for row in cursor:
if N == selectCount:break
row = row[0].union(zoningGeom[N])
cursor.updateRow([row])
N += 1
I think I am just missing something fundamental here. Hopefully, someone can swoop in and point me in the right direction or, better yet, offer a solution.
Thank you in advance,
Solved! Go to Solution.
Your first script fails because you forgot the index in the failing line. So you're trying to use the non-existing union method of an array (row) instead of the geometry (row[0]).
But the script would fail there anyway, because arcpy.management.CopyFeatures() does not what you think it does. You seem to want to extract the geometries, but this tool copies a feature class from one location to another.
You got the gist of what you need to do:
zones = "TestPolygons" # layer name or fc path
zone_name_field = "TextField" # name of the field that determines the "sameness"
only_keep_first = True # only keep the first row of each zone, delete the following rows
zone_names = ["A"] # Names you want to union
# You can also do it automatically for every zone name:
#zone_names = {r[0] for r in arcpy.da.SearchCursor(zones, [zone_name_field])}
for zone_name in zone_names:
sql = f"{zone_name_field} = '{zone_name}'"
# extract the geometries into a list
zone_geometries = [r[0] for r in arcpy.da.SearchCursor(zones, ["SHAPE@"], sql)]
first_row = True
# iterate over the fc
with arcpy.da.UpdateCursor(zones, ["SHAPE@"], sql) as cursor:
for r in cursor:
if first_row:
# union the current geometry with every extracted geometry
geo = r[0]
for other_geo in zone_geometries:
geo = geo.union(other_geo)
cursor.updateRow([geo])
# delete the following rows if only_keep_first == True
first_row = not only_keep_first
else:
cursor.deleteRow()
Before:
With only_keep_first == True:
With only_keep_first == False:
edit and format your code would be helpful
Code formatting ... the Community Version - Esri Community
It doesn’t appear to be possible on mobile. I will update/correct tomorrow. Thank you for the tip.
Your first script fails because you forgot the index in the failing line. So you're trying to use the non-existing union method of an array (row) instead of the geometry (row[0]).
But the script would fail there anyway, because arcpy.management.CopyFeatures() does not what you think it does. You seem to want to extract the geometries, but this tool copies a feature class from one location to another.
You got the gist of what you need to do:
zones = "TestPolygons" # layer name or fc path
zone_name_field = "TextField" # name of the field that determines the "sameness"
only_keep_first = True # only keep the first row of each zone, delete the following rows
zone_names = ["A"] # Names you want to union
# You can also do it automatically for every zone name:
#zone_names = {r[0] for r in arcpy.da.SearchCursor(zones, [zone_name_field])}
for zone_name in zone_names:
sql = f"{zone_name_field} = '{zone_name}'"
# extract the geometries into a list
zone_geometries = [r[0] for r in arcpy.da.SearchCursor(zones, ["SHAPE@"], sql)]
first_row = True
# iterate over the fc
with arcpy.da.UpdateCursor(zones, ["SHAPE@"], sql) as cursor:
for r in cursor:
if first_row:
# union the current geometry with every extracted geometry
geo = r[0]
for other_geo in zone_geometries:
geo = geo.union(other_geo)
cursor.updateRow([geo])
# delete the following rows if only_keep_first == True
first_row = not only_keep_first
else:
cursor.deleteRow()
Before:
With only_keep_first == True:
With only_keep_first == False:
Not only the solution I was after but served on a silver platter!!!
Thank you @JohannesLindner