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]
-
Do you have duplicate min values or "None" values in your attribute table?Aaron– Aaron ♦2015年02月17日 19:48:02 +00:00Commented 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 fieldsVanessa– Vanessa2015年02月18日 15:56:07 +00:00Commented Feb 18, 2015 at 15:56
2 Answers 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
-
1Given all the parameters are integer values, it seems to me that there'd be an error with keys not being unique.alphabetasoup– alphabetasoup2015年02月18日 20:26:34 +00:00Commented 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.recurvata– recurvata2015年02月18日 20:39:04 +00:00Commented 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'Vanessa– Vanessa2015年02月19日 15:19:23 +00:00Commented 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.recurvata– recurvata2015年02月19日 15:26:58 +00:00Commented Feb 19, 2015 at 15:26
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.
-
Nice, but I think you mean: return resultList[0]phloem– phloem2015年02月18日 00:39:25 +00:00Commented 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...Vanessa– Vanessa2015年02月18日 10:47:34 +00:00Commented Feb 18, 2015 at 10:47
-
@phloem.. thanks for the catch.. I edited my answer.Branco– Branco2015年02月18日 13:16:12 +00:00Commented 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.Branco– Branco2015年02月18日 13:17:18 +00:00Commented Feb 18, 2015 at 13:17
-
They're all short integer except for the MainFailing column which I set to textVanessa– Vanessa2015年02月18日 14:00:59 +00:00Commented Feb 18, 2015 at 14:00
Explore related questions
See similar questions with these tags.