Generating Labels using Significant Figures in ArcGIS

Every once in a while I have a need to report monitoring results using a specific number of significant figures.  For example, a project manager may ask me to show all results on a map with 2 significant figures. So:

0.358 would be 0.36
4.2 would be 4.2
45681 would be 46000
0.02 would be 0.020

This is always tricky, especially when the number has trailing zeros.  Increasingly, I’m using Python instead of VBScript to form label expressions in ArcGIS.  I’ve found that I can frequently do pretty cool things with the Python interpreter in the label expression builder, although sometimes I have Python code that works fine in a stand-alone script that won’t work inside the label expression.  The debugging inside the label expression dialog box is terrible, so it’s often hard to track down what’s not working when things go awry.

Over at Randle Taylor’s blog, I found a great Python function for formating a number to a specific number of significant figures.  I’ve taken Randle’s code and combined it with some ArcGIS specific label function logic.  In this particular case, I have three fields that I’m using the drive the labels:

[RESULT_VAL] is the analytical result;
[MDL] is the detection limit.  I want to use this when the sample results are below the detection limit;
[RESUT_QUA] is the field that holds lab reporting flags.

I added some additional functionality to this so that really large numbers are returned using scientific notation.  The number of significant figures to use is specified in the initial FindLabel function in the call to the Helper function (next to the last line of the FindLabel function.  The threshold for when scientific notation is used is set in the helper function (10,000). Hopefully someone finds this useful.

 

[raw]

from decimal import Decimal
import math
from math import log10, floor
def FindLabel ( [RESULT_VAL] , [MDL] ,[RESULT_QUA] ):
  if ("U" in [RESULT_QUA] ):
    dVal=[MDL]
  else: dVal=[RESULT_VAL]
  FindLabel = Helper(dVal , [RESULT_QUA]  , 3)
  return FindLabel
def to_precision(x,p):
    """
    from https://randlet.com/blog/python-significant-figures-format/
    returns a string representation of x formatted with a precision of p
    Based on the webkit javascript implementation taken from here:
    https://code.google.com/p/webkit-mirror/source/browse/JavaScriptCore/kjs/number_object.cpp
    """
    x = float(x)
    if x == 0.:
        return "0." + "0"*(p-1)
    out = []
    if x < 0:
        out.append("-")
        x = -x
    e = int(math.log10(x))
    tens = math.pow(10, e - p + 1)
    n = math.floor(x/tens)
    if n < math.pow(10, p - 1):
        e = e -1
        tens = math.pow(10, e - p+1)
        n = math.floor(x / tens)
    if abs((n + 1.) * tens - x) <= abs(n * tens -x):
        n = n + 1
    if n >= math.pow(10,p):
        n = n / 10.
        e = e + 1
    m = "%.*g" % (p, n)
    if e < -2 or e >= p:
        out.append(m[0])
        if p > 1:
            out.append(".")
            out.extend(m[1:p])
        out.append('e')
        if e > 0:
            out.append("+")
        out.append(str(e))
    elif e == (p -1):
        out.append(m)
    elif e >= 0:
        out.append(m[:e+1])
        if e+1 < len(m):
            out.append(".")
            out.extend(m[e+1:])
    else:
        out.append("0.")
        out.extend(["0"]*-(e+1))
        out.append(m)
    return "".join(out)
 
def Helper (dVal, dFlag, iSN):
  dVal = float(dVal)
  if (dVal<1):
    dVal = dVal + 0
  if (dVal>=10000):
      sFormatString = "{:." + str(iSN-1) + "E}"
      sOut = sFormatString.format(Decimal(dVal)) + dFlag
  else:
      sOut = to_precision(dVal,iSN) + dFlag
  return sOut

[/raw]

Share:

Share on facebook
Facebook
Share on twitter
Twitter
Share on pinterest
Pinterest
Share on linkedin
LinkedIn

Related Posts