How to Update Geometry based on Attribute Values or External Tables

3691
8
06-12-2018 10:39 AM
JamesJordan
New Contributor

I am trying to update the geometry of a point layer based on values in another table.  I originally collected a large set of manhole locations and attributes using a submeter GNSS receiver.  Requirements for the project changed and we ended up having to go back out and survey them with an RTK GNSS receiver for higher accuracy.  I already have my feature class with attachments and attributes (including an Asset_ID field) for the submeter resolution data.  I have a .csv and a shapefile of the RTK resolution data (with a Name field that matches the Asset_ID field from my submeter dataset).  How can I go about moving all of my submeter data to the positions of the RTK data set, and maintain my attachments and attributes, without manually updating the geometry of each feature in the advanced editing toolbar, or manually snapping them to the features in the RTK shapefile.  I am running 10.6 Advanced with most extensions (i.e. spatial analyst, 3D analyst, Geostatistical analyst, etc.) 

P.S.: I have already done a join based on the Name/Asset_ID fields and populated 3 fields in my Submeter dataset (POINT_X, POINT_Y, and POINT_Z) with the coordinates from the RTK dataset, so I guess I could update based on those fields instead of an external dataset/table

0 Kudos
8 Replies
DanAllen
Occasional Contributor III

I have this exact same problem.  Did you ever figure out a way to do it?

0 Kudos
DerekHunt1
New Contributor

My situation is very similar.

I have two address point layers with the same data, but different point locations. It sounds similar to your updating structure locations issue. There is a common field between the two layers. I have several thousand points that need updated, so a manual effort would be a poor use of time.Green point locations are where I would like to (batch) move the red points. 

0 Kudos
JohannesLindner
MVP Frequent Contributor

@JamesJordan, @DanAllen , @DerekHunt1 

I'm pretty late to the party, but maybe it still helps...

This sounds like a job for Python, not Arcade.

Open the Python window:

JohannesLindner_0-1615445542356.png

 

Edit this code, paste it in the Python window and execute it (make sure you don't have selections in the layers!).

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
with arcpy.da.UpdateCursor(attribute_layer, [common_field, "SHAPE@"]) as cursor:
    for row in cursor:
        try:
            new_shape = shapes[row[0]]
            cursor.updateRow([row[0], new_shape])
        except KeyError:
            print("No new geometry found for feature with {} = {}".format(common_field, row[0]))

 


Have a great day!
Johannes
BillMoody
New Contributor III

Huge Kudos!  This worked flawlessly!

0 Kudos
RichardKennedy2
New Contributor II

Hi Johannes,

 

Thank you for the script. It does indeed work great. Would you be kind enough to edit the  script to print the list of only the features that had their geometry changed?

Cheers,


Richard

 

0 Kudos
JohannesLindner
MVP Frequent Contributor
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))

Have a great day!
Johannes
SuzannahReagan
New Contributor

So I'm able to run the script but I keep ending with "No new geometry found for feature with__" and then it list my common field. Any ideas on what I need to change?

Tags (1)
0 Kudos
JohannesLindner
MVP Frequent Contributor

That means the script doesn't find the corresponding values in the geometry update table.

  • make sure the common field has the same data type
    • if WrongGeometry.CommonField is an integer field, CorrectGeometry.CommonField must also be an integer field.
  • make sure there are actually matching values
    • if you want to update an entry in WrongGeometry with CommonField = 5, you need an entry in CorrectGeometry with CommonField = 5.

Have a great day!
Johannes
0 Kudos