0

I am trying to build a script tool for my job that takes any vector feature (roads, rails, land cover, water polygons etc) and clips it to selected geocells. The geocells are one feature with a field (ID) that displays the name of each geocell. I have used the blog post here:

https://www.arcgis.com/home/item.html?id=91501d56a92e4534a16054554ac9f6d1

to allow users of the tool to be able to select one or more geocells of their choosing to perform the clip. I want the tool built this way so that essentially any boundary type polygon can be used as the clipping feature where you can select portions of the boundary polygon based on a field value.

Here is my code:

# Import libraries and set environments
import os
import arcpy
from arcpy import env
from arcpy.sa import *
from arcpy.ddd import *
env.overwriteOutput = True

# Set the parameters
InputBoundary = arcpy.GetParameterAsText(0)
InputField = arcpy.GetParameterAsText(1)
InputValue = arcpy.GetParameterAsText(2)
selection = arcpy.SetParameter(3, InputValue)
InputFeature = arcpy.GetParameterAsText(4)
Output = arcpy.GetParameterAsText(5)

# Perform the Clip
arcpy.PairwiseClip_analysis(InputFeature, selection, Output)

As written the tool will fail and say that I am not honoring all of the parameters of the clip analysis. That has to to with having "selection" as the clip feature. If I change "selection" to be "InputBoundary" the tool will work but instead of honoring the selection of individual geocells, the tool is clipping the features to the full extent of all geocells

The GUI of my tool looks like how I want it to and lets me select individual geocells:

Feature Extraction Tool

As described in the link above, I am trying to expand upon the example tool to create a MULTIVALUE parameter choice list from an input feature class/table automatically.

In ArcGIS Pro, that example tool's parameters and code look like this:

as shown here

I have attempted to expand upon that example tool's setup like this:

as shown here

I just want to be able to input a boundary polygon, select certain parts of that polygon, and use that selection to clip out portions of another feature.

2
  • 1
    Do you really have 6 parameters? I only see 5. If I understand correctly, 'selection' isn't a parameter but rather should be defined as a feature layer of parameter(0) with a query where the field parameter(1) includes the values of parameter(2).
    – Brennan
    Aug 10, 2022 at 16:00
  • @Brennan Yes, I have edited my question to include screenshots of what the parameters look like for the example tool I am attempting to expand from and what the parameters are of my current tool attempt. The example tool uses this script as a part in a larger model builder setup so in the mean time I am going to do the same and see if that provides a solution, however, I would like the whole tool to just run in python
    – Ferenczi
    Aug 11, 2022 at 14:47

1 Answer 1

1

Save this code as a Python Toolbox (ExtractFeatures.pyt). It should provide the functionality you are describing, and you can re-purpose as needed to work within your model.

# -*- 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 = "Extract Features"
        self.alias = "pytbx"

        # List of tool classes associated with this toolbox
        self.tools = [extractor]

class extractor(object):
    def __init__(self):
        self.label = "Feature Extraction Tool"
        self.description = "Performs a clip based on selected values"
        self.canRunInBackground = False

    def getParameterInfo(self):
        
        InputBoundary = arcpy.Parameter( #0
            displayName="Input Boundary Features",
            name="InputBoundary",
            datatype="GPFeatureLayer",
            parameterType="Required",
            direction="Input")
        InputBoundary.filter.list = ["Polygon"]
       
        InputField = arcpy.Parameter( #1
            displayName="Input Field",
            name="InputField",
            datatype="GPString",
            parameterType="Required",
            direction="Input")    
       
        Values = arcpy.Parameter( #2
            displayName = "Select Values in Field",
            name = "Values",
            datatype="GPString",
            parameterType="Required",
            direction = "Input",
            multiValue = True)
            
        InputFeatures = arcpy.Parameter( #3
            displayName="Input Features to Clip",
            name="InputFeatures",
            datatype="GPFeatureLayer",
            parameterType="Required",
            direction="Input")
        
        Output = arcpy.Parameter( #4
            displayName="Output Feature Class",
            name="Output",
            datatype="DEFeatureClass",
            parameterType="Required",
            direction="Output")
            
        parameters = [InputBoundary,InputField,Values,InputFeatures,Output]
        return parameters
    
    def updateParameters(self, parameters):
        #if InputBoundary is defined/changed, clear subsequent values and populate InputField list
        if parameters[0].value and not parameters[0].hasBeenValidated:
            parameters[1].value = ''
            parameters[1].filter.list = [f.name for f in arcpy.ListFields(parameters[0].value) if f.type not in ['Blob','Geometry']]
            parameters[2].value = None
            parameters[2].filter.list = []
        
        #if InputField is defined/changed, clear and populate Values list
        if parameters[1].value and not parameters[1].hasBeenValidated:
            parameters[2].value = None
            parameters[2].filter.list = list(set(str(row[0]) for row in arcpy.da.SearchCursor(parameters[0].valueAsText, parameters[1].valueAsText)))
        
        return    
        
    def execute(self, parameters, messages):
        
        InputBoundary   = parameters[0].valueAsText
        InputField      = parameters[1].valueAsText
        Values          = parameters[2].values
        InputFeatures   = parameters[3].valueAsText
        Output          = parameters[4].valueAsText
        
        #Define the selection query based on if InputField is numeric or string
        InType =  arcpy.ListFields(InputBoundary,InputField)[0].type
        if InType.lower() in ('string','guid','globalid'):
            query = InputField+" IN ({:s})".format(','.join(f"'{x}'" for x in Values))
        else:
            query = InputField+" IN ({:s})".format(','.join(f"{x}" for x in Values))
            
        #select by attribute and clip
        arcpy.management.SelectLayerByAttribute(InputBoundary, 'NEW_SELECTION', query)
        arcpy.analysis.Clip(InputFeatures, InputBoundary, Output)
        
        return


0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.