2

I'm trying to work out how to populate a field depending on the lowest score across 6 other fields. I've read several other questions relating to if/else statements but I'm only just starting to learn Python so I'm struggling to put together any code that works.

I'm trying to populate a 'Main Failing' field, where for each object ID in the feature class the worst scored field out of 6 other fields will be noted.

The other fields are: 'Interconnectivity', 'PropCover', 'PatchSize', 'ShapeIndex', 'Naturalness' and 'EdgeNat' and they are all short integer, with high numbers being better than low numbers.

So for example if 'Interconnectivity' had the lowest score across the 5 fields for one objectID, I would like to work out how to populate the 'Main Failing' column for that objectID with text saying 'Interconnectivity'.

Edited: Here's an example of the code I've tried so far with Branco's help. It's running without errors but is either leaving the MainFailing field blank (if 'return resultList[0]') or is populating it with 0's (if return resultList[1]).

Codeblock:

myFunction( !InterconnectivityScore!, !PropCoverScore!, !PatchSizeScore!, !ShapeIndexScore!, !NatScore!, !EdgeNatScore!)

Pre-logic script code:

def myFunction ( interconnectivityScoreValue, propCoverScoreValue, patchSizeScoreValue, shapeIndexScoreValue, natScoreValue, edgeNatScoreValue):
resultList = ["",0]
if interconnectivityScoreValue <= resultList[1]:
 resultList[0] = "Interconnectivity"
 resultList[1] = InterconnectivityScore
if propCoverScoreValue <= resultList[1]:
 resultList[0] = "ProportionalCover"
 resultList[1] = PropCoverScore
if patchSizeScoreValue <= resultList[1]:
 resultList[0] = "PatchSize"
 resultList[1] = PatchSizeScore
if shapeIndexScoreValue <= resultList[1]:
 resultList[0] = "ShapeIndex"
 resultList[1] = ShapeIndexScore
if natScoreValue <= resultList[1]:
 resultList[0] = "Naturalness"
 resultList[1] = NatScore
if edgeNatScoreValue <= resultList[1]:
 resultList[0] = "EdgeNaturalness"
 resultList[1] = EdgeNatScore
return resultList[1]
asked Feb 17, 2015 at 16:54
2
  • Do you have duplicate min values or "None" values in your attribute table? Commented Feb 17, 2015 at 19:48
  • @Aaron - I don't have any 'none' values, but there may be cases where there may be a joint minimum value across the fields Commented Feb 18, 2015 at 15:56

2 Answers 2

2

Try this (edited per @alpha-beta-soup comment):

def myFunction (inter, prop, patch, shp, nat, edge):
 myList = [inter, prop, patch, shp, nat, edge]
 myList.sort()
 myDict = {'Interconnectivity' : inter,
 'PropCover' : prop,
 'PatchSize' : patch,
 'ShapeIndex': shp,
 'Naturalness' : nat,
 'EdgeNat' : edge}
 myVal = 101 # using 101 as a max + 1 possible value; adjust if needed
 myReturn = ''
 for k, v in myDict.iteritems():
 if v < myVal:
 myVal = v
 myReturn = k
 return myReturn

Note that if you have two matching low values, there's nothing to select one over the other. That would require additional checking based on whatever your criteria is. Since a dictionary is unordered, you can't control it that way.

Here's another way without dictionaries, with an optional clause for ties. You may want different logic in case of ties.

def myFunction2 (inter, prop, patch, shp, nat, edge):
 # use tuples to ensure value order
 myScoreTuple = (prop, patch, shp, nat, edge)
 myTextTuple = ('PropCover',
 'PatchSize',
 'ShapeIndex',
 'Naturalness',
 'EdgeNat')
 # initialize values
 myLowValue = inter
 myReturn = 'Interconnectivity'
 # now check for any lower value
 for i in range(len(myScoreTuple)):
 if myScoreTuple[i] < myLowValue:
 myLowValue = myScoreTuple[i]
 myReturn = myTextTuple[i]
 # optional - add multiple text values in case of tie. Remove if unneeded
 elif myScoreTuple[i] == myLowValue:
 myReturn = ', '.join((myReturn, myTextTuple[i]))
 return myReturn
