Hello!
I am currently involved in the project where we are creating a tool to assess flood risk using the multi-criteria analysis. We would like to give the user the option to decide on his/her own weights for each input. E.g. one of the inputs is geology (vector data) and we would like to make a script in a way that the user, after selecting the geology input, gets all of the geology classes from the attribute table and then chooses the weight for each geology class (the possible weights would be: 1,2,5,8 or 10).
This part of code is currently hardcoded and therefore the script is applicable only for our specific region:
arcpy.AddField_management('geologyDiss', 'weight', 'SHORT', 0)
try:
with arcpy.da.UpdateCursor('geologyDiss',('geolS_eng','weight')) as cursor:
for row in cursor:
if row [0] == 'clay slate, marl, breccia, sandstone, conglomerate, chert':
row[1] = 8
elif row[0] == 'dolomite':
row[1] = 2
elif row[0] == 'flysch':
row[1] = 10
elif row[0] == 'igneous rock (diabase, spilite, porphyry, pyroclastics, keratophyre)':
row[1] = 10
elif row[0] == 'limestone, limestone with dolomite':
row[1] = 1
elif row[0] == 'moraine sediment':
row[1] = 5
elif row[0] == 'rivers and stream deposit, diluvium':
row[1] = 5
else:
row[1] = 2
cursor.updateRow(row)
del row
del cursor
except Exception as e:
print e.message
Are you creating a script tool or Python toolbox? Both have an updateParameters function that can help with creating a choice list. This blog Generating a choice list from a field discusses programming the validator in a script tool.
And to help me understand your project...
In your list, 'dolomite' has a weight of 2. Would you want the user to select 'dolomite' and give it a weight other than 2?
Do you want the user to be able to select from other features? And if so, are they similarly structured (same field layout)?
We are creating a script tool and the idea is that:
In our case there is some dolomite on our study area and we weighted it with a 2, but the user can have other classes and this is why we do not want to hardcode it.
Here are some sample python toolboxes that might give you some ideas for your project. The first is basically a python toolbox version of the script tool described in the blog post mentioned in my previous post. I have added a dropdown for the weight values. Select a feature layer or feature class; select a field in that feature; choose an attribute and select the weight.
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 = "Select Value"
self.alias = "selection"
# List of tool classes associated with this toolbox
self.tools = [SelectValue]
class SelectValue(object):
def __init__(self):
"""Define the tool (tool name is the name of the class)."""
self.label = "Select Value"
self.description = ""
self.canRunInBackground = False
self.fcfield = (None, None) # global to remember field selection
def getParameterInfo(self):
"""Define parameter definitions"""
# First parameter
inFeature = arcpy.Parameter(
displayName="Input Features",
name="inFeature",
datatype=["DEFeatureClass","GPFeatureLayer"],
parameterType="Required",
direction="Input")
# Second parameter
fieldName = arcpy.Parameter(
displayName="Field Name",
name="fieldName",
datatype="Field",
parameterType="Required",
direction="Input")
fieldName.parameterDependencies = [inFeature.name]
fieldName.filter.list = ["Short", "Long", "Double", "Float", "Text"]
# Third parameter
fldProperty = arcpy.Parameter(
displayName="Property",
name="fldProperty",
datatype="String",
parameterType="Required",
direction="Input")
fldProperty.parameterDependencies = [inFeature.name, fieldName.name]
# Fourth parameter
weightVal = arcpy.Parameter(
displayName="Weight",
name="weightVal",
datatype="String",
parameterType="Required",
direction="Input")
weightVal.filter.list = [ 1, 2, 5, 8, 10 ]
weightVal.value = weightVal.filter.list[0]
params = [inFeature, fieldName, fldProperty, weightVal]
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 and parameters[1].value: # get first field and value list
fc, col = parameters[0].valueAsText, parameters[1].valueAsText
desc = arcpy.Describe(parameters[0])
if desc.dataType == 'FeatureLayer': # if feature layer, use catalog path
fc = desc.catalogPath
if self.fcfield != (fc, col):
self.fcfield = (fc, col)
parameters[2].filter.list = [str(val) for val in sorted(set(row[0] for row in arcpy.da.SearchCursor(fc,col)))]
if parameters[2].value not in parameters[2].filter.list:
parameters[2].value = parameters[2].filter.list[0]
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."""
inFeature = parameters[0].valueAsText
fieldName = parameters[1].valueAsText
fldProperty = parameters[2].valueAsText
weightVal = parameters[3].valueAsText
messages.addMessage(
"\nInput Feature: {}".format(inFeature))
messages.addMessage(
"\nSelected Field: {}".format(fieldName))
messages.addMessage(
"\nWeight Value: {}".format(weightVal))
messages.addMessage(
"\nField Property: {}".format(fldProperty))
desc = arcpy.Describe(parameters[0])
messages.addMessage(
"\nDataType: {}\nPath: {}".format(desc.dataType, desc.catalogPath))
return
The second reads domain information into a list for the dropdown. In this example, the domain is hard-coded to a specific domain in a specific database (lines 32-33). It could be modified to allow the user to select the database and domain name.
import arcpy, operator
def getDomain(gdb, domainName):
domDict = {} # empty dictionary
domains = arcpy.da.ListDomains(gdb)
for domain in domains: # assumes domainName references a coded value domain
if domain.name == domainName:
coded_values = domain.codedValues
for val, desc in coded_values.items():
domDict[desc] = val # use { desc: val, ... } for dropdown menu
return domDict
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
self.domain = getDomain(r'C:\Path\to\file.gdb',
'DomainName') # domain description: domain code
def getParameterInfo(self):
"""Define parameter definitions"""
domValue = arcpy.Parameter(
displayName = "Select Domain",
name = "domValue",
datatype = "GPString",
parameterType = "Required",
direction = "Input")
domValue.filter.type = "ValueList"
# set filter list; descriptions sorted in code order
domValue.filter.list = [x[0] for x in sorted(self.domain.items(), key=operator.itemgetter(1))]
domValue.value = domValue.filter.list[0] # default first item in list
return [domValue]
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."""
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."""
messages.addMessage('Selected: {} -- Code: {}'.format(parameters[0].value, self.domain[parameters[0].value]))
return
Hope this gives you some ideas.