Using Python Dictionaries to Assign Feature Values

4324
10
Jump to solution
04-23-2020 09:52 AM
NataliaGutierrez1
New Contributor III

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!

0 Kudos
1 Solution

Accepted Solutions
JoeBorgione
MVP Emeritus

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...

That should just about do it....

View solution in original post

10 Replies
DavidPike
MVP Frequent Contributor

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.

0 Kudos
NataliaGutierrez1
New Contributor III

Can You explain a little bit further what you mean by baseName?

Also, should I write

   if row[1] in useskey:

0 Kudos
DavidPike
MVP Frequent Contributor

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.

0 Kudos
JoshuaBixby
MVP Esteemed Contributor

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.

NataliaGutierrez1
New Contributor III

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.

0 Kudos
NataliaGutierrez1
New Contributor III

I even include the image containing the field/column name in the attribute table of my feature class.

0 Kudos
JoeBorgione
MVP Emeritus

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...

That should just about do it....
NataliaGutierrez1
New Contributor III

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. 

0 Kudos
JoeBorgione
MVP Emeritus

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...

That should just about do it....
0 Kudos