Hello,
I have a layer with Zoning Overlays. I have a layer with parcels. I need to iterate through zoning Overlay, select the parcels falling inside, add a new field to the parcels Feature class and add some text to the selected fields, then repeat for the next zoning overlay. The loop works, insofar but it stops with a particular error that is not specific enough.
The code runs until it has to assign the values to the second field.
Please see below for more details.
Here's my code:
Import arcpy # Set two geoprocessing environments arcpy.env.workspace = r"D:\APRX, MXDS\Geo_Engine_Zoning_Project\Austin_Geo_Engine.gdb" arcpy.env.overwriteOutput = True # List of fields in Merged_Ovelays FC fields = ["OBJECTID", "zoning_ove"] # Convert austin_parcels feature class to feature layer arcpy.MakeFeatureLayer_management("austin_parcels", "austin_parcels_layer") # Convert Merged_Overlays feature class to feature layer arcpy.MakeFeatureLayer_management("Merged_Overlays", "Merged_Overlays_Layer") # arcpy.da.SearchCursor(in_table, field_names, {where_clause}, {spatial_reference}, {explode_to_points}, {sql_clause}) with arcpy.da.SearchCursor("Merged_Overlays_Layer", fields) as cursor: for row in cursor: select = "OBJECTID = {}".format(row[0]) # SelectLayerByAttribute(in_layer_or_view, {selection_type}, {where_clause}, {invert_where_clause}) arcpy.management.SelectLayerByAttribute("Merged_Overlays_Layer", "NEW_SELECTION", select) # SelectLayerByLocation(in_layer, {overlap_type}, {select_features}, {search_distance}, {selection_type}, {invert_spatial_relationship}) arcpy.management.SelectLayerByLocation("austin_parcels_layer", "HAVE_THEIR_CENTER_IN", "Merged_Overlays_Layer","","NEW_SELECTION") # Syntax: AddField(in_table, field_name, field_type, {field_precision}, {field_scale}, {field_length}, {field_alias}, {field_is_nullable}, {field_is_required}, {field_domain}) arcpy.management.AddField('austin_parcels_layer', "Overlay_{}".format(row[1]), "TEXT") # CalculateField(in_table, field, expression, {expression_type}, {code_block}, {field_type}) arcpy.management.CalculateField("austin_parcels_layer", "Overlay_{}".format(row[1]), '"Overlay_{}".format(row[1])')
I am getting the following error and I am not sure how to fix it:
Traceback (most recent call last):
File "<string>", line 24, in <module>
File "c:\program files\arcgis\pro\Resources\arcpy\arcpy\management.py", line 4230, in CalculateField
raise e
File "c:\program files\arcgis\pro\Resources\arcpy\arcpy\management.py", line 4227, in CalculateField
retval = convertArcObjectToPythonObject(gp.CalculateField_management(*gp_fixargs((in_table, field, expression, expression_type, code_block), True)))
File "c:\program files\arcgis\pro\Resources\arcpy\arcpy\geoprocessing\_base.py", line 506, in <lambda>
return lambda *args: val(*gp_fixargs(args, True))
arcgisscripting.ExecuteError: ERROR 999999: Something unexpected caused the tool to fail. Contact Esri Technical Support (http://esriurl.com/support) to Report a Bug, and refer to the error help for potential solutions or workarounds.
Invalid pointer
Failed to execute (CalculateField).
Is it something with my line of code that is not working?
arcpy.management.CalculateField("austin_parcels_layer", "Overlay_{}".format(row[1]), '"Overlay_{}".format(row[1])')
My goal is to:
Copy the text from the selected feature below:
and put it into the newly created field.
I would really appreciate your help,
Thank you so much!
Natalia
For your select query I think OBJECTID should be enclosed in quotes.
select = ' " ' + "OBJECTID" + ' " ' + " = " + str(row[0])
Although AddFieldDelimiters—ArcPy Functions | ArcGIS Desktop will still add double quotes around file geodatabase and shape file field names, they haven't been necessary for a while. The ArcMap SQL reference for query expressions used in ArcGIS—Help | ArcGIS for Desktop (ArcMap) documentation states:
For File geodatabase data you can enclose your field names in double quotes, but it's generally not needed.
The ArcGIS Pro SQL reference for query expressions used in ArcGIS—ArcGIS Pro | ArcGIS Desktop (Pro) documentation has gone one step further and completely removed the Fields section so there are no references to field delimiters.
I don't think arcpy.env.workspace can take "two geoprocessing environments". Perhaps the comma in the workspace variable is causing the "something unexpected" error.
# Set two geoprocessing environments
arcpy.env.workspace = r"D:\APRX, MXDS\Geo_Engine_Zoning_Project\Austin_Geo_Engine.gdb"
arcpy.env.overwriteOutput = True
Randy, I don't think the OP is trying to pass two values, the comma is in the name of the folder! Although allowed by Windows and ArcGIS, I think most would argue commas are a bad idea in file paths.
I took another look at your code and was wondering if you intended to create a new field in your parcels layer for each feature in the Merged_Overlays_Layer? This could be a lot of fields to add. Or did you intend to create a field and populate it with the name/ID of the overlay feature the parcel was located in?
For the CalculateField, I believe the single quotes should be inside the double quotes for the third parameter.
'"Overlay_{}".format(row[1])'
# try instead:
"'Overlay_{}'".format(row[1])
I was experimenting in Desktop and needed to add a 4th parameter "PYTHON_9.3" which is supposed to be optional, but without it I was getting an error.
For my testing I was using the following code in ArcMap's Python window. Changes are probably required, but it may give you some ideas.
parcels = 'austin_parcels_layer'
pField = 'Overlay' # new field for overlay feature name/ID
overlay = 'Merged_Overlays_layer'
oFields = ['OBJECTID', 'zoning_ove']
arcpy.management.AddField(parcels, pField, 'TEXT', None, 100) # add text field with length of 100
with arcpy.da.SearchCursor(overlay,oFields) as cursor:
for row in cursor:
select = "OBJECTID = {}".format(row[0])
arcpy.management.SelectLayerByAttribute(overlay, "NEW_SELECTION",select)
arcpy.management.SelectLayerByLocation(parcels, "HAVE_THEIR_CENTER_IN", overlay, "", "NEW_SELECTION")
arcpy.management.CalculateField(parcels, pField, "'{}'".format(row[1]), "PYTHON_9.3")
arcpy.management.SelectLayerByAttribute(overlay,"CLEAR_SELECTION") # clear any selections
arcpy.management.SelectLayerByAttribute(parcels,"CLEAR_SELECTION")
Your first Select Layer by Attribute is unnecessary and may cause issues if you are changing the selection of a layer while iterating over the layer with a Search Cursor. Just add "SHAPE@" to your list of field names to get the shape you are interested in and drop the first Select Layer By Attribute.
Do you really want to add a new field for each loop in the Search Cursor? Assuming austin_parcel_layer geometries can only have their center in one merged_overlays_layer, you will be creating an unnecessarily sparse matrix of columns and rows.
Hi Joshua, Randy and David,
Thanks for your help!
I did need to add a new field for each loop in the Search Cursor.
This is the code that ended up working. I am sharing it just in case anyone needs it.
I had to fix some of the raw data for it to work correctly. I had to modify the names of the cell values to have underscores instead of spaces.
Import arcpy
# Set two geoprocessing environments
arcpy.env.workspace = r"D:\APRX_MXDS\Geo_Engine_Zoning_Project\Austin_Geo_Engine.gdb"
arcpy.env.overwriteOutput = True
# List of fields in Merged_Ovelays FC
fields = ["OBJECTID", "zoning_ove"]
# Convert austin_parcels feature class to feature layer
arcpy.MakeFeatureLayer_management("austin_parcels", "austin_parcels_layer")
# Convert Merged_Overlays feature class to feature layer
arcpy.MakeFeatureLayer_management("Merged_Overlays", "Merged_Overlays_Layer")
# arcpy.da.SearchCursor(in_table, field_names, {where_clause}, {spatial_reference}, {explode_to_points}, {sql_clause})
with arcpy.da.SearchCursor("Merged_Overlays_Layer", fields) as cursor:
for row in cursor:
select = "OBJECTID = {}".format(row[0])
# SelectLayerByAttribute(in_layer_or_view, {selection_type}, {where_clause}, {invert_where_clause})
arcpy.management.SelectLayerByAttribute("Merged_Overlays_Layer", "NEW_SELECTION", select)
# SelectLayerByLocation(in_layer, {overlap_type}, {select_features}, {search_distance}, {selection_type}, {invert_spatial_relationship})
arcpy.management.SelectLayerByLocation("austin_parcels_layer", "HAVE_THEIR_CENTER_IN", "Merged_Overlays_Layer","","NEW_SELECTION")
# Syntax: AddField(in_table, field_name, field_type, {field_precision}, {field_scale}, {field_length}, {field_alias}, {field_is_nullable}, {field_is_required}, {field_domain})
arcpy.management.AddField('austin_parcels_layer', "Overlay_{}".format(row[1]), "TEXT")
# CalculateField(in_table, field, expression, {expression_type}, {code_block}, {field_type})
arcpy.management.CalculateField("austin_parcels_layer", "Overlay_{}".format(row[1]), "'Overlay_{}'".format(row[1]), "PYTHON_3")
arcpy.management.SelectLayerByAttribute("Merged_Overlays_Layer", "CLEAR_SELECTION") # clear any selections
arcpy.management.SelectLayerByAttribute("austin_parcels_layer", "CLEAR_SELECTION")
Thanks Joshua Bixby for the comment about using "SHAPE@". The SelectLayerByAttribute
step is not necessary.
oFields = ['OBJECTID', 'zoning_ove', 'SHAPE@']
with arcpy.da.SearchCursor(overlay,oFields) as cursor:
for row in cursor:
print "Processing feature {}".format(row[0])
arcpy.management.SelectLayerByLocation(parcels, "HAVE_THEIR_CENTER_IN", row[2], "", "NEW_SELECTION") # row[2] is SHAPE@
arcpy.management.CalculateField(parcels, pField, "'{}'".format(row[1]), "PYTHON_9.3")
Do what all those guys suggest....