List domain values for a field

2806
6
04-11-2019 07:59 AM
FugroICT
New Contributor II

I am quite stuck here: how do I list domain values for a field in a feature class?

To give you a broader context: after I got the domain values, I need to compare the values with the one from a shapefile and choose the correct one, strip the numbers from the text of the shapefile and populate the fields in my feature class.

I.e. shapefile value: "100 - apple" corresponds to domain value "abcd100 Apple"

So to begin with, I have so far failed to even list said domain values. Any code snippet would work and thanks for you help in advance

Tags (1)
0 Kudos
6 Replies
Egge-JanPollé1
MVP Regular Contributor

Hi Fugro ICT‌,

Domain values in a File Geodatabase (FGDB) are not stored at Feature Class level, but at FGDB level, i.e. a domain can be used in any Feature Class in the FGDB. This is done by assigning the domain to a certain field in a certain Feature Class.

That said, you can list your domain values like this (example taken from the docs: ListDomains—Help | ArcGIS Desktop - replace the Boston.gdb with yours):

import arcpy

domains = arcpy.da.ListDomains("C:/Boston/Boston.gdb")

for domain in domains:
print('Domain name: {0}'.format(domain.name))
if domain.domainType == 'CodedValue':
coded_values = domain.codedValues
for val, desc in coded_values.items():
print('{0} : {1}'.format(val, desc))
elif domain.domainType == 'Range':
print('Min: {0}'.format(domain.range[0]))
print('Max: {0}'.format(domain.range[1]))

Is this what you are looking for?

Egge-Jan

FugroICT
New Contributor II

Thanks! I have been staring at this little snippet today for far too long already  It gives me a nice list of all my domains for the gdb but how do I get only the one from my FC and from the specific field?

0 Kudos
DanPatterson_Retired
MVP Esteemed Contributor

Field—ArcPy classes | ArcGIS Desktop 

domain
(Read and Write)

The name of the associated domain.

Suggesting you will have to examine your featureclasses (ListFeatureClasses, their fields (ListFields) and check to see if the fields have that property

RandyBurton
MVP Regular Contributor

When I wanted a count of domain values used in all fields in a feature, I used the following.  It ignores 'Range' type domains, but it might give you some ideas.  To limit it to a specific field, you could use something like:  field.name == 'field_name'.

import arcpy

gdb = r"C:\path\to\file.gdb"
arcpy.env.workspace = gdb # set environment for arcpy
fc = 'feature_name' # a feature in the geodatabase


# gdb domains to dictionary # # # # # # #
domDict = {} # empty dictionary
domains = arcpy.da.ListDomains(gdb)
for domain in domains:
if domain.domainType == 'CodedValue':
if domain.name not in domDict:
vList = [] # empty list
coded_values = domain.codedValues
for val, desc in coded_values.items():
vList.append({val:desc})
domDict[domain.name] = vList
# print domDict

# read feature's fields and domains information # # # # # # #

fields = arcpy.ListFields(fc)
fldDict = {} # empty dictionary
for field in fields:
if len(field.domain):
fldDict[field.name] = field.domain
# print fldDict

# count values in fields with domains # # # # # # #
domCount = {}
fldList = list(fldDict.keys())
with arcpy.da.SearchCursor(fc, fldList) as rows:
for row in rows:
for i, f in enumerate(fldList):
# print i, fldList, row # index, field name, field value
if fldList not in domCount:
domCount[fldList] = {}
if row not in domCount[fldList]:
domCount[fldList][row] = 1
else:
domCount[fldList][row] += 1
del rows # release any locks
# print domCount

# output the results # # # # # # #
for k, v in domCount.iteritems():
print "Field: {}".format(k)
print " Domain: {}".format(fldDict)
for dLst in domDict[fldDict]:
for k1, v1 in dLst.iteritems():
if k1 in v:
print " Key: {} - Description: {} - Count: {}".format(k1, v1, v[k1])
else:
print " Key: {} - Description: {} - Count: {}".format(k1, v1, 0)

# note, this does not check for invalid codes in domain fields

An example of the output for one field:

Field: Observed
Domain: YN
Key: Y - Description: Yes - Count: 159
Key: ? - Description: ? - Count: 121
Key: N - Description: No - Count: 255
BarbaraS
New Contributor III

Hi Randy,

My apologies for the late reply. I actually got help by a consultant in the end, who worked on that script for a whole day

So this was the situation in our case:

# Classes and functions

def get_domain_values(database, domain_name):
'''
Get domain values from the database
'''

domain_values = {}

msg = '...Get domain values from the database'
arcpy.AddMessage(msg)

in_workspace = database
out_table = os.path.join("IN_MEMORY", domain_name)

arcpy.DomainToTable_management(in_workspace=in_workspace,
domain_name=domain_name,
out_table=out_table,
code_field='CODE',
description_field='DESCRIPTION')
search_fields = ['CODE', 'DESCRIPTION']
with arcpy.da.SearchCursor(out_table, search_fields) as cursor:
for row in cursor:
domain_values[format(row[0])] = format(row[1])

return domain_values

And then the code:

# Get domain values for symbology code
domain_name = 'SYMBOL_LINE'
symbology_code_domain_list = get_domain_values(FGDB_path, domain_name)
# Read Name field and update symbology_code_field field
with arcpy.da.UpdateCursor(inmem_SWshape, [symbology_code_field, 'Name']) as cursor:
geometry_type = 'LINE '
for row in cursor:
try:
IDdesc = row[1].upper()
if IDdesc.startswith(geometry_type):
IDdesc = IDdesc.replace(geometry_type, '')
domain_code = IDdesc.split(' ')[0]
if domain_code in symbology_code_domain_list:
row[0] = domain_code
else:
row[0] = default_iogp_code
except:
row[0] = default_iogp_code
arcpy.AddMessage("...ERROR: Checking Symbology Code failed")
cursor.updateRow(row)‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

So he figured to export the domain as a table and then read the table in the script. Sounds like a good way to me!

I will surely need your script at a later point as well Randy, so your effort is highly appreciated!

gallgher55
New Contributor

 

def get_domain_values(feature, field):
    feature_fields = [f for f in arcpy.ListFields(feature)]

    if field.upper() not in [x.name.upper() for x in feature_fields]:
        raise ValueError("Did not find field: {} in {}".format(field, feature))

    gdb = arcpy.Describe(feature).path

    target_field = [f for f in feature_fields if f.name.upper() == field.upper()][0]
    target_field_domain = target_field.domain

    if target_field_domain:
        field_domain = [d for d in arcpy.da.ListDomains(gdb) if d.name == target_field_domain][0]
        domain_values = field_domain.codedValues

        return domain_values

    return False

 

0 Kudos