deb-python-pint/pint/measurement.py
C.D. Clark III dcb3df3ce2 Added support for siunitx formatting.
Added support for generating siunitx commands in the __format__
functions for Quantity, Measurment, and Unit classes.

This adds a new code, 'Lx', to the formatting spec, that if present will
trigger the LaTeX siunitx formatting. All other formatting options in
the spec string are be passed through.

Currently does not accept siunit options.
2015-12-07 16:51:32 -06:00

116 lines
3.8 KiB
Python

# -*- coding: utf-8 -*-
"""
pint.measurement
~~~~~~~~~~~~~~~~
:copyright: 2013 by Pint Authors, see AUTHORS for more details.
:license: BSD, see LICENSE for more details.
"""
from __future__ import division, unicode_literals, print_function, absolute_import
from .compat import ufloat
from .formatting import _FORMATS, siunitx_format_unit
MISSING = object()
class _Measurement(object):
"""Implements a class to describe a quantity with uncertainty.
:param value: The most likely value of the measurement.
:type value: Quantity or Number
:param error: The error or uncertainty of the measurement.
:type error: Quantity or Number
"""
def __new__(cls, value, error, units=MISSING):
if units is MISSING:
try:
value, units = value.magnitude, value.units
except AttributeError:
try:
value, error, units = value.nominal_value, value.std_dev, error
except AttributeError:
units = ''
try:
error = error.to(units).magnitude
except AttributeError:
pass
inst = super(_Measurement, cls).__new__(cls, ufloat(value, error), units)
if error < 0:
raise ValueError('The magnitude of the error cannot be negative'.format(value, error))
return inst
@property
def value(self):
return self._REGISTRY.Quantity(self.magnitude.nominal_value, self.units)
@property
def error(self):
return self._REGISTRY.Quantity(self.magnitude.std_dev, self.units)
@property
def rel(self):
return float(abs(self.magnitude.std_dev / self.magnitude.nominal_value))
def __repr__(self):
return "<Measurement({0:.2f}, {1:.2f}, {2})>".format(self.magnitude.nominal_value,
self.magnitude.std_dev,
self.units)
def __str__(self):
return '{0}'.format(self)
def __format__(self, spec):
# special cases
if 'Lx' in spec: # the LaTeX siunitx code
# the uncertainties module supports formatting
# numbers in value(unc) notation (i.e. 1.23(45) instead of 1.23 +/- 0.45),
# which siunitx actually accepts as input. we just need to give the 'S'
# formatting option for the uncertainties module.
spec = spec.replace('Lx','S')
# todo: add support for extracting options
opts = 'separate-uncertainty=true'
mstr = format( self.magnitude, spec )
ustr = siunitx_format_unit(self.units)
ret = r'\SI[%s]{%s}{%s}'%( opts, mstr, ustr )
return ret
# standard cases
if 'L' in spec:
newpm = pm = r' \pm '
pars = _FORMATS['L']['parentheses_fmt']
elif 'P' in spec:
newpm = pm = '±'
pars = _FORMATS['P']['parentheses_fmt']
else:
newpm = pm = '+/-'
pars = _FORMATS['']['parentheses_fmt']
if 'C' in spec:
sp = ''
newspec = spec.replace('C', '')
pars = _FORMATS['C']['parentheses_fmt']
else:
sp = ' '
newspec = spec
if 'H' in spec:
newpm = '&plusmn;'
newspec = spec.replace('H', '')
pars = _FORMATS['H']['parentheses_fmt']
mag = format(self.magnitude, newspec).replace(pm, sp + newpm + sp)
if 'L' in newspec and 'S' in newspec:
mag = mag.replace('(', r'\left(').replace(')', r'\right)')
if 'uS' in newspec or 'ue' in newspec or 'u%' in newspec:
return mag + ' ' + format(self.units, spec)
else:
return pars.format(mag) + ' ' + format(self.units, spec)