Search by attributes tool

255
2
a month ago
2Quiker
Frequent Contributor

I'm developing a script tool that allows users to select specific features on a map. The tool has three parameters:
Layer – The user selects the target map layer.
Layer Field – The user chooses a field within the selected layer.
Layer Field Attribute – The user selects an attribute value within the chosen field.
Once all parameters are set, the user runs the tool. However, despite receiving no errors, nothing gets selected on the map.

Script

import arcpy

class ToolValidator:
    def __init__(self):
        self.params = None

    def initializeParameters(self):
        return

    def updateParameters(self):
        # If the layer is selected, and it is a feature layer
        if self.params[0].value:
            layer_name = self.params[0].valueAsText
            try:
                fields = [f.name for f in arcpy.ListFields(layer_name)]
                if "PLAT_NAME" in fields:
                    self.params[1].value = "PLAT_NAME"  # Auto-populate the field name
                    # Get unique values from the PLAT_NAME field
                    values = set()
                    with arcpy.da.SearchCursor(layer_name, ["PLAT_NAME"]) as cursor:
                        for row in cursor:
                            if row[0]:
                                values.add(row[0])
                    self.params[2].filter.list = sorted(values)
                else:
                    self.params[1].value = None
                    self.params[2].filter.list = []
            except Exception as e:
                self.params[1].value = None
                self.params[2].filter.list = []

        return

    def updateMessages(self):
        return


def main():
    # Parameters
    layer_name = arcpy.GetParameterAsText(0)   # Layer name to select from map
    field_name = arcpy.GetParameterAsText(1)   # Field to search (e.g., PLAT_NAME)
    acc_val = arcpy.GetParameterAsText(2)      # Attribute value (e.g., "BRIDGEWATER ESTATES #3")

    if not layer_name or not field_name or not acc_val:
        arcpy.AddError("Layer, field name, or search value is missing.")
        return

    # Access current project, map, and layout
    project = arcpy.mp.ArcGISProject("CURRENT")
    active_map = project.listMaps()[0]
    layout = project.listLayouts()[0]  # Layout is not used here, but included if needed

    # Get the target layer by name
    try:
        target_layer = active_map.listLayers(layer_name)[0]
    except IndexError:
        arcpy.AddError(f"Layer '{layer_name}' not found in the map.")
        return

    # Build where clause using input values directly (no escaping)
    expression = "{0} = '{1}'".format(field_name, acc_val)
    where_clause = str(expression)

    arcpy.AddMessage(f"Where clause: {where_clause}")

    # Perform the selection
    arcpy.management.SelectLayerByAttribute(target_layer, "NEW_SELECTION", where_clause)

    # Count and report results
    count = int(arcpy.management.GetCount(target_layer)[0])
    if count == 0:
        arcpy.AddWarning(f"No features found where {field_name} = '{acc_val}'.")
    else:
        arcpy.AddMessage(f"Selected {count} feature(s) where {field_name} = '{acc_val}'.")

 

0 Kudos
2 Replies
AlfredBaldenweck
MVP Regular Contributor

Gotta ask, why don't you just direct them to select by attribute? Is it because this tool is going to add the selection to the map?

 

Anyway, whenever you use select by attribute/location, you should ALWAYS assign it to a variable. This bites everyone at some point, and it's a common question here. So, Line 67 should be like

sel = arcpy.management.SelectLayerByAttribute(target_layer, "NEW_SELECTION", where_clause)

Then you can add it to the map, etc. 

 

It might be something else, but at first glance, that's my guess.

HaydenWelch
MVP Regular Contributor

I flattened out your code a bit so it's easier to follow, it seems like your general flow is correct, I did add a call to arcpy.GetParameterInfo() in the ToolValidator initialization though.

import arcpy

class ToolValidator:
    def __init__(self):
        self.params: list[arcpy.Parameter] = arcpy.GetParameterInfo()

    def initializeParameters(self): ...
    def updateParameters(self):
        # No updates if the layer isn't selected yet
        if not self.params[0].value:
            return
        
        # Get LayerName and Fields
        layer_name = self.params[0].valueAsText
        fields = [f.name for f in arcpy.ListFields(layer_name)]
        
        # No options if 'PLAT_NAME' is not in the fields
        if "PLAT_NAME" not in fields:
            self.params[1].value = None
            self.params[2].filter.list = []
            return
        
        self.params[1].value = "PLAT_NAME"  # Auto-populate the field name
        # Get unique values from the PLAT_NAME field
        values = {
            plat_name
            for plat_name, *_ in arcpy.da.SearchCursor(layer_name, ["PLAT_NAME"])
            if plat_name
        }
        self.params[2].filter.list = sorted(values)
        return
    def updateMessages(self): ...

def main():
    # Parameters
    layer_name = arcpy.GetParameterAsText(0)   # Layer name to select from map
    field_name = arcpy.GetParameterAsText(1)   # Field to search (e.g., PLAT_NAME)
    acc_val = arcpy.GetParameterAsText(2)      # Attribute value (e.g., "BRIDGEWATER ESTATES #3")

    if not all(layer_name, field_name, acc_val):
        arcpy.AddError("Layer, field name, or search value is missing.")
        return

    # Access current project, map, and layout
    project = arcpy.mp.ArcGISProject("CURRENT")
    active_map = project.listMaps()[0]
    #layout = project.listLayouts()[0]  # Layout is not used here, but included if needed

    # Get the target layer by name
    layer_match = active_map.listLayers(layer_name)
    target_layer = layer_match.pop() if layer_match else None
    
    if not target_layer:
        arcpy.AddError(f"Layer '{layer_name}' not found in the map.")
        return

    # Build where clause using input values directly (no escaping)
    where_clause = f"{field_name} = '{acc_val}'"
    arcpy.AddMessage(f"Where clause: {where_clause}")
    
    # Perform the selection
    try:
        arcpy.management.SelectLayerByAttribute(target_layer, "NEW_SELECTION", where_clause)
    except Exception as e:
        arcpy.AddError(f"!!---Feature Selection Failed:---!!\n{e}")
        return

    # Count and report results
    count = sum(1 for _ in arcpy.da.SearchCursor(target_layer, ['OID@']))
    
    if not count:
        arcpy.AddWarning(f"No features found where {field_name} = '{acc_val}'.")
        return
    
    arcpy.AddMessage(f"Selected {count} feature(s) where {field_name} = '{acc_val}'.")

 

When you run the tool, are you getting any messages? If so which messages?

0 Kudos