fiendskrah / pjscripts

Creating an ArcGIS Pro python toolbox for multi-criteria decision analysis
1 stars 0 forks source link

Standardize field #1

Open fiendskrah opened 1 year ago

fiendskrah commented 1 year ago

This tool allows the user to provide specific criteria in a data layer that will be standardized for later analysis

  1. It accepts a user-specified data layer [x]
  2. It allows the user to select specific fields which will be standardized [x]
  3. It allows the user to specify a standardization method (score/ratio) [x]
  4. it allows the user to specify whether the provided field is a cost or benefit criteria [x]
  5. it executes the intended functionality [ ]

This tool is optional for the current assignment but I still would like to include it because other arcgis tools I can find don't add the standardized scores to the attribute table for use in later tools.

fiendskrah commented 1 year ago

Original code:

# Adds a standardized version of the input field
# to the input feature attribute table
# standardization scale [0.0, 1.0]
# AUTHOR: Arika Ligmann-Zielinska
# LAST UPDATED: July 21 2011
#--- IMPORTS ----------------------------------------------------------
import sys, arcpy
#------------- INPUTS -------------------------------------------------

inFC = sys.argv[1]
infield = sys.argv[2]
outfield = sys.argv[3]  # output field name
benefit = sys.argv[4]   # treat as benefit or cost?
method = sys.argv[5]    # standardization method

#------------- APPLICATION --------------------------------------------
try:
    # [1] Check input field - must be "numeric"
    fields = arcpy.ListFields(inFC, infield)
    for fld in fields:
        if fld.type not in ["SmallInteger","Integer","Single","Double"]:
            arcpy.AddError(infield+" is not numeric.")
            sys.exit(1)
    # [2] add field
    arcpy.AddField_management(inFC, outfield, "FLOAT", 6, 3)
    arcpy.AddMessage("Field "+outfield+" created.")
    # [3] Get a list of input field values to standardize
    rows = arcpy.SearchCursor(inFC)   
    fieldVals = []
    for row in rows:
        aval = row.getValue(infield)
        fieldVals.append(aval)
    del row; del rows
    # Get min & max
    minVal = min(fieldVals)
    maxVal = max(fieldVals)
    # [4] standardize
    if benefit == "BENEFIT":
        if method == "RATIO (LINEAR SCALE)":
            rows = arcpy.UpdateCursor(inFC)
            for row in rows:
                sval = float(row.getValue(infield))/maxVal
                row.setValue(outfield,sval)
                rows.updateRow(row)
            del row; del rows
        else: # 'SCORE RANGE' selected
            arange = float(maxVal - minVal)
            rows = arcpy.UpdateCursor(inFC)
            for row in rows:
                sval = float(row.getValue(infield)) - minVal
                sval = sval/arange
                row.setValue(outfield,sval)
                rows.updateRow(row)                
            del row; del rows
    else: # 'COST'
        if method == "RATIO (LINEAR SCALE)":
            rows = arcpy.UpdateCursor(inFC)
            for row in rows:
                sval = minVal/float(row.getValue(infield))
                row.setValue(outfield,sval)
                rows.updateRow(row) 
            del row; del rows
        else: # 'SCORE RANGE' selected
            arange = float(maxVal - minVal)
            rows = arcpy.UpdateCursor(inFC)
            for row in rows:
                sval = maxVal - float(row.getValue(infield))
                sval = sval/arange
                row.setValue(outfield,sval)
                rows.updateRow(row)
            del row; del rows
    # display the information
    info = infield+ " of "+inFC+" standardized to "+outfield
    arcpy.AddMessage(info)
except:
    arcpy.AddError("Script run error: "+arcpy.GetMessages(2))

current pyt:

