Hi,
I have a script where I spatially select another layer, and the selected records in that layer are then used to populate the fields in the layer that was used for the spatial selection. So specifically I am trying to transfer attributes, but I did some research and the only concern with scripting the Transfer Attributes is the additional field that may get added. I believe I could possibly delete the field to fix that issue but I am unfortunately working in an sde database and I don't want to risk messing with the schemas. If anyone has another possible solution for this I would be very open to it.
with arcpy.da.UpdateCursor(fc, ["OID@", "LANDDISTRICT", "LANDLOT"], """LANDDISTRICT IS NULL OR LANDLOT IS NULL""") as selected_fc:
for row in selected_fc:
#Create temp fc copy
arcpy.MakeFeatureLayer_management(fc, r"in_memory\fcLayer")
#Select layer by attribute
arcpy.SelectLayerByAttribute_management (r"in_memory\fcLayer", "NEW_SELECTION", "OBJECTID = {}".format(row[0]))
#Select layer by location
arcpy.SelectLayerByLocation_management(r"in_memory\DLL_layer", "INTERSECT", r"in_memory\fcLayer", '', "NEW_SELECTION")
#If selected district and landlot in row are null
if row[1] is None and row[2] is None:
print '{} Land District is {} and Land Lot is {} '.format(row[0], row[1], row[2])
def DL():
for DL in arcpy.da.SearchCursor(r"in_memory\DLL_layer", ["LAND_DIST"]):
print DL
return DL[0]
def LL():
for LL in arcpy.da.SearchCursor(r"in_memory\DLL_layer", ["LAND_LOT"]):
print LL
return LL[0]
row[1] = DL()
row[2] = LL()
selected_fc.updateRow(row)
print '{} Land District is {} and Land Lot is {} '.format(row[0], row[1], row[2])
I have tried several attempts with this and I either run into the same error or an error referring to something else.
Traceback (most recent call last):
File "U:\Models_Tools\Scripts related to Landlot and District\Populate Landlot and District Test 2.py", line 65, in <module>
row[1] = DL()
File "U:\Models_Tools\Scripts related to Landlot and District\Populate Landlot and District Test 2.py", line 57, in DL
return DL[0]
UnboundLocalError: local variable 'DL' referenced before assignment
Stumbled over this while trying to refresh my grasp of arcpy cursors. Not entirely sure what you're doing here. But the first thing I notice is that your Update and Search Cursors reference different fields; "LANDLOT" vs "LAND_LOT", and "LANDDISTRICT" vs "LAND_DISTRICT". So DL never gets assigned anything. So when you call DL[0], your error screams:
local variable 'DL' referenced before assignment
There is a lot of info on this kind of error out there, e.g. Understanding UnboundLocalError in Python - Eli Bendersky's website.
Hi Robert,
Is this the same process you were working on here?:
Trouble with selecting features by location using arcpy?
If so, I think you should take a look at Spatial Join. This is really the best/only way to transfer attributes the way you are describing via arcpy. Transfer Attributes is only for transferring attributes between linear features.
Anyways, I believe the workflow I recommended in your previous post is still your best bet. In code it would look something like this:
# set up environment to overwrite output and output to in memory
arcpy.env.overwriteOutput = True
arcpy.env.workspace = "in_memory"
# create feature layer from your DLL feature class
arcpy.MakeFeatureLayer_management(DLL_featureclass, "DLL_Layer")
# loop through your point layers, updating LANDDISTRICT first, then LANDLOT
for fc in fcs_to_update:
# make feature layer only containing the features with null values
arcpy.MakeFeatureLayer_management(fc, "temp_layer", "LANDDISTRICT IS NULL")
# spatial join to output a feature class in memory with the attributes of your polygon dataset
arcpy.SpatialJoin_analysis("temp_layer", "DLL_Layer", "tempSpatialJoinOutput",
"JOIN_ONE_TO_ONE", "KEEP_COMMON", "#", "INTERSECT")
# join the output back to your temporary layer based on TARGET_FID
arcpy.AddJoin_management("temp_layer", arcpy.Describe("temp_layer").OIDFieldName,
"tempSpatialJoinOutput", "TARGET_FID")
# get field name to update, since these field names will be qualified now that it is joined
LANDDISTRICT_field_name = "{}.LANDDISTRICT".format(fc.split("\\")[-1])
# update the values
arcpy.CalculateField_management("temp_layer", LANDDISTRICT_field_name,
"!tempSpatialJoinOutput.LANDDISTRICT!", "PYTHON_9.3")
# same thing, but for LANDLOT field
arcpy.MakeFeatureLayer_management(fc, "temp_layer", "LANDLOT IS NULL")
# spatial join to output a feature class in memory with the attributes of your polygon dataset
arcpy.SpatialJoin_analysis("temp_layer", "DLL_Layer", "tempSpatialJoinOutput",
"JOIN_ONE_TO_ONE", "KEEP_COMMON", "#", "INTERSECT")
# join the output back to your temporary layer based on TARGET_FID
arcpy.AddJoin_management("temp_layer", arcpy.Describe("temp_layer").OIDFieldName,
"tempSpatialJoinOutput", "TARGET_FID")
# get field name to update, since these field names will be qualified now that it is joined
LANDLOT_field_name = "{}.LANDLOT".format(fc.split("\\")[-1])
# update the values
arcpy.CalculateField_management("temp_layer", LANDDISTRICT_field_name,
"!tempSpatialJoinOutput.LANDLOT!", "PYTHON_9.3")
# remove the join
arcpy.RemoveJoin_management("temp_layer")
# cleanup
arcpy.Delete_management("in_memory")
arcpy.Delete_management("temp_layer")
I believe this would be much faster and simpler than any sort of feature-by-feature nested cursor approach.
Micah
Thanks Micah,
I thought about doing a spatial join but my only concern is that I have a
line feature and, though I haven't fully tested it out, I got a different
result than what I was looking for. Some of the line features cross
multiple polygons and I'm trying to determine how to best go about this.
Some are entirely inside a polygon or cross either two or more polygons. So
I tried to convert the feature to point so I could determine which part of
the polygon either contained the largest portion of the line or at least
it's determine where the middle of the line fell. I looked at other ways
and I think I found a couple but I will give your example a try. I didn't
think about the spatial join after converting to point so that might
definitely be a better solution than what I thought to try or attempt.