I've created the following field calculation that I'd like to convert to a python script tool:
def blocklow(a, b, c, d):
mylist = [a, b, c, d] # create list from input range variables
if mylist == [0, 0, 0, 0]:
m = 0
else:
m = min(i for i in mylist if i > 0) # find minimum value greater than zero
if m > 0 and m < 99:
return 10 # value for minimum block number between 1-99
elif m == 0:
return 0
else:
return int(math.floor(m / 100.0)) * 100 # round minimum to lowest hundred
esri_field_calculator_splitter blocklow( !LLO!, !LHI!, !RLO!, !RHI!)
The gist of it is there are four address range fields (integer type) and I'm after the lowest numeric value, rounded down to an even hundred, that isn't zero. It works, although I'm sure there is room for improvement.
I'd like to convert this to a script tool. I've done it semi-successfully defining a parameter for the feature class and field to be calculated. However, if add parameters for the input fields of the calculation and then try to reference those in the function, it fails. Also, I'm using the arcpy.CalculateField_management approach but calling a function by as a string kind of sucks. I'm sure there's a more elegant and efficient way.
Here's what the script tool should look like:
I'm really a rookie at best.
Update: here's the script I'm working on. I'm still off somewhere (probably everywhere). Any ideas:
import arcpy
arcpy.env.overwriteOutput = True
try:
inCenterline = arcpy.GetParameterAsText(0)
inBlockF = arcpy.GetParameterAsText(1)
inLF = arcpy.GetParameterAsText(2)
inLT = arcpy.GetParameterAsText(3)
inRF = arcpy.GetParameterAsText(4)
inRT = arcpy.GetParameterAsText(5)
expression = "blocklow(inLF, inLT, inRF, inRT)"
codeblock = """import math
def blocklow(a, b, c, d):
mylist = [a, b, c, d] # create list from input range variables
if mylist == [0, 0, 0, 0]:
m = 0
else:
m = min(i for i in mylist if i > 0) # find minimum value greater than zero
if m > 0 and m < 99:
return 10 # value for minimum block number between 1-99
elif m == 0:
return 0
else:
return int(math.floor(m / 100.0)) * 100 # round minimum to lowest hundred"""
arcpy.CalculateField_management(inCenterline, inBlockF, "blocklow(inLF, inLT, inRF, inRT)", "PYTHON_9.3", codeblock)
arcpy.AddMessage("Calculation complete")
except:
arcpy.AddError("Could not complete the calculation")
arcpy.AddMessage(arcpy.GetMessages())
UPDATE: Here's the finished script and tool based on the example and direction that Michael provided.
# ---------------------------------------------------------------------------
# Calculate_Addr_Blocks_Tool.py
# Author: Josse Allen: Product Instructor, Spillman Technologies, Inc
# Original creation date: 2015-09-15
# Version: beta
# Revisions:
# Revision notes:
# Description: this script is used with an ArcGIS script tool. The tool
# evaluates the from-to/left-right address range values for each row in the
# centerline, finds the lowest value, and rounds DOWN to the LOWEST hundred.
#
# Platform: developed using Python 2.6, ArcGIS Desktop 10.0 - Basic
#
# Input requirements:
# - Input centerline (containing from-to/left-right address range fields
# - To/from address range fields for left/right sides (4 total, short or long)
#
# ---------------------------------------------------------------------------
import arcpy
# The output result will be calculated in the input!
arcpy.env.overwriteOutput = True
# Prelogic used to pass through for calculating the low block number
CodeBlockL = """
def blocklow(a, b, c, d):
mylist = [a, b, c, d] # create list from input range variables
if mylist == [0, 0, 0, 0]:
m = 0
else:
m = min(i for i in mylist if i > 0) # find minimum value greater than zero
if m > 0 and m < 99:
return 10 # value for minimum block number between 1-99
elif m == 0:
return 0
else:
return int(math.floor(m / 100.0)) * 100 # round minimum to lowest hundred
""" # Finished Code block
# Prelogic used to pass through for calculating the high block number
CodeBlockH = """
def blockhigh(a, b, c, d):
h = max(a, b, c, d) # find high value from input range variables
if h == 0:
return 0
else:
return int(math.ceil(h / 100.0)) * 100 - 1 # round to highest hundred less 1
""" # Finished Code block
try:
# Set input parameters
inCenterline = arcpy.GetParameterAsText(0) # Source layer containing the address range fields
inLF = arcpy.GetParameterAsText(1) # Script tool parameter for left from address value
inLT = arcpy.GetParameterAsText(2) # Script tool parameter for left to address value
inRF = arcpy.GetParameterAsText(3) # Script tool parameter for right from address value
inRT = arcpy.GetParameterAsText(4) # Script tool parameter for right to address value
# Set variables for fields to be added
field_nameL = "BLOCKLO" # Field name to be created for the low block value
field_nameH = "BLOCKHI" # Field name to be created for the high block value
# create fields for output values
arcpy.AddMessage("Adding fields for block low and high values")
arcpy.AddField_management(inCenterline, field_nameL, "LONG", "", "", "", "", "NULLABLE", "NON_REQUIRED", "")
arcpy.AddField_management(inCenterline, field_nameH, "LONG", "", "", "", "", "NULLABLE", "NON_REQUIRED", "")
# Calculate the block low field
expressionL = "blocklow(!{0}!, !{1}!, !{2}!, !{3}!)".format(inLF, inLT, inRF, inRT)
arcpy.AddMessage("Calculating the low block value...")
arcpy.CalculateField_management(inCenterline, field_nameL, expressionL, "PYTHON_9.3", CodeBlockL)
arcpy.AddMessage("Low block calculation complete")
# Calculate the block high field
expressionH = "blockhigh(!{0}!, !{1}!, !{2}!, !{3}!)".format(inLF, inLT, inRF, inRT)
arcpy.AddMessage("Calculating the high block value...")
arcpy.CalculateField_management(inCenterline, field_nameH, expressionH, "PYTHON_9.3", CodeBlockH)
arcpy.AddMessage("High block calculation complete")
except:
arcpy.AddError("Could not complete the calculation")
arcpy.AddMessage(arcpy.GetMessages())
Calculate Field
, run it normally and then under the Results window, right click the result andcopy to Python snippet
.