Modifiable field variable

2305
9
Jump to solution
08-29-2018 09:37 AM
JohnPapageorgiou
New Contributor III

Hi,

I am trying to put together a python script that among other things allows the user to input a given feature class, select a field from it and pass that field along as a variable in the field calculator. In the attached code sample the calculation is on line 35, I need !HT_FT! to have the ability to be modifiable, because when we receive these feature classes from the client, that field of tree heights does not always have the same name. I tried creating a variable in line 30, but that did not work (it is now commented out so it doesn't interfere with the rest of the script). I was hoping to set up a system that would allow the user input the workspace, feature class we receive, and select a field from that feature class to base all other calculations (as in the attached tool and parameters screenshots. However, whenever I run that I get an error that says "the field has not been defined."  Any help is greatly appreciated.

Thanks!
John

Tags (3)
0 Kudos
1 Solution

Accepted Solutions
RandyBurton
MVP Alum

As Brittney White‌ is suggesting, you should use the ToolValidator (Validation tab in tool's properties).  See Programming a ToolValidator class and related documentation for additional information.  For my test I pasted Brittney's code in the updateParameters section with no changes.

For the tools Parameters, I defined them as a feature class and a string.

parameters

I used the following script for my tests.  The expression used in the field calculator is interesting to code (line 22 below) as you need to escape curly braces and watch your quote marks so that when the expression is passed, it has the proper values.  the first .format will work with the escaped curly braces in field calculator, and the second .format will insert the field name used for the calculation.  Perhaps Dan Patterson‌ can suggest alternative ways of formatting the expression.

import arcpy
from arcpy import env
import os, sys, traceback

feature = arcpy.GetParameterAsText(0)
field = arcpy.GetParameterAsText(1)

arcpy.AddMessage("Feature: {}".format(feature)) 
arcpy.AddMessage("Field: {}".format(field))

env.workspace = feature

# arcpy.env.overwriteOutput = True
# env.transferDomains = True

# add a new field to feature
newField = 'HT_FT_txt'
arcpy.AddField_management(feature, newField, 'TEXT', '', '', '50', 'Buffer_field', 'NULLABLE')

# calculate HT_FT_txt field
arcpy.CalculateField_management(feature, newField,
                                expression="'{{}} Feet'.format(!{}!)".format(field),
                                expression_type="PYTHON_9.3", code_block="")‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

My version of the tool looks like the following.  The red x indicates that the feature class needs to be entered. 

script tool

I have not checked your code for the buffer calculation.

View solution in original post

0 Kudos
9 Replies
BrittneyWhite1
Esri Contributor

You should be able to accomplish with with ToolValidator class. See: Customizing script tool behavior—Geoprocessing and Python | ArcGIS Desktop: http://pro.arcgis.com/en/pro-app/arcpy/geoprocessing_and_python/customizing-script-tool-behavior.htm. In particular, you can use the updateParameters method and the filter object (See: Filter—ArcPy classes | ArcGIS Desktop: http://pro.arcgis.com/en/pro-app/arcpy/classes/filter.htm).

Here's a simple example from a script tool that has 2 parameters, the first is an input feature class, and the second is field name. This code derives a pick list of field names based on the input feature class.

def updateParameters(self):
        """Modify the values and properties of parameters before internal
        validation is performed. This method is called whenever a parameter
        has been changed."""
        # The first parameter in the tool [0] is the input feature class.
        # The second parameter in the tool [1] is the derived list of field names.
        string_filter = self.params[1].filter
        feature_class = self.params[0].value
        if feature_class:
            string_filter.list = [fld.name for fld in 
                                  arcpy.Describe(feature_class).fields]
        # If the user hasn't changed the keyword value, set it to the
        # default value (first value in the value list filter).
        if not self.params[1].altered:
            self.params[1].value = string_filter.list[0]
        return
JohnPapageorgiou
New Contributor III

Hi Brittney,

Thank you for your response, I'll give it a try.  I forgot to mention that I am working in ArcGIS Desktop 10.4.1 will your solution work there, or do I have to use ArcGIS Pro?  They use different versions of python.

thanks,

John

0 Kudos
BrittneyWhite1
Esri Contributor

Yes, the ToolValidator class is available in ArcMap. See: Customizing script tool behavior—Help | ArcGIS Desktop: http://desktop.arcgis.com/en/arcmap/10.4/analyze/creating-tools/customizing-script-tool-behavior.htm

0 Kudos
DanPatterson_Retired
MVP Emeritus

parameter 0 is the workspace

parameter 1 is the featureclass

parameter 2 is the field derived from the featureclass.

Your script needs to be modified to reflect that (modelbuilder to script isn't great, especially if you make changes)

That is why the field name is hardcoded in your field calculation

0 Kudos
JohnPapageorgiou
New Contributor III

Hi Dan,

Thank you for helping me think of this in a different way.  That is exactly what is giving me difficulties.  At present the field name is hardcoded because that is the only way I can get it to work.  I'm having trouble figuring out how to define parameter 2.  I tried "arcpy.GetParameterAsText" but that did not work.  Is there some literature you can direct me to that discusses how to define a parameter whose variable is a field derived from an input feature class?

thank you,

John

0 Kudos
DanPatterson_Retired
MVP Emeritus

John.. the simplest thing in ArcMap is to do each step manually using the tool in arctoolbox, then copy the code snippet.

It will give you the exact syntax.  If you do that and post it we can proceed.  When you specify a field derived from a featureclass, you will get a string representation of just that and you will see how it goes into the next step as a variable

RandyBurton
MVP Alum

As Brittney White‌ is suggesting, you should use the ToolValidator (Validation tab in tool's properties).  See Programming a ToolValidator class and related documentation for additional information.  For my test I pasted Brittney's code in the updateParameters section with no changes.

For the tools Parameters, I defined them as a feature class and a string.

parameters

I used the following script for my tests.  The expression used in the field calculator is interesting to code (line 22 below) as you need to escape curly braces and watch your quote marks so that when the expression is passed, it has the proper values.  the first .format will work with the escaped curly braces in field calculator, and the second .format will insert the field name used for the calculation.  Perhaps Dan Patterson‌ can suggest alternative ways of formatting the expression.

import arcpy
from arcpy import env
import os, sys, traceback

feature = arcpy.GetParameterAsText(0)
field = arcpy.GetParameterAsText(1)

arcpy.AddMessage("Feature: {}".format(feature)) 
arcpy.AddMessage("Field: {}".format(field))

env.workspace = feature

# arcpy.env.overwriteOutput = True
# env.transferDomains = True

# add a new field to feature
newField = 'HT_FT_txt'
arcpy.AddField_management(feature, newField, 'TEXT', '', '', '50', 'Buffer_field', 'NULLABLE')

# calculate HT_FT_txt field
arcpy.CalculateField_management(feature, newField,
                                expression="'{{}} Feet'.format(!{}!)".format(field),
                                expression_type="PYTHON_9.3", code_block="")‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

My version of the tool looks like the following.  The red x indicates that the feature class needs to be entered. 

script tool

I have not checked your code for the buffer calculation.

0 Kudos
DanPatterson_Retired
MVP Emeritus

here is a quick example of doing it manually and copying the tool's code expression

Which is exactly what is expected if you build the query manually for record.

arcpy.management.CalculateField("s0", "test_text", "str(!OBJECTID!)", "PYTHON3", None)

I am not exactly sure what expression you are trying to build

That expression on line 21 will yield

in_fld = 'test_field'
"'{{}} Feet'.format(!{}!)".format(in_fld)
"'{} Feet'.format(!test_field!)"
if that is what you want and it will take whatever value... string or number (say 5)... and return  
5 Feet
Is that right?
RandyBurton
MVP Alum

In the OP's code, he has for the expression:

'format( !HT_FT! ) + " Feet"'

So, assuming the value is 5 in the field HT_FT (or another field as selected by the script's parameter), I think "5 Feet" would be the desired result.  And field calculator was happy to put that value in the field.  I just wasn't sure if there was a more efficient/readable way of writing the expression. 

0 Kudos