How can I copy and replace the multipart polygon GEOMETRY from one feature (e.g. input FGDB layer record) to another feature (e.g. master AGOL Feature Service layer record)?
Geometry copy - not feature copy - to avoid messing with: existing attributes (Object ID, GUID, create/edit name/date), nested relates, and dependent apps.
Currently, I'm tracing the "input" shapes by using the "Replace Geometry" and "Continue Feature" tools to updated the master feature record. This is tedious and error prone given complex shapes with up to 100+ multipart parts.
There is a python way to replace geometries but I don't know how to create a safe "press button" or copy/paste solution in ArcPro.
Solved! Go to Solution.
If the input and master layers have a common field:
geometry_layer_name = "name_of_the_layer_with_the_right_geometry"
attribute_layer_name = "name_of_the_layer_with_attributes_and_wrong_geometry"
common_field = "name_of_the_common_field"
# this will change the geometry of the second layer's underlying data, so back it up!
active_map = arcpy.mp.ArcGISProject("current").activeMap
geometry_layer = active_map.listLayers(geometry_layer_name)[0]
attribute_layer = active_map.listLayers(attribute_layer_name)[0]
# read the correct geometries and save them in a dictionary
# {common_field_value: shape}
cursor = arcpy.da.SearchCursor(geometry_layer, [common_field, "SHAPE@"])
shapes = dict([row for row in cursor])
# loop through the second layer and update the geometries
updated_features = []
with arcpy.da.UpdateCursor(attribute_layer, [common_field, "SHAPE@"]) as cursor:
for row in cursor:
try:
new_shape = shapes[row[0]]
# only update if the geometry is different, fill the updated_features list
if not new_shape.equals(row[1]):
cursor.updateRow([row[0], new_shape])
updated_features.append(row[0])
except KeyError:
print("No new geometry found for feature with {} = {}".format(common_field, row[0]))
# build an SQL query of the updated_features, depending on whether common_field is a text field or not
if updated_features and isinstance(updated_features[0], str):
sql = "{} IN ('{}')".format(common_field, "', '".join(updated_features))
else:
sql = "{} IN ({})".format(common_field, ", ".join([str(uf) for uf in updated_features]))
# print the SQL query
print("Updated the geometry of {} features:\n{}".format(len(updated_features), sql))
Thanks Johannes for the code example!
I'm updating just one record in the master and the input has one record with random unrelated attributes. With enough skill, all doable in python. However, having to manually and correctly modify a script on every record update makes me very nervous. Have to look into the costs of developing an Add-In if there are no other options.
Ah. Then the script gets easier.
Select the feature you want to update in the master layer. If the input layer has more than one record, select the corresponding feature there, too. Run the script in the python window.
You just have to edit lines 1 and 2.
input_layer_name = "name_of_the_input_layer"
master_layer_name = "name_of_the_master_layer"
active_map = arcpy.mp.ArcGISProject("current").activeMap
input_layer = active_map.listLayers(input_layer_name)[0]
master_layer = active_map.listLayers(master_layer_name)[0]
new_shape = [r[0] for r in arcpy.da.SearchCursor(input_layer, ["SHAPE@"])][0]
with arcpy.da.UpdateCursor(master_layer, ["SHAPE@"]) as cursor:
for row in cursor:
cursor.updateRow([new_shape])