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
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
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?
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
Thanks! I am going to be using this to pull values of a domain, then populate to a list that will be leveraged with updateParameters within the properties of a python script tool as a value list. I couldn't see another way of loading a domain to the script tool gui otherwise.
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
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!
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