[GIS] Using multiValue in Python Toolbox with parameters interaction

arcpymulti-valuesparameterspython-toolbox

I want to select out the records from A.shp if the where clause is satisfied. First, get the unique values (e.g., [2011,2012,2013,2014]) from a field (e.g., Year) and the field is from the A.shp, and then give the user to select the values as he wants. Suppose he is interested in the dataset from the year 2011 and 2012. Based on the values selected, delete other records (Year == 2013 or 2014 in this case) in the A.shp.

The code below has several problems.
1. Select All and Unselect All option in the tool window don't work.
2. The select out values don't change if the user unchecked several of them.
3. The UpdateCursor part removes all records rather than reflecting the user interests.

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"""
        #fc
        fc = arcpy.Parameter(
            displayName="FC:",
            name="fc",
            datatype="Feature Class",
            parameterType="Required",
            direction="Input")

        # Plat category field parameter
        fld = arcpy.Parameter(
            displayName="Field from the Plat Features",
            name="fld",
            datatype="Field",
            parameterType="Required",
            direction="Input")
        fld.parameterDependencies = [fc.name]

        # MultiValue
        values = arcpy.Parameter(
            displayName="Values",
            name="values",
            datatype="String",
            parameterType="Required",
            direction="Input",
            multiValue=1)


        params = [fc, fld, values]
        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:
            fc = str(parameters[0].value)
            col = str(parameters[1].value)
            vals = sorted(set(row[0] for row in arcpy.da.SearchCursor(fc,[col]) if row))
            parameters[2].filter.list = vals
            parameters[2].value = vals            
        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."""
        values = parameters[2].valueAsText
        list = values.split(';')

        for x in list:
            arcpy.AddMessage(x)


        fc = parameters[0].valueAsText
        field = parameters[1].valueAsText
        with arcpy.da.UpdateCursor(fc,[field]) as cursor:
            for row in cursor:
                if not row[0] in list:
                    cursor.deleteRow()

        return

Any suggestion?

Best Answer

  1. Select All and Unselect All option in the tool window don't work.
  2. The select out values don't change if the user unchecked several of them.

This is because you are resetting the values every time there is a value set for parameter 0 and 1 (done in the line parameters[2].value = vals). Comment this line out.

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:
        fc = str(parameters[0].value)
        col = str(parameters[1].value)
        vals = sorted(set(row[0] for row in arcpy.da.SearchCursor(fc,[col]) if row))
        parameters[2].filter.list = vals
        #parameters[2].value = vals
    return
  1. The UpdateCursor part removes all records rather than reflecting the user interests.

I think this sounds a bit odd that you are actually removing features that user doesn't want to work with. Isn't it easier just to filter them out or create a new dataset that will contain the data user would like to work with? There is a risk your users will be deleting things and be unaware of this.

Anyways, this is the code that will remove all rows from the features class that were not selected by user:

def execute(self, parameters, messages):
    """The source code of the tool."""
    values = parameters[2].valueAsText
    values_to_remove = values.split(';')

    for x in values_to_remove:
        arcpy.AddMessage(x)

    fc = parameters[0].valueAsText
    field = parameters[1].valueAsText
    with arcpy.da.UpdateCursor(fc,[field]) as cursor:
        for row in cursor:
            if not row[0] in values_to_remove:
                cursor.deleteRow()

    return

Some notes:

  • never name your variables using built-in Python keywords such as class or pass;

  • never name your variables using built-in Python data types such as list or dict;

If you have a variable named list it might bite you later. The reason why all features are deleted in your tool is because you are resetting the values in the parameter values essentially unselecting all of them (will will force UpdateCursor to delete all rows).

Related Question