Formatting results with significant figures

There are results, that should not be formatted with fixed decimal precision, especially when they are spread over a wide scales.
In Senaite LIMS you cannot explicitely configure significant digits for analysis results at this time.
But, you can use the feature Calculate Precision from Uncertainties.

The idea behind is, that senaite rounds the result to the decimal, which is indicated by the absolute uncertainty value of the actual result. This can be configured as a relative percent value.

So you get the following context:

  • Uncertainty value 10% will lead to 2 significant figures
  • Uncertainty value 1% will lead to 3 significant figures
  • Uncertainty value 0.1% will lead to 4 significant figures
  • etc.

For example, create an analysis service with those attributes:

  • Precision as number of decimals: 5 (don’t know if necessary)
  • Uncertainty:
    • Range Min: 0
    • Range Max: 10000000
    • Value: 1% (means 3 significant figures!)
  • Calculate Precision from Uncertainties: Yes

After using this service in analysis requests/samples this is the effect in different situations after submission of results:

  • entered result 0.012345678 formats to 0.0123
  • entered result 0.12345678 formats to 0.123
  • entered result 1.2345678 formats to 1.23
  • entered result 12.345678 formats to 12.3
  • entered result 123.45678 formats to 123

So far so good, but I’m afraid this does not work correctly onto the integer part of values:

  • entered result 1234.5678 formats to 1235, should be 1230
  • entered result 12345.678 formats to 12346, should be 12300

Nevertheless this is a kind of workaround, that works for me. I don’t know whether this interferes with other result processing, e.g. decimals, detection limits,…

IMHO in measurement and analysis this is more important than a fixed decimal precision.

I would appreciate any suggestions and ideas.

Also see example worksheet:

Our solution was to add in a significant figures calculator to the Senaite Impress publisher. This won’t change it inside the LIMS interface, but by using the python sigfig formula you can pretty it up for reporting.

round(TEST_RESULT, NUM_OF_SIGFIGS-int(floor(log10(abs(TEST_RESULT))))-1)

We modify the model.py and reportview.py files in senaite.impress directly and just git-merge updates, but you could potentially do it all inside of a custom TAL template if the Math module is available.

1 Like

Hi, @NEWAGE-Labs, charming solution indeed.
I consider using this idea in our tal report.

Does it process original or formatted result values?
Two-step formatting would increase rounding errors slightly, and could lead to some confusion, if we distinguish between formatted and published results.

This way you have a single rule for publishing results with significant figures for your lab or for the report?

Normally I would set all results to 3 significant figures, but for some tests I would prefer 2 or sometimes 4.

@NEWAGE-Labs: How do you handle integer results?

In those cases round() returns an unwanted ‘.0’:

>>> TEST_RESULT=123.456
>>> NUM_OF_SIGFIGS=3
>>> round(TEST_RESULT, NUM_OF_SIGFIGS-int(floor(log10(abs(TEST_RESULT))))-1)
123.0
>>> TEST_RESULT=123456
>>> round(TEST_RESULT, NUM_OF_SIGFIGS-int(floor(log10(abs(TEST_RESULT))))-1)
123000.0

Another problem is cutting off significant zeros.

See:

>>> NUM_OF_SIGFIGS=3
>>> TEST_RESULT=0.120034
>>> round(TEST_RESULT, NUM_OF_SIGFIGS-int(floor(log10(abs(TEST_RESULT))))-1)
0.12

Should be ‘0.120’ instead

Shame on round():

>>> round(0.120034,3)
0.12

I just tried your idea of your formula within an analysis service calculation in senaite.

round(TEST_RESULT, NUM_OF_SIGFIGS-int(floor(log10(abs(TEST_RESULT))))-1)

But it conflicts with decimal precision settings, and function abs() is not available.

(We’re still at senaite v1.3, might work better with v2.x)

Displaying binary numbers as decimal numbers is always kind of a 2-step process because, even in your Python interpreter, there is SOME kind of print function being called to process the binary number into a floating point decimal number. Even without the round function, you cannot put more than 1 trailing zero in a non-string object, nor can you remove a 0 from a Float. For example:

>>> NotAnInt = float(12)
>>> NotAnInt
12.0

>>> truncatedFloat = 12.000
>>> truncatedFloat
12.0

That function will round a value to a different value based on significant digits, but to print the value a particular way you will need string formatting of some kind. If a single test of yours regularly fluctuates above and below the 1 value, then you’ll probably need to both round and print the value separately.

There is no catch-all way to do this in python that I am aware of, but the solution we use is to convert the value to a string, and splice it accordingly depending on the significant figures. You need to check for the . character though and increase the splice by 1 if it exists.

1 Like