Hello,
I am trying to use python dictionaries to change the feature values of different fields.
I created the script below to change the feature values of a field called "DOR_UC" and as you can see there is a list of other fields where I need to do something similar - that's why there is a long list of other fields.
import arcpy
# script to assign values to features in one field based on a value in the dictionary
arcpy.env.workspace = r"D:\APRX_MXDS\USA_Parcels_2019_Project\test_featureclasses.gdb"
arcpy.env.overwriteOutput = True
# feature class
fc = "testing_fc"
# printing all fields in fc
fields = [f.name for f in arcpy.ListFields(fc)]
print(fields)
# dictionary
uses = {"000" : "Vacant Residential – with/without extra features", "001" : "Single Family", "002": "Mobile Homes",
"003" : "Multi-family - 10 units or more",
"004" : "Condominiums",
"005" : "Cooperatives",
"006" : "Retirement Homes not eligible for exemption",
"007" : "Miscellaneous Residential (migrant camps, boarding homes, etc.)",
"008" : "Multi-family - fewer than 10 units",
"009" : "Residential Common Elements/Areas",
"010" : "Vacant Commercial - with/without extra features",
"011" : "Stores, one story",
"012" : "Mixed use - store and office or store and residential combination",
}
# dictionary keys to list
usesKey = list(uses.keys())
# dictionary values to list
usesvalues = list(uses.values())
# List of fields
fields = ["BAS_STRT", "DOR_UC", "TEST", "PAR_SPLT", "CONST_CLASS", "IMP_QUAL", "M_PAR_SAL1", "QUAL_CD1"]
with arcpy.da.UpdateCursor(fc, fields) as cursor:
for row in cursor:
if usesKey in row[1]:
row[2] = usesvalues
cursor.updateRow()
Field DOR_UC currently has some codes that I need to convert into a sentence.
See image below for fc attribute's table:
Each of those codes has a meaning in the form of a sentence. I need to assign their meaning and delete the codes.
To do this I've created a dictionary where the key is the code and the value is the sentence (See attached csv).
To start testing the script I created a field called "TEST" where I want to put the value part of the dictionary.
So the code would go something like this:
If a feature in field DOR_UC is equal to 000 then the feature value in field TEST would be "Vacant Residential - with/without extra features".
When I try to run the code I am getting this first error:
Traceback (most recent call last):
File "D:/APRX_MXDS/USA_Parcels_2019_Project/Scripts/Dictionary Key() method_2.py", line 44, in <module>
for row in cursor:
RuntimeError: A column was specified that does not exist.
The weird thing is that I have both of the columns.
Not sure how to solve this.
Also, not sure if the overall code has more errors.
Could someone help me with this? I need to finish this today and I have no idea on how to continue.
thank you!
Solved! Go to Solution.
Natalia - your use of list comprehension on line 12 is impressive. I think your use of the 'in' statement on line 39 is problematic as Joshua suggests:
if usesKey in row[1]:
row[2] = usesvalues
You have defined usesKey as a list of all the keys in your dictionary. That list looks something like this:
['000', '001', 002', ..... '012']
I think you may mean this:
if row[1] in usesKey:
do something....
Similarly, you set usesvalues to a list as well. Do you want to set the value of Test to that complete list?
My guess is you do not, but rather you want to set the value of Test to the value associated to that given key in your dictionary.
Assuming that my guess is correct, you can skip the lists and your code could look like:
with arcpy.da.UpdateCursor(fc, fields) as cursor:
for row in cursor:
keyValue = row[1]
if keyValue in uses:
row[2] = uses.get(keyValue)
cursor.updateRow()
# more succinctly:
with arcpy.da.UpdateCursor(fc, fields) as cursor:
for row in cursor:
keyValue = row[1]
if keyValue in uses:
row[2] = uses[keyValue][0]
cursor.updateRow()
the logic is fairly simple:
set the keyValue variable value to what is in DOR_UC field for the given position of the cursor
look for that keyValue in the uses dictionary
if it is in the dictionary get the associated Value to that Key and update the TEST field with that value
Give this a try and see if it works for you...
see: Get() method for dictionaries in Python - GeeksforGeeks
The more succinct way is helpful if your dictionary keys have multiple values; here we are getting the first (and only value) of the given key...
I'm guessing you've put the field list in for our benefit? It doesn't look light theres anything wrong with that fieldlist, but you may want to try baseName.
from the actual cursor, it looks like you're using the in statement the wrong way around, and also trying to set the output to a list of values which won't work.
Can You explain a little bit further what you mean by baseName?
Also, should I write
if row[1] in useskey:
I don't know if field.name is returning aliases, im not sure on that one. you could use a wildcard if it becomes a sticking point '*'.
yes,
if row[1] in useskey:
row[2] = uses[row[1]]
this sets a test that the DOR_UC field value is in the key list, then sets "TEST" to the dictionary key value.
There may be issues further down in your code, like not using Python 'in' correctly, but fundamentally the error you are encountering now has to do with columns/fields. The error is straightforward, i.e., there is a column name being passed to the cursor that doesn't exist in the feature class or feature layer. So, focus on verifying the columns and column names.
I understand that is the error but the column name is correct and it exists in my feature class.
I even include a line of code in my script that prints all of the field names. When I run the line of code it prints out the field names that supposedly don't exist.
I even include the image containing the field/column name in the attribute table of my feature class.
Natalia - your use of list comprehension on line 12 is impressive. I think your use of the 'in' statement on line 39 is problematic as Joshua suggests:
if usesKey in row[1]:
row[2] = usesvalues
You have defined usesKey as a list of all the keys in your dictionary. That list looks something like this:
['000', '001', 002', ..... '012']
I think you may mean this:
if row[1] in usesKey:
do something....
Similarly, you set usesvalues to a list as well. Do you want to set the value of Test to that complete list?
My guess is you do not, but rather you want to set the value of Test to the value associated to that given key in your dictionary.
Assuming that my guess is correct, you can skip the lists and your code could look like:
with arcpy.da.UpdateCursor(fc, fields) as cursor:
for row in cursor:
keyValue = row[1]
if keyValue in uses:
row[2] = uses.get(keyValue)
cursor.updateRow()
# more succinctly:
with arcpy.da.UpdateCursor(fc, fields) as cursor:
for row in cursor:
keyValue = row[1]
if keyValue in uses:
row[2] = uses[keyValue][0]
cursor.updateRow()
the logic is fairly simple:
set the keyValue variable value to what is in DOR_UC field for the given position of the cursor
look for that keyValue in the uses dictionary
if it is in the dictionary get the associated Value to that Key and update the TEST field with that value
Give this a try and see if it works for you...
see: Get() method for dictionaries in Python - GeeksforGeeks
The more succinct way is helpful if your dictionary keys have multiple values; here we are getting the first (and only value) of the given key...
Thank you Joe for your response.
I was able to run the code and it worked! I now understand how dictionaries work in ArcGIS.
This was extremely helpful.
I'm glad it worked for you. Using dictionaries is one of those tools you don't use every day in ArcGIS, but when you need them, they are great. Be sure and keep little tricks like these somewhere on your computer; I keep a directory called 'PythonDevelopment' where I archive 'stuff' that I've learned; that's where the code I shared came from...