Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

python - pretty print errorbars

I'm using python with numpy, scipy and matplotlib for data evaluation. As results I obtain averages and fitting parameters with errorbars.

I would like python to automatically pretty-print this data according to a given precision. For example:

Suppose I got the result x = 0.012345 +/- 0.000123. Is there a way to automatically format this as 1.235(12) x 10^-2 when a precision of 2 was specified. That is, counting the precision in the errorbar, rather than in the value.

Does anyone know a package that provides such functionality, or would I have to implement this myself?

Is there a way to inject this into the python string formatting mechanism? I.e. being able to write something like "%.2N" % (0.012345, 0.0000123).

I already looked through the docs of numpy and scipy and googled around, but I couldn't find anything. I think this would be a useful feature for everyone who deals with statistics.

Thanks for your help!

EDIT: As requested by Nathan Whitehead I'll give a few examples.

123 +- 1         ----precision 1----->  123(1)
123 +- 1.1       ----precision 2----->  123.0(11)
0.0123 +- 0.001  ----precision 1----->  0.012(1)
123.111 +- 0.123 ----precision 2----->  123.11(12)

The powers of ten are omitted for clarity. The number inside the parenthesis is a shorthand notation for the standard error. The last digit of the number before the parens and the last digit of the number inside the parens have to be at the same decimal power. For some reason I cannot find a good explanation of this concept online. Only thing I got is this German Wikpedia article here. However, it is a quite common and very handy notation.

EDIT2: I implemented the shorthand notation thing myself:

#!/usr/bin/env python
# *-* coding: utf-8 *-*

from math import floor, log10

# uncertainty to string
def un2str(x, xe, precision=2):
    """pretty print nominal value and uncertainty

    x  - nominal value
    xe - uncertainty
    precision - number of significant digits in uncertainty

    returns shortest string representation of `x +- xe` either as
        x.xx(ee)e+xx
    or as
        xxx.xx(ee)"""
    # base 10 exponents
    x_exp = int(floor(log10(x)))
    xe_exp = int(floor(log10(xe)))

    # uncertainty
    un_exp = xe_exp-precision+1
    un_int = round(xe*10**(-un_exp))

    # nominal value
    no_exp = un_exp
    no_int = round(x*10**(-no_exp))

    # format - nom(unc)exp
    fieldw = x_exp - no_exp
    fmt = '%%.%df' % fieldw
    result1 = (fmt + '(%.0f)e%d') % (no_int*10**(-fieldw), un_int, x_exp)

    # format - nom(unc)
    fieldw = max(0, -no_exp)
    fmt = '%%.%df' % fieldw
    result2 = (fmt + '(%.0f)') % (no_int*10**no_exp, un_int*10**max(0, un_exp))

    # return shortest representation
    if len(result2) <= len(result1):
        return result2
    else:
        return result1


if __name__ == "__main__":
    xs    = [123456, 12.34567, 0.123456, 0.001234560000, 0.0000123456]
    xes   = [   123,  0.00123, 0.000123, 0.000000012345, 0.0000001234]
    precs = [     1,        2,        3,              4,            1]

    for (x, xe, prec) in zip(xs, xes, precs):
        print '%.6e +- %.6e @%d --> %s' % (x, xe, prec, un2str(x, xe, prec))

Output:

1.234560e+05 +- 1.230000e+02 @1 --> 1.235(1)e5
1.234567e+01 +- 1.230000e-03 @2 --> 12.3457(12)
1.234560e-01 +- 1.230000e-04 @3 --> 0.123456(123)
1.234560e-03 +- 1.234500e-08 @4 --> 0.00123456000(1235)
1.234560e-05 +- 1.234000e-07 @1 --> 1.23(1)e-5
like image 736
Lemming Avatar asked Jul 12 '11 21:07

Lemming


2 Answers

For people that are still interested in this question, see the gvar library and here for an example of (at last part of) the desired behavior by the OP.

like image 53
marnix Avatar answered Oct 13 '22 10:10

marnix


since x +- y is not a standard type (it could be seen as a complex with real and imaginary as x and y i guess, but that does not simplify anything...) but you can get full control over the presentation by creating a type and overriding the string function, i.e. something like this

class Res(object):
   def __init__(self, res, delta):
     self.res = res
     self.delta = delta

   def __str__(self):
     return "%f +- %f"%(self.res,self.delta)

if __name__ == '__main__':
   x = Res(0.2710,0.001)
   print(x)
   print(" a result: %s" % x)

you could naturally do something a bit more fancy inside the __str__ function...

like image 30
bjarneh Avatar answered Oct 13 '22 09:10

bjarneh