Package reflectometry :: Package reduction :: Module limits

Source Code for Module reflectometry.reduction.limits

  1  # This program is public domain 
  2  """ 
  3  Data limits for high dynamic range data. 
  4   
  5  Limits() is a class for collecting combined limits on multiple sets of data. 
  6   
  7  limits(x,dv=0) returns floor,ceiling for a single dataset. 
  8  """ 
  9   
 10  from copy import copy 
 11  from numpy import inf 
 12   
13 -def limits(v, dv=0):
14 """ 15 Return data limits (floor, ceiling), where floor is the minimum 16 significant value (1/2-sigma away from zero) and ceiling is the 17 maximum absolute value. If dv=0, then floor is the minimum 18 non-zero absolute value. 19 """ 20 L = Limits(v,dv=dv) 21 return L.floor,L.ceiling
22
23 -class Limits(object):
24 """ 25 Collect data limits, used for selecting ranges in colour maps for example. 26 27 A Limits() object has the following attributes:: 28 29 ceiling - the maximum absolute data value 30 floor - 1/2 the min absolute value at least 1/2-sigma away from zero 31 min - the minimum data value 32 max - the maximum data value 33 34 The limits are collected by adding data sets to a limits object:: 35 36 L = Limits() 37 for f in frames: 38 L.add(f, dv=sqrt(f)) 39 40 Alternatively you can use the union operator:: 41 42 L = Limits() 43 for f in frames: 44 L |= Limits(f, dv=sqrt(f)) 45 46 The computed attributes are robust against values all identically 47 zero, returning instead a ceiling of 1 and a floor of 1/2. Other 48 situations may still cause problems such as infinities in the 49 data (infinite limits are hard to represent in a colour scale) or 50 all data being identical but non-zero (in which case floor==ceiling). 51 52 Regarding the choice of floor, the main goal of limits is to 53 avoid insignificant numbers on the log scale. The simplest algorithm 54 is to test v-dv > 0, which is to say that we are asking for 1-sigma 55 significance. However, it is useful to distinguish pixels with a 56 single count from those with zero counts on a 2-D detector, 57 but 1 +/- 1 would fail this test. Changing the test to v-dv >= 0 58 also includes points with 0 +/- 0, which we definitely want to 59 exclude. So instead we change the test to 1/2-sigma, which 60 catches 1 +/- 1 and skips 0 +/- 0. 61 """ 62 _floor = inf 63 _ceiling = -inf 64 _min = inf 65 _max = -inf
66 - def _getfloor(self):
67 return self._floor/2 if self._floor<inf else self.ceiling/2
68 - def _getceiling(self):
69 return self._ceiling if self._ceiling>0 else 1
70 - def _getmin(self):
71 return self._min if self._min < inf else self.max/2
72 - def _getmax(self):
73 return self._max if self._max > -inf else 1
74 floor = property(_getfloor) 75 ceiling = property(_getceiling) 76 min = property(_getmin) 77 max = property(_getmax) 78
79 - def __init__(self, *args, **kw):
80 if len(args) == 1: 81 self.add(*args,**kw) 82 elif len(args) > 1: 83 raise TypeError, "Limits() tokes 0 or 1 argument"
84
85 - def add(self, v, dv=0):
86 v = numpy.array(v) 87 ceiling = abs(v).max() 88 if ceiling > self._ceiling: self._ceiling = ceiling 89 90 # Protect against no values being significant 91 nz = v[abs(v)-dv/2>0] 92 if len(nz) > 0: 93 floor = abs(nz).min() 94 if floor < self._floor: self._floor = floor 95 96 min = v.min() 97 max = v.max() 98 if min < self._min: self._min = min 99 if max > self._max: self._max = max
100
101 - def __ior__(self, L):
102 if L._ceiling > self._ceiling: self._ceiling = L._ceiling 103 if L._floor < self.floor: self._floor = L._floor 104 if L._max > self._max: self._max = L._max 105 if L._min < self._min: self._min = L._min
106
107 - def __or__(self, L):
108 retval = copy(self) 109 retval |= L 110 return retval
111