I am using ArcMap 10.2.
I'm trying to adapt a model and script combination found on ESRI's blog site titled 'Generating a multivalue choice list'.
However, I've concluded that part of the validation used in the embedded script is reliant upon the 'Frequency' Tool in order to function properly, but this is only available with and Advanced license (lame). The blog post explains the workflow and where to download the models and scripts (but I'll happily post them up here upon request). As far as I can tell, the core of the functionality I'm after, generating a multivalue choice list:
enter image description here
..is predicated upon the validation script working properly. Without the validation, I'm unable to get the values from the field to appear as a list. Is there anything I can remove out of this validation script to get the functionality I'm after, or is there a workaround? I'm unfamiliar with the validation process. Here is the code for the validation (I was going to post as a Code Sample, but this looks like it might be easier to follow): enter image description here
[Editor note: here is the actual validation code, the image is not correct]
import arcpy
class ToolValidator(object):
"""Class for validating a tool's parameter values and controlling
the behavior of the tool's dialog."""
def __init__(self):
"""Setup arcpy and the list of tool parameters."""
self.params = arcpy.GetParameterInfo()
def initializeParameters(self):
"""Refine the properties of a tool's parameters. This method is
called when the tool is opened."""
return
def updateParameters(self):
"""Modify the values and properties of parameters before internal
validation is performed. This method is called whenever a parmater
has been changed."""
if self.params[1].altered: #Set condition - if the input field value changes
if self.params[1].value: #if the field parameter has a value
for field in arcpy.Describe(self.params[0].value).fields: #iterate through fields in the input dataset
if field.name.lower() == self.params[1].value.value.lower(): #find the field object with the same name as field parameter
try:
if self.params[2].values: #if this parameter has seleted values
oldValues = self.params[2].values #set old values to the selected values
except Exception:
pass
values = set() #create an empty set
fieldname = self.params[1].value.value #set the value of variable fieldname equal to the input field value
FrequencyTable = arcpy.Frequency_analysis (self.params[0].value, "in_memory\Frequency", self.params[1].value.value, "") #for large tables create a frequency table
cursor = arcpy.SearchCursor(FrequencyTable, "", "", self.params[1].value.value, "{0} A".format(self.params[1].value.value)) #open a search cursor on the frequency table
for row in cursor: #loop through each value
values.add(row.getValue(fieldname)) #add the value to the set
self.params[2].filter.list = sorted(values) #set the filter list equal to the sorted values
newValues = self.params[2].filter.list
try:
if len(oldValues): # if some values are selected
self.params[2].values = [v for v in oldValues if v in newValues] # check if seleted values in new list,
# if yes, retain the seletion.
except Exception:
pass
def updateMessages(self):
"""Modify the messages created by internal validation for each tool
parameter. This method is called after internal validation."""
return
Is it possible that my assumption (via testing) that the validation is the key piece is false, and that something else isn't allowing the values to be exposed as a selectable list? Many thanks in advance. Having this type of functionality will really jump start the adoption of several key workflows I'm trying to distribute in our company!
3 Answers 3
I thought some people might find this valuable. ESRI was gracious enough to help work through this and find an alternate to the validation used in the blog post which does not require an Advanced license. While I certainly had to figure out some additional items, I cannot take credit for the validation code. But, the ends justify the means and this qualifies as the answer to my question. Here you go:
import arcpy
class ToolValidator(object):
"""Class for validating a tool's parameter values and controlling
the behavior of the tool's dialog."""
def __init__(self):
"""Setup arcpy and the list of tool parameters."""
self.params = arcpy.GetParameterInfo()
def initializeParameters(self):
"""Refine the properties of a tool's parameters. This method is
called when the tool is opened."""
return
def updateParameters(self):
"""Modify the values and properties of parameters before internal
validation is performed. This method is called whenever a parameter
has been changed."""
if self.params[0].value and self.params[1].value:
self.params[2].filter.list = sorted({row[0] for row in arcpy.da.SearchCursor(self.params[0].value, self.params[1].value.value) if row[0]})
def updateMessages(self):
"""Modify the messages created by internal validation for each tool
parameter. This method is called after internal validation."""
return
Using the arcpy.da.SearchCursor returns values from the chosen field very fast considering the number of records its searching (at least in my data). I may start a new thread to see if anyone has any ideas on how to apply a filter to the validation based on a query. I hope this helps someone, but I'm glad we have an answer!
I did it in an other way: using database consist of fivel levels, without choosing the shapefile or fields just by selecting items from first level the validation script generates the values for the second level according to your choice in first level, her the script:
import arcpy
class ToolValidator(object):
"""Class for validating a tool's parameter values and controlling
the behavior of the tool's dialog."""
def __init__(self):
"""Setup arcpy and the list of tool parameters."""
self.params = arcpy.GetParameterInfo()
def initializeParameters(self):
"""Refine the properties of a tool's parameters. This method is
called when the tool is opened."""
return
def updateParameters(self):
fc="C:/LUCS/System_shapes/sys.shp"
## fc = arcpy.MakeFeatureLayer_management(Lucssys)
"""Modify the values and properties of parameters before internal
validation is performed. This method is called whenever a parmater
has been changed."""
## if self.params[0].value and self.params[0].value:
fc="C:/LUCS/System_shapes/sys.shp"
col= ("L1_NAM")
self.params[0].filter.list = [str(val) for val in
sorted(
set(
row.getValue(col)
for row in arcpy.SearchCursor(fc, None, None,col)))]
if self.params[0].value not in self.params[0].filter.list:
self.params[0].value = self.params[0].filter.list[0]
if self.params[0].value:
fc="C:/LUCS/System_shapes/sys.shp"
col1= ("L1_NAM")
col2= ("L2_NAM")
fields=(col1,col2)
##___________level2___________________________________________________________
fc="C:/LUCS/System_shapes/sys.shp"
col1= ("L1_NAM")
col2= ("L2_NAM")
fields=(col1,col2)
Level0list=[]
Level0list_uniq=[]
cursor = arcpy.SearchCursor(fc)
for row in cursor:
if (row.getValue(col1)) ==(str(self.params[0].value)):
Level0list.append (row.getValue(col2))
for elem in Level0list:
if elem not in Level0list_uniq:
Level0list_uniq.append(elem)
if self.params[1].value not in self.params[1].filter.list:
self.params[1].filter.list =Level0list_uniq
##________________level3______________________________________________________
fc="C:/LUCS/System_shapes/sys.shp"
col2= ("L2_NAM")
col3= ("L3_NAM")
fields=(col2,col3)
Level2list=[]
Level2list_uniq=[]
cursor = arcpy.SearchCursor(fc)
for row in cursor:
if (row.getValue(col2)) ==(str(self.params[1].value)):
Level2list.append (row.getValue(col3))
for elem in Level2list:
if elem not in Level2list_uniq:
Level2list_uniq.append(elem)
if self.params[2].value not in self.params[2].filter.list:
self.params[2].filter.list =Level2list_uniq
##________________level4______________________________________________________
fc="C:/LUCS/System_shapes/sys.shp"
col3= ("L3_NAM")
col4= ("L4_NAM")
fields=(col3,col4)
Level3list=[]
Level3list_uniq=[]
cursor = arcpy.SearchCursor(fc)
for row in cursor:
if (row.getValue(col3)) ==(str(self.params[2].value)):
Level3list.append (row.getValue(col4))
for elem in Level3list:
if elem not in Level3list_uniq:
Level3list_uniq.append(elem)
if self.params[3].value not in self.params[3].filter.list:
self.params[3].filter.list =Level3list_uniq
##________________level5______________________________________________________
fc="C:/LUCS/System_shapes/sys.shp"
col4= ("L4_NAM")
col5= ("L5_NAM")
fields=(col4,col5)
Level4list=[]
Level4list_uniq=[]
cursor = arcpy.SearchCursor(fc)
for row in cursor:
if (row.getValue(col4)) ==(str(self.params[3].value)):
Level4list.append (row.getValue(col5))
for elem in Level4list:
if elem not in Level4list_uniq:
Level4list_uniq.append(elem)
if self.params[4].value not in self.params[4].filter.list:
self.params[4].filter.list =Level4list_uniq
def updateMessages(self):
"""Modify the messages created by internal validation for each tool
parameter. This method is called after internal validation."""
Add new conditions to ensure a single option when the same term exists in more than one category. ِand to force arcpy to deal with arabic fonts
import arcpy
import sys
reload(sys)
sys.setdefaultencoding('utf-8')
class ToolValidator(object):
"""Class for validating a tool's parameter values and controlling
the behavior of the tool's dialog."""
def __init__(self):
"""Setup arcpy and the list of tool parameters."""
self.params = arcpy.GetParameterInfo()
def updateParameters(self):
fc="C:/LUCS/System_shapes/sys.shp"
col= ("L1_NAM")
##________________level1_________________
self.params[0].filter.list = [str(val) for val in
sorted(
set(
row.getValue(col)
for row in arcpy.SearchCursor(fc, None, None,col)))]
if self.params[0].value not in self.params[0].filter.list:
self.params[0].value = self.params[0].filter.list[0]
if self.params[0].value:
fc="C:/LUCS/System_shapes/sys.shp"
col1= ("L1_NAM")
col2= ("L2_NAM")
col3= ("L3_NAM")
col4= ("L4_NAM")
col5= ("L5_NAM")
fields=(col1,col2,col3,col4,col5)
Level1list=[]
Level1list_uniq=[]
Level2list=[]
Level2list_uniq=[]
Level3list=[]
Level3list_uniq=[]
Level4list=[]
Level4list_uniq=[]
Level5list=[]
Level5list_uniq=[]
cursor = arcpy.SearchCursor(fc)
for row in cursor:
if (row.getValue(col1)) ==(str(self.params[0].value)):
Level1list.append (row.getValue(col2))
for elem in Level1list:
if elem not in Level1list_uniq:
Level1list_uniq.append(elem)
if self.params[1].value not in self.params[1].filter.list:
self.params[1].filter.list =Level1list_uniq
##________________level3_________________
cursor = arcpy.SearchCursor(fc)
for row in cursor:
if (row.getValue(col1)) ==(str(self.params[0].value)):
if (row.getValue(col2)) ==(str(self.params[1].value)):
Level2list.append (row.getValue(col3))
for elem in Level2list:
if elem not in Level2list_uniq:
Level2list_uniq.append(elem)
if self.params[2].value not in self.params[2].filter.list:
self.params[2].filter.list =Level2list_uniq
##________________level4_______________
cursor = arcpy.SearchCursor(fc)
for row in cursor:
if (row.getValue(col1)) ==(str(self.params[0].value)):
if (row.getValue(col3)) ==(str(self.params[2].value)):
Level3list.append (row.getValue(col4))
for elem in Level3list:
if elem not in Level3list_uniq:
Level3list_uniq.append(elem)
if self.params[3].value not in self.params[3].filter.list:
self.params[3].filter.list =Level3list_uniq
##________________level5_______________
cursor = arcpy.SearchCursor(fc)
for row in cursor:
if (row.getValue(col1)) ==(str(self.params[0].value)):
if (row.getValue(col4)) ==(str(self.params[3].value)):
Level4list.append (row.getValue(col5))
for elem in Level4list:
if elem not in Level4list_uniq:
Level4list_uniq.append(elem)
if self.params[4].value not in self.params[4].filter.list:
self.params[4].filter.list =Level4list_uniq
return
-
Please format you whole code properly.Marcelo Villa– Marcelo Villa2019年07月22日 19:28:33 +00:00Commented Jul 22, 2019 at 19:28
-
it was done, its working in 10.5.0Younes Idriss– Younes Idriss2019年07月22日 19:42:08 +00:00Commented Jul 22, 2019 at 19:42
-
Part of you code is formated, but as you can see other lines are not (e.g. the import statements of your code). Use the
{ }
button to properly format your code.Marcelo Villa– Marcelo Villa2019年07月22日 19:59:23 +00:00Commented Jul 22, 2019 at 19:59 -
It also looks like you are missing the definition of a class.Marcelo Villa– Marcelo Villa2019年07月22日 20:10:46 +00:00Commented Jul 22, 2019 at 20:10
Explore related questions
See similar questions with these tags.
arcpy.da.SearchCursor
is much faster and more suitable for this task than the olderarcpy.SearchCursor
.