[GIS] Handling multi-column value table in ArcGIS Python Toolbox

arcgis-10.3arcpyparameterspython-toolboxvalue-table

I am building a relatively simple python tool for ArcGIS 10.3 which will automate the process of generating summary statistics for multiple raster datasets, for polygons in a polygon dataset, using ESRI's Zonal Statistics tool. The key component of the tool is a multi-column value table that will allow the user to input:

  1. a raster dataset (to be summarized)
  2. summary statistic that will be calculated (i.e. mean, range, max, etc.)
  3. name of the column that will be added to the polygon dataset (which will contain the summary statistic values)

Because I need to use a value table, I decided to use a Python Toolbox as the interface for my python script. I've tested the code that performs the geoprocessing, and it works. The problem I'm having now is that when the value table is passed to my python script from the toolbox, it's being sent as unicode, and my script doesn't recognize that variable as a being a value table. I assume this is because the parameters are being sent using this code (which is recommended by ESRI):

parameters[2].valueAsText

which results in this error:

line 14, in main
  param_count = param_tbl.rowCount
AttributeError: 'unicode' object has no attribute 'rowCount'

I've tried changing how the parameter is sent, i.e.

parameters[2].values

however, this results in:

AttributeError: 'list' object has no attribute 'rowCount'

How exactly should a value table be sent from the Python Tool execute function or do I need to convert the variable from a string back into a value table in my geoprocessing script?

Here's the relevant code from the Python Toolbox (.pyt):

    param2 = arcpy.Parameter(
        displayName='Summary data list',
        name='stat_list',
        datatype='GPValueTable',
        parameterType='Required',
        direction='Input')
    param2.columns = [['Raster Dataset','Raster Dataset'], ['GPString','Statistic Type'], ['GPString', 'Summary Field Name']]
    param2.filters[1].type = 'ValueList'
    param2.filters[1].list = ['ALL', 'MEAN', 'MAXIMUM', 'MINIMUM', 'RANGE', 'STD', 'SUM']

def execute(self, parameters, messages):
    """The source code of the tool."""
    ps.main(parameters[0].valueAsText,
            parameters[1].valueAsText,
            parameters[2].valueAsText,
            parameters[3].valueAsText,
            parameters[4].valueAsText)
    return

and here's the relevant code from the Python script that performs the statistical summary and geoprocessing:

import arcpy
from arcpy.sa import *
import polystat_util as u
arcpy.CheckOutExtension("SPATIAL")

arcpy.env.overwriteOutput = True

def main(in_fc, in_fc_join_field, param_tbl, out_path, out_fc):
    arcpy.MakeFeatureLayer_management(in_fc, "in_fc_lyr")
    param_count = param_tbl.rowCount

    # add new fields to polygon feature class that will contain summarized stats
    param_names = []
    zone_field = "ZONE_INDEX"
    for i in range(param_count):
        param_val = param_tbl.getValue(i,2)
        param_names.append(param_val)
    arcpy.AddField_management("in_fc_lyr", zone_field, "TEXT")
    arcpy.CalculateField_management("in_fc_lyr", zone_field, "!" + in_fc_join_field + "!", "Python_9.3")
    ply_tmp = u.AddStatFields("in_fc_lyr", zone_field, param_names)

    for j in range(param_count):
        raster_name = param_tbl.getValue(j,0)
        stat_name = param_tbl.getValue(j,1)
        field_name = param_tbl.getValue(j,2)
        ras_lyr = arcpy.MakeRasterLayer_management(raster_name, "ras_lyr")
        zstat_result = ZonalStatisticsAsTable(ply_tmp, zone_field, ras_lyr, "in_memory\\zstat", "DATA", stat_name)
        u.JoinCalc(ply_tmp, zone_field, field_name, zstat_result, stat_name)

     arcpy.FeatureClassToFeatureClass_conversion(ply_tmp, out_path, out_fc)
    return

Here's my revised code snippet, based on Farid's answer:

def main(in_fc, in_fc_join_field, param_tbl, out_path, out_fc):
    # extract values from value table
    param_rows = param_tbl.split(';')
    vt_array = []
    for r in param_rows:
        vt_array.append(r.split())

    param_count = len(param_rows)

    for j in range(param_count):
        raster_name = vt_array[j][0]
        stat_name = vt_array[j][1]
        field_name = vt_array[j][2]
        ras_lyr = arcpy.MakeRasterLayer_management(raster_name, "ras_lyr")
        zstat_result = ZonalStatisticsAsTable(ply_tmp, zone_field, ras_lyr, "in_memory\\zstat", "DATA", stat_name)

Best Answer

Within the execute method, each parameter's value can be accessed from the list using the valueAsText method. Other Parameter object properties can be accessed as needed.

Here is your solution:

def execute(self, parameters, messages):
        #parameters[0]  is your value table  
        vt_text = parameters[0].valueAsText
        arcpy.AddMessage(vt_text)
        #for a two rows value table output:
        #col1 col2 #;col1 col2 col3    where # stands for not set

        # to get the row count
        if vt_text != '':
            arcpy.AddMessage("Row Count: " + str(len(vt_text.split(';'))))
        else:
            arcpy.AddMessage("Row Count: 0")

        return
Related Question