I have not found anything on this issue, and it is not easy to search for. I have a Python Toolbox that has multiple, user-selected feature class inputs with each feature class input having 3 or 6 dropdowns for values. The tool is set up so the feature class inputs are optional and each value input is optional, basically, the user can choose to include a feature class and include 1 to 6 values from that feature class. This setup was as per the requester, so I am trying to maintain it as close as possible. As the title says, I am having values "disappear" after selecting the value; I click on the value, it shows in the box, and then resets to zero or none, depending on the box. This is behavior is occurring on features with 6 values; with values 1 and 2 working properly and 3-6 showing then disappearing after selection. I am not seeing this behavior on 3 value features, all three dropdowns work as expected. I have the dropdown values hardcoded in the toolbox and have copied a portion of the script into a new toolbox and tested auto-populating dropdown values from within def updateParameters(self, parameters). Dropdowns populate correctly but exhibit the same behavior as the hardcoded ones. I have attached two short screen captures. Geocapture is from the complete toolbox showing a three value feature with no issues, and a 6 value feature with "disappearing" selections. Geocapture2 is from the test-toolbox and auto-populates the values based on the feature and exhibits the same behavior. Please note, the screen capture videos did not capture the dropdown boxes popping up. The block of code starting with "params13" is from the complete toolbox. I did not post the entire script as it is around a thousand lines long. The second block of code is from the test-toolbox using auto-populate. I think this is a recent occurrence, possibly after 2.6 came, out because this was written and tested back in May and June and was working and has cropped up in the final testing and editing. Any ideas on where to go from here or possible fixes would be most appreciated. I am guessing it is something simple and I am just missing it.
params13 = arcpy.Parameter(
displayName="Vegetation Feature Class",
name="inVegfeature",
datatype="DEFeatureClass",
parameterType="Optional",
direction="Input",)
params13.value = None
# First Input
params14 = arcpy.Parameter(
displayName="First Vegeation Class",
name="veg1",
datatype="GPDouble",
parameterType="Optional",
direction="Input")
params14.value = 0
params14.filter.list = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37,
38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49,
50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,
62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73,
74, 75, 76]
# Second Input
params15 = arcpy.Parameter(
displayName="Second Vegetation Class",
name="veg2",
datatype="GPDouble",
parameterType="Optional",
direction="Input",)
params15.value = 0
params15.filter.list = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37,
38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49,
50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,
62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73,
74, 75, 76]
# Third Input
params16 = arcpy.Parameter(
displayName="Third Vegeation Class",
name="veg3",
datatype="GPDouble",
parameterType="Optional",
direction="Input",)
params16.value = 0
params16.filter.list = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37,
38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49,
50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,
62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73,
74, 75, 76]
# Fourth Input
params17 = arcpy.Parameter(
displayName="Fourth Vegeation Class",
name="veg3",
datatype="GPDouble",
parameterType="Optional",
direction="Input",)
params17.value = 0
params17.filter.list = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37,
38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49,
50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,
62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73,
74, 75, 76]
# Fifth Input
params18 = arcpy.Parameter(
displayName="Fifth Vegeation Class",
name="veg3",
datatype="GPDouble",
parameterType="Optional",
direction="Input",)
params18.value = 0
params18.filter.list = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37,
38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49,
50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,
62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73,
74, 75, 76]
# Sixth Input
params19 = arcpy.Parameter(
displayName="Sixth Vegeation Class",
name="veg3",
datatype="GPDouble",
parameterType="Optional",
direction="Input",)
params19.value = 0
params19.filter.list = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37,
38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49,
50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,
62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73,
74, 75, 76]
# -*- coding: utf-8 -*-
import arcpy
class Toolbox(object):
def __init__(self):
"""Define the toolbox (the name of the toolbox is the name of the
.pyt file)."""
self.label = "Toolbox"
self.alias = ""
# List of tool classes associated with this toolbox
self.tools = [Tool]
class Tool(object):
def __init__(self):
"""Define the tool (tool name is the name of the class)."""
self.label = "Tool"
self.description = ""
self.canRunInBackground = False
def getParameterInfo(self):
"""Define parameter definitions"""
# Geology Class Feature Class Parameters
params0 = arcpy.Parameter(
displayName="Geology Feature Class",
name="inGeofeature",
datatype="DEFeatureClass",
parameterType="Optional",
direction="Input",)
params0.value = None
# First Input
params1 = arcpy.Parameter(
displayName="First Geology Class",
name="geo1",
datatype="GPString",
parameterType="Optional",
direction="Input")
params1.value = None
# Second Input
params2 = arcpy.Parameter(
displayName="Second Geology Class",
name="geo2",
datatype="GPString",
parameterType="Optional",
direction="Input",)
params2.value = None
# Third Input
params3 = arcpy.Parameter(
displayName="Third Geology Class",
name="geo3",
datatype="GPString",
parameterType="Optional",
direction="Input",)
params3.value = None
# Fourth Input
params4 = arcpy.Parameter(
displayName="Fourth Geology Class",
name="geo3",
datatype="GPString",
parameterType="Optional",
direction="Input",)
params4.value = None
# Fifth Input
params5 = arcpy.Parameter(
displayName="Fifth Geology Class",
name="geo3",
datatype="GPString",
parameterType="Optional",
direction="Input",)
params5.value = None
# Sixth Input
params6 = arcpy.Parameter(
displayName="Sixth Geology Class",
name="geo3",
datatype="GPString",
parameterType="Optional",
direction="Input",)
params6.value = None
params = [params0, params1, params2, params3, params4, params5, params6]
return params
def isLicensed(self):
"""Set whether tool is licensed to execute."""
return True
def updateParameters(self, parameters):
"""Modify the values and properties of parameters before internal
validation is performed. This method is called whenever a parameter
has been changed."""
if parameters[0].value:
with arcpy.da.SearchCursor(parameters[0].valueAsText, "GLG_SYM") as rows:
parameters[1].filter.list = sorted(list(set([row[0] for row in rows])))
if parameters[0].value:
with arcpy.da.SearchCursor(parameters[0].valueAsText, "GLG_SYM") as rows:
parameters[2].filter.list = sorted(list(set([row[0] for row in rows])))
if parameters[0].value:
with arcpy.da.SearchCursor(parameters[0].valueAsText, "GLG_SYM") as rows:
parameters[3].filter.list = sorted(list(set([row[0] for row in rows])))
if parameters[0].value:
with arcpy.da.SearchCursor(parameters[0].valueAsText, "GLG_SYM") as rows:
parameters[4].filter.list = sorted(list(set([row[0] for row in rows])))
if parameters[0].value:
with arcpy.da.SearchCursor(parameters[0].valueAsText, "GLG_SYM") as rows:
parameters[5].filter.list = sorted(list(set([row[0] for row in rows])))
if parameters[0].value:
with arcpy.da.SearchCursor(parameters[0].valueAsText, "GLG_SYM") as rows:
parameters[6].filter.list = sorted(list(set([row[0] for row in rows])))
return
def updateMessages(self, parameters):
"""Modify the messages created by internal validation for each tool
parameter. This method is called after internal validation."""
return
def execute(self, parameters, messages):
"""The source code of the tool."""
return
The first issue is lines 64, 73 and 82 of the second script which sets the various parameter's name to the same value, "geo3", which is the name for params3 in line 55. This will cause parameters 3 through 6 to have the same value; when any one of these gets changed, the others in the group will also change. You have a similar problem in your first script as the name "veg3" is also used multiple times.
Additional thoughts:
The updateParameters section is a bit awkward, but in a quick test it does work. You could combine these six parameters into one that is "multiple values". This may also apply to vegetation class as well.
Regarding the vegetation class, all the numbers appear to be integers, but you are using a type of float (double). This could be an issue. You may also wish to use a filter type of "Range":
param0.filter.type = "Range"
param0.filter.list = [0, 76]
Not sure where the same values came from, I just flat missed them. This project has been moving between computers and drives and reworked multiple times, thank you for catching that. Everything is working now that the parameter names have been changed. I also changed the double to long where it applied, I had missed in the documentation that long worked for integer values. I agree with the awkward part, the number of optional parameters that also have to be dropdowns has made this a challenge, especially for this being my first, large python toolbox project (two tools with 38 parameters each). Thanks, again for the assistance.
I know this has been answered, but you have a lot of unnecessary duplication. The Update Parameters routine could be re-written as:
def updateParameters(self, parameters):
"""Modify the values and properties of parameters before internal
validation is performed. This method is called whenever a parameter
has been changed."""
if Not parameters[0].value is None:
with arcpy.da.SearchCursor(parameters[0].valueAsText, "GLG_SYM") as rows:
geoList = sorted(set([row[0] for row in rows]))
for i in range(1,7):
parameters[i].filter.list = geoList
return
First, there's no need to run the if 6 different times.
Second, there's no need to open a search cursor 6 different times.
Third, the sorted function returns a list and accepts an iterable variable. A set and a list are both iterable so sorted will return a sorted list given a set.
Finally, while if parameters[0].value: does work, it's not very readable code. Changing it to what is above very quickly tells someone else what you're really testing for.
As an aside, the range(1,7) will cycle through 1-6 and is just one of many reasons why I hate python...
William, thank you for that post, I am new to python and I am the only one where I work that uses python, or any language for that matter, so haven’t really been able to get feedback and suggestions beyond what I can find on the web and books. I did not know that I could use a range to populate parameters filters, this is incredibly helpful going forward.