Do you work on the IS side of GIS, in ESRI geodatabases? The day may come when you are faced with culling domain values from what seems like a gazillion tables, organizing and verifying the values, and loading them into multiple domains.
Sorting through domain values by visually inspecting each column and loading domains one by one can get tiresome. It may be that you decide that the best thing to do is to learn how to script and automate much of the domain value sorting, validating and loading process.
Whether you are just starting out and want some tips, or whether you don't like scripting and just want something that works--this blog is for you.
This series of posts on domains will put you on your way. Each post describes a python script tool that can be added to an ArcGIS custom toolbox. Collectively, the tools automate the domain workflow, reduce errors, and save time.
Summary Of Tool
The List Domain Values tool
outputs a table listing the unique values in each domain columnn in
each of the input tables. The output table columns are as follows:
Domain (Domain name)
DomainType (Type of domain, coded, range, etc.)
Code (Domain value)
Description (Domain description)
RangeMin (Range domains only--minimum value--left blank for this tool)
RangeMax (Range domains only--maximum value--left blank for this tool)
DomainColType (Domain column type, Double, Long, Text, etc.)
TableName (Table name)
ColumnName (Column name)
The table schema matches the table schema used in the Batch Domain Loading tool, as well as the Export Geodatabase Domains tool.
ESRI database types supported are: personal, file, SDE. Non-ESRI databases are not supported.
The
output from this tool can be used for verifying and editing domain
values, for domain documentation, as well as for a domain loading table.
Illustration
Usage
There is no usage for this tool.
Syntax
DomainValuesInTables_mytools (Feature_Class_or_Table_List_To_Process, Output_Workspace, Output_Table_Name)
| Parameter | Explanation | Data Type |
|---|---|---|
| Feature_Class_or_Table_List_To_Process |
Dialog Reference List of Tables or Feature Classes ___________________ Python Reference List of Tables or Feature Classes |
Multiple Value |
| Output_Workspace |
Dialog Reference Output workspace ___________________ Python Reference Output workspace |
Workspace |
| Output_Table_Name |
Dialog Reference Output table name ___________________ Python Reference Output table name |
String |
Code Samples
ListDomainValuesInTables.py
See below for tool source code.
import arcpy, traceback, sys, os
arcpy.env.overwriteOutput = True
def add_fields(Input_Layer, field_name_list):
'''ADDS FIELDS TO A TABLE. USES A VALUE TABLE TO COLLECT FIELD PROPERTIES.
The example below shows one way to manage field names for easier coding.
Create the field name list in your main code, then paste below for reference.
# NAMES FOR FIELDS TO ADD
col_name = "Domain"
col_type = "DomainType"
col_code = "Code"
col_desc = "Description"
col_min = "RangeMin"
col_max = "RangeMax"
col_ctype = "DomainColType"
col_tab = "TableName"
col_col = "ColumnName"
Create table syntax: CreateTable_management (out_path, out_name, {template}, {config_keyword})
'''
# CREATE VALUE TABLE FOR FIELD PROPERTIES
# ADDROW FORMAT: Name Type Length - Length is optional
vtab = arcpy.ValueTable(3)
vtab.addRow(field_name_list[0] + " Text 100")
vtab.addRow(field_name_list[1] + " Text 15")
vtab.addRow(field_name_list[2] + " Text 100")
vtab.addRow(field_name_list[3] + " Text 100")
vtab.addRow(field_name_list[4] + " Double")
vtab.addRow(field_name_list[5] + " Double")
vtab.addRow(field_name_list[6] + " Text 15")
vtab.addRow(field_name_list[7] + " Text 50")
vtab.addRow(field_name_list[8] + " Text 50")
x = 0
# ITERATE THE VALUE TABLE, ADDING FIELDS TO THE INPUT TABLE
while x < vtab.rowCount:
if (vtab.getValue(x, 1) == "Text"):
arcpy.AddField_management(Input_Layer, vtab.getValue(x, 0), vtab.getValue(x, 1), field_length=(int(vtab.getValue(x, 2))))
else:
arcpy.AddField_management(Input_Layer, vtab.getValue(x, 0), vtab.getValue(x, 1))
arcpy.AddMessage(" Added field " + vtab.getValue(x, 0) + ".")
x += 1
def fieldname_list_from_layer(in_layer):
# RETURNS A PYTHON LIST OF FIELD NAME STRINGS FROM AN INPUT FEATURE LAYER
desc = arcpy.Describe(in_layer)
l_path = desc.catalogPath
flds = arcpy.ListFields(l_path, "*")
return flds
def insert_rows(in_layer, field_list, rows_to_insert):
# USES DA.INSERTCURSOR TO INSERT ROWS OF DATA INTO INPUT TABLE.
# PARAMETERS: INPUT LAYER, LIST OF FIELD NAME STRINGS, LIST OF DATA ROW LISTS.
cursor = arcpy.da.InsertCursor(in_layer, field_list)
for row in rows_to_insert:
cursor.insertRow(row)
del cursor
def workspace_from_fc(in_feature_class):
# RETURNS WORKSPACE NAME FROM FEATURE CLASS PATH OR TABLEVIEW LAYER
wksp = os.path.dirname(in_feature_class)
desc = arcpy.Describe(wksp)
if hasattr(desc, "datasetType") and desc.datasetType=='FeatureDataset':
wksp = os.path.dirname(wksp)
return wksp
def get_basename_from_layername(in_layer):
# RETURNS BASE NAME FROM LAYER NAME.
# RETURNS TABLE NAME OR FEATURE CLASS NAME.
desc_1 = arcpy.Describe(in_layer)
cat_path = desc_1.catalogPath
desc_2 = arcpy.Describe(cat_path)
t = desc_1.baseName
return t
def get_distinct_values(in_layer, in_col):
# RETURNS A LIST OF THE UNIQUE VALUES CONTAINED IN THE INPUT COLUMN.
l = [row[0] for row in arcpy.da.SearchCursor(in_layer, in_col)]
list_of_distinct_values = set(l)
return list_of_distinct_values
def dict_domainname_domaincolumntype(input_wksp):
# CREATES A DICTIONARY FROM CODED VALUE DOMAINS.
# KEY = DOMAIN NAME, VALUES = DOMAIN COLUMN TYPE AND DOMAIN TYPE.
# RETURNS NONE IF WORKSPACE TYPE IS FILE SYSTEM.
desc = arcpy.Describe(input_wksp)
wksp_type = desc.workspaceType
if wksp_type == 'FileSystem':
d = None
else:
d = {}
doms = arcpy.da.ListDomains(input_wksp)
for dom in doms:
d[dom.name] = [dom.type, dom.domainType]
return d
if __name__ == "__main__":
in_tables = arcpy.GetParameterAsText(0).split(";") # TABLEVIEW, MULTIPLE
out_workspace = arcpy.GetParameterAsText(1) # WORKSPACE
out_table_name = arcpy.GetParameterAsText(2) # STRING
try:
arcpy.AddMessage(" ")
# CREATE OUTPUT TABLE
arcpy.AddMessage(" Creating output table...")
arcpy.Delete_management("in_memory")
mem_table = arcpy.CreateTable_management ("in_memory", out_table_name)
# CREATE THE COLUMN HEADINGS LIST
col_name = "Domain"
col_type = "DomainType"
col_code = "Code"
col_desc = "Description"
col_min = "RangeMin"
col_max = "RangeMax"
col_ctype = "DomainColType"
col_tab = "TableName"
col_col = "ColumnName"
field_names = [col_name, col_type, col_code, col_desc, col_min, col_max, col_ctype, col_tab, col_col]
# ADD THE COLUMN HEADINGS TO THE OUTPUT TABLE
add_fields(mem_table, field_names)
# GET DOMAINS FROM DATABASE
in_workspace = workspace_from_fc(in_tables[0])
arcpy.AddMessage(" Input workspace: " + str(in_workspace))
arcpy.AddMessage(" Getting domain names from workspace...")
dom_dict = dict_domainname_domaincolumntype(in_workspace)
# CREATE LIST TO HOLD ROWS OF DATA TO INSERT INTO OUTPUT TABLE
rows_to_insert = []
# ITERATE TABLES
fld_list = []
this_line = []
val_list = []
for tab in in_tables:
tabname = get_basename_from_layername(tab)
arcpy.AddMessage(" Collecting domain values from table " + tabname + "...")
# GET FIELDS
fld_list = fieldname_list_from_layer(tab)
# ITERATE FIELDS
for fld in fld_list:
# IF FIELD IS DOMAIN GET UNIQUE VALUES
if fld.domain != "":
sDomain = fld.domain
sColumn = fld.name
sType = ""
sDType = ""
if sDomain in dom_dict:
sType = dom_dict[sDomain][0]
sDType = dom_dict[sDomain][1]
val_list = get_distinct_values(tab, sColumn)
# CREATE INSERT ROW LIST FOR THIS FIELD
# AND APPEND IT TO THE LIST OF ROWS TO INSERT
for v in val_list:
this_line = []
this_line.append(sDomain)
this_line.append(str(sDType))
this_line.append(str(v))
this_line.append(str(v))
this_line.append(None)
this_line.append(None)
this_line.append(str(sType))
this_line.append(tabname)
this_line.append(sColumn)
rows_to_insert.append(this_line)
# POPULATE THE OUTPUT TABLE AND SAVE TO DISK
arcpy.AddMessage(" Creating output table...")
insert_rows(mem_table, field_names, rows_to_insert)
out_table = arcpy.TableToTable_conversion(mem_table, out_workspace, out_table_name)
# SET THE OUTPUT PARAMETER
arcpy.SetParameter(3, out_table) # TABLEVIEW
arcpy.AddMessage(" ")
except:
# PRINT ERROR MESSAGES
tb = sys.exc_info()[2]
tbinfo = traceback.format_tb(tb)[0]
pymsg = tbinfo + "\n" + str(sys.exc_type)+ ": " + str(sys.exc_value)
arcpy.AddError("Python Messages: " + pymsg + " GP Messages: " + arcpy.GetMessages(2))
finally:
del in_tables, out_workspace, out_table_name
del out_table
del in_workspace, dom_dict, rows_to_insert, fld_list, this_line
del val_list
arcpy.Delete_management("in_memory")
Tags
Domain, AddField, Describe, InsertCursor, Set, SearchCursor, Dictionary, CreateTable, TableToTable
Credits
Ruth Bowers, 2016
Use limitations
Tested in ArcGIS 10.2.2. as a python script tool in a custom toolbox.

No comments:
Post a Comment