answered Feb 18, 2015 at 13:51
4
  • 1
    Given all the parameters are integer values, it seems to me that there'd be an error with keys not being unique. Commented Feb 18, 2015 at 20:26
  • Hmm, yes, hadn't thought of that. If the scores are guaranteed to be exclusive (i.e., a hierarchical ranking), it will work. Maybe I can flip the keys and values and search in a for loop for the smallest value. Let me think about it. Commented Feb 18, 2015 at 20:39
  • Thanks very much for your help. I've had a go both ways but am still struggling to make it work - my limited Python knowledge probably isn't helping! Error says 'a field name was not found or there were unbalanced quotation marks' Commented Feb 19, 2015 at 15:19
  • It worked on my end in PyScripter. Did you copy and paste the code, or enter it manually? As the error states, check for missing or extra quotation marks, and that you're passing in all 6 (not 5) fields. Commented Feb 19, 2015 at 15:26
0

You can do this using the field calculator and python. Make sure you have the Parser set to Python and the code block being shown.

Here is an idea of what the field calculator should look like when finished..

The code I set up just uses a series of IF statements. I decided this was easier since I was comparing their scores, which I am assuming are numeric scores? In either case, I am not doing any checking for 2 scores having the same value. I am sure you can figure out that part, or figure out how to handle strings (if that is how the info is being stored). I wasn't going to worry about if, elif, etc etc... This would be run from your Main Failing field calculator. This is the main Pre-Logic Script Code: part. This outlines the function you're going to be using to process the passed in information in your *MainFailing * (Field12 for me) part. These are your function parameters.

def myFunction(interconnectivityValue, propCoverValue, patchSizeValue, shapeIndexValue, naturalnessValue, edgeNatValue):
 resultList = ["", 0]
 if interconnectivityValue <= resultList[1]:
 resultList[0] = "interconnectivity"
 resultList[1] = interconnectivityValue
 if propCoverValue <= resultList[1]:
 resultList[0] = "propCover"
 resultList[1] = propCoverValue
 if patchSizeValue <= resultList[1]:
 resultList[0] = "patchSize"
 resultList[1] = patchSizeValue 
 if shapeIndexValue <= resultList[1]:
 resultList[0] = "shapeIndex"
 resultList[1] = shapeIndexValue
 if naturalnessValue <= resultList[1]:
 resultList[0] = "naturalness"
 resultList[1] = naturalnessValue
 if edgeNatValue <= resultList[1]:
 resultList[0] = "edgeNat"
 resultList[1] = edgeNatValue
 return resultList[0]

The Main Failing part lets you specify how you want to call whatever function you declared in your Pre-Logic Script Code: section. To pass the fields for each row, notice that the field names are surrounded by !'s. This is how python knows to grab the value from the attribute table.

Using python (or VB Script) in the field calculator is a nice step towards using a more python centered approach. I would personally prefer to do this using the python interactive window and an arcpy UpdateCursor. That is another approach you can look at once you figure out the Field Calculator portion.

answered Feb 17, 2015 at 18:44
8
  • Nice, but I think you mean: return resultList[0] Commented Feb 18, 2015 at 0:39
  • Thanks very much for your help. I've managed to get it running without errors but it doesn't seem to be working yet. It either leaves the MainFailing field blank (if I have 'return resultList[0]' or just populates it with 0s if I have 'return resultList[1]'. I'll post a copy of what I've done in a new answer... Commented Feb 18, 2015 at 10:47
  • @phloem.. thanks for the catch.. I edited my answer. Commented Feb 18, 2015 at 13:16
  • @Vanessa ... What kind of values are you using for the other fields? Are they strings, integers, floating point, etc? I set it up for comparing numbers. If you have string fields (check the field type), then it will not behave correctly. Commented Feb 18, 2015 at 13:17
  • They're all short integer except for the MainFailing column which I set to text Commented Feb 18, 2015 at 14:00

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.