class StandardizeRatiosScore(object):
    def __init__(self):
        """Define the tool (tool name is the name of the class)."""
        self.label = "Standardize Ratios/Score"
        self.description = "Takes numerical data from a user-provided field in a data layer in the current ArcGIS Pro project, as well as a user-provided cost/benefit binary value, and returns the data as a standardized ratio or score."
        self.canRunInBackground = False

    def getParameterInfo(self):
        """Define parameter definitions"""
        input_table = arcpy.Parameter(
            displayName="Input Table",
            name="input_table",
            datatype="GPTableView",
            parameterType="Required",
            direction="Input")

        fields_to_standardize = arcpy.Parameter(
            displayName="Field with Numerical Data",
            name="fields_to_standardize",
            datatype="Field",
            parameterType="Required",
            direction="Input",
            enabled=False,
            multiValue=True)
        fields_to_standardize.parameterDependencies = [input_table.name]

        standardization_method = arcpy.Parameter(
            displayName="Standardization Method",
            name="standardization_method",
            datatype="GPString",
            parameterType="Required",
            direction="Input")
        standardization_method.filter.type = "ValueList"
        standardization_method.filter.list = ['Score Range', 'Ratio (Linear Scale)']

        cost_benefit = arcpy.Parameter(
            displayName="Cost/Benefit",
            name="cost_benefit",
            datatype="GPString",
            parameterType="Required",
            direction="Input",
            multiValue=False)
        cost_benefit.filter.type = "ValueList"
        cost_benefit.filter.list = ['Cost', 'Benefit']

        # define the derived output parameter
        outfield_name = arcpy.Parameter(
            displayName="Output Field Name",
            name="outfield_name",
            datatype="GPString",
            parameterType="Required",
            direction="Input",
            enabled=True)
        cost_benefit.filter.type = "Value"

        outfield = arcpy.Parameter(
            displayName="Output Field",
            name="outfield",
            datatype="Field",
            parameterType="Derived",
            direction="Output")

        parameters = [input_table, fields_to_standardize, standardization_method, cost_benefit, outfield, outfield_name]
        return parameters

    def updateParameters(self, parameters):
        """Modify the values and properties of parameters before internal
        validation is performed.  This method is called whenever a parameter
        has been changed."""
        if parameters[0].altered:
            parameters[1].enabled = True

    def execute(self, parameters, messages):
        """The source code of the tool."""
        input_table = arcpy.GetParameterAsText(0)
        fields_to_standardize = arcpy.GetParameterAsText(1)

        # Get the minimum and maximum values of the user-provided field
        with arcpy.da.SearchCursor(input_table, [fields_to_standardize]) as cursor:
            max_value = None
            min_value = None
            for row in cursor:
                if max_value is None or row[0] > max_value:
                    max_value = row[0]
                if min_value is None or row[0] < min_value:
                    min_value = row[0]
        # create a dictionary to store the max and min values
        result_dict = {'maximum': max_value, 'minimum': min_value}

        outfield_name = parameters[5].valueAsText
        # Add the new field to the input layer
        arcpy.AddField_management(input_table, outfield_name, "DOUBLE") 

        # set parameters for standardization loop
        result_dict = eval(parameters[4].valueAsText)
        method = parameters[2].valueAsText
        benefit = parameters[3].valueAsText
        maxVal = result_dict['maximum']
        minVal = result_dict['minimum']
        outfield = parameters[5]

        # standardize the score of each row using the min and max values
        if benefit == "Benefit":
            if method == "Ratio (Linear Scale)":
                rows = arcpy.UpdateCursor(input_table)
                for row in rows:
                    sval = float(row.getValue(row))/maxVal
                    row.setValue(outfield,sval)
                    rows.updateRow(row)
                del row; del rows
            else: # 'Score Range' selected
                arange = float(maxVal - minVal)
                rows = arcpy.UpdateCursor(input_table)
                for row in rows:
                    sval = float(row.getValue(row)) - minVal
                    sval = sval/arange
                    row.setValue(outfield,sval)
                    rows.updateRow(row)                
                del row; del rows
        else: # 'Cost'
            if method == "Ratio (Linear Scale)":
                rows = arcpy.UpdateCursor(input_table)
                for row in rows:
                    sval = minVal/float(row.getValue(row))
                    row.setValue(outfield,sval)
                    rows.updateRow(row) 
                del row; del rows
            else: # 'Score Range' selected
                arange = float(maxVal - minVal)