Search code examples
pythonesriarcmap

ArcMap Python Field Calculator does not work the same as Python


I am trying to use the python field calculator in ArcMap to do a simple calculation, where:

  • there are two input variables, the numerator and the denominator
  • if the numerator is zero a zero is returned
  • else, the numerator is divided by the denominator and multiplied by 100

The code I tried:

def getScore(num, den):
    if num == 0:
        return 0
    else:
        return (num/den) * 100

when I run the script i get no errors yet the 'else' statement is not getting returned.

there will be no zeros in the denominator, so div/0 will not be an issue. The input fields are all 'long' integers and the target field is a 'double.'

I've attached a couple of images showing a test in python where the same exact code works perfectly, as well as the the field calculator where it does not work.

enter image description here enter image description here


Solution

  • The way ArcGIS Desktop divides integers will result in an integer, so percentages will always end up as zero (e.g. 1 / 10 = 0) -- annoying, and counterintuitive, but that's what it's doing.

    ArcGIS Pro uses Python 3 and in ArcGIS Desktop, it uses Python 2. Python 2 uses integer math, meaning that dividing two integer values will always produce an integer value (3 / 2 = 1). In Python 3, dividing two integer values will produce a float (3 / 2 = 1.5).

    You can instead explicitly cast the variables as float, which will then do float division and give you a float result (1 / 10 = 0.1). The following works for me:

    def getScore(num, den):
        if num == 0:
            return 0
        else:
            return (float(num)/float(den)) * 100
    

    One observation: your conditional is basically saying "if the numerator is zero, don't bother dividing, just return zero" -- however, that's what 0 divided by anything is going to be anyway. You can skip the conditional, and the entire codeblock, and just directly calculate -- but still remember to cast the values as float first, or you'll still get a bunch of zeros :)

    float(!Healthy!) / float(!Total!)