Create a coded value attribute domain from unique values in a field

I often have to take data I have received containing redundant text fields, and turn it into something more meaningful. Often, this will involve extracting unique values from a text field and converting it into a coded value domain.

This has the advantage of minimising data capture errors resulting from spelling mistakes, and provides a nice dropdown list in whichever interface I choose to represent the layer in (whether it be ArcMap, ArcGIS Online, Collector or a web viewer).

#
# @date 25/02/2015
# @author Cindy Williams
#
# Extracts a list of values from a field in an attribute table
# to be used in a coded value domain.
#
# For use in the Python window in ArcCatalog.
#
import arcpy
arcpy.env.workspace = r"C:\Some\Arb\Folder\source.gdb" # File GDB containing source feature class or table
# Input variables
gdb = r"C:\Some\Arb\Folder\work.gdb" # File GDB that will contain the domain
ftr = "ftr_class" # Feature class or table
field_nam = "DC_NAME" # Field name containing values
cvd = "cvd_Dist" # Name of new coded value domain
# Generator of values (from http://stackoverflow.com/questions/4154571/sorted-using-generator-expressions-rather-than-lists/4155652#4155652)
gen_cvd = sorted(set(row[0] for row in arcpy.da.SearchCursor(ftr, field_nam)), key=str.lower)
# Create empty coded value domain of type SHORT
arcpy.management.CreateDomain(in_workspace=gdb,
domain_name=cvd,
domain_description="Dist",
field_type="SHORT",
domain_type="CODED")
# Populate the domain with values from the generator
for dom_code, dom_value in enumerate(gen_cvd):
arcpy.management.AddCodedValueToDomain(in_workspace=gdb,
domain_name=cvd,
code=dom_code,
code_description=dom_value)
print("Added {0}: {1}".format(dom_code, dom_value))
print("Script complete.")

view raw
createCVDfromGen.py
hosted with ❤ by GitHub

This script has gone through various revisions since I first wrote it two years ago. Let’s take a closer look at line 22:

gen_cvd = sorted(set(row[0] for row in arcpy.da.SearchCursor(ftr, field_nam)), 
                 key=str.lower)

I’ve used a generator expression instead of a list comprehension to store all the values retrieved from the field using a search cursor. The amount of data I’m working with here didn’t really warrant the use of a generator – in fact, since I am performing multiple steps on this data (retrieving, dropping duplicates, sorting, looping), I probably should store it in a list.

However, I try to use different methods whenever I can so that I am always learning more about developing in my favourite language.

Using set, I remove duplicate values and then sort the values alphabetically. The cmp key str.lower is used to force case-insensitive sorting, otherwise uppercase values will be placed before lowercase values.

for dom_code, dom_value in enumerate(gen_cvd):
    arcpy.management.AddCodedValueToDomain(in_workspace=gdb,
                                           domain_name=cvd,
                                           code=dom_code,
                                           code_description=dom_value)

From Line 22, I use enumerate to add each value as a coded value to the attribute domain. Previously, I achieved this by doing the following:

vals = list(set([row[0] for row in arcpy.da.SearchCursor(ftr, field_nam)]))
codes = [c for c in xrange(0, len(vals)]
domDict = dict(zip(codes, vals))
for pair in domDict:
    ...

By using enumerate, I have a counter which can be used as the code part of the coded value pair.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.