Coverage for python/lsst/sims/maf/slicers/oneDSlicer.py : 11%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1# oneDSlicer - slices based on values in one data column in simData.
3import numpy as np
4from functools import wraps
5import warnings
6from lsst.sims.maf.utils import optimalBins
7from lsst.sims.maf.stackers import ColInfo
8from lsst.sims.maf.plots.onedPlotters import OneDBinnedData
10from .baseSlicer import BaseSlicer
12__all__ = ['OneDSlicer']
14class OneDSlicer(BaseSlicer):
15 """oneD Slicer."""
16 def __init__(self, sliceColName=None, sliceColUnits=None,
17 bins=None, binMin=None, binMax=None, binsize=None,
18 verbose=True, badval=0):
19 """
20 'sliceColName' is the name of the data column to use for slicing.
21 'sliceColUnits' lets the user set the units (for plotting purposes) of the slice column.
22 'bins' can be a numpy array with the binpoints for sliceCol or a single integer value
23 (if a single value, this will be used as the number of bins, together with data min/max or binMin/Max),
24 as in numpy's histogram function.
25 If 'binsize' is used, this will override the bins value and will be used together with the data min/max
26 or binMin/Max to set the binpoint values.
28 Bins work like numpy histogram bins: the last 'bin' value is end value of last bin;
29 all bins except for last bin are half-open ([a, b>), the last one is ([a, b]).
30 """
31 super(OneDSlicer, self).__init__(verbose=verbose, badval=badval)
32 self.sliceColName = sliceColName
33 self.columnsNeeded = [sliceColName]
34 self.bins = bins
35 self.binMin = binMin
36 self.binMax = binMax
37 self.binsize = binsize
38 if sliceColUnits is None:
39 co = ColInfo()
40 self.sliceColUnits = co.getUnits(self.sliceColName)
41 else:
42 self.sliceColUnits = sliceColUnits
43 self.slicer_init = {'sliceColName':self.sliceColName, 'sliceColUnits':sliceColUnits,
44 'badval':badval}
45 self.plotFuncs = [OneDBinnedData,]
47 def setupSlicer(self, simData, maps=None):
48 """
49 Set up bins in slicer.
50 """
51 if self.sliceColName is None:
52 raise Exception('sliceColName was not defined when slicer instantiated.')
53 sliceCol = simData[self.sliceColName]
54 # Set bin min/max values.
55 if self.binMin is None:
56 self.binMin = np.nanmin(sliceCol)
57 if self.binMax is None:
58 self.binMax = np.nanmax(sliceCol)
59 # Give warning if binMin = binMax, and do something at least slightly reasonable.
60 if self.binMin == self.binMax:
61 warnings.warn('binMin = binMax (maybe your data is single-valued?). '
62 'Increasing binMax by 1 (or 2*binsize, if binsize set).')
63 if self.binsize is not None:
64 self.binMax = self.binMax + 2 * self.binsize
65 else:
66 self.binMax = self.binMax + 1
67 # Set bins.
68 # Using binsize.
69 if self.binsize is not None:
70 # Add an extra 'bin' to the edge values of the bins (makes plots much prettier).
71 self.binMin -= self.binsize
72 self.binMax += self.binsize
73 if self.bins is not None:
74 warnings.warn('Both binsize and bins have been set; Using binsize %f only.' %(self.binsize))
75 self.bins = np.arange(self.binMin, self.binMax+self.binsize/2.0, self.binsize, 'float')
76 # Using bins value.
77 else:
78 # Bins was a sequence (np array or list)
79 if hasattr(self.bins, '__iter__'):
80 self.bins = np.sort(self.bins)
81 self.binMin = self.bins[0]
82 self.binMax = self.bins[-1]
83 # Or bins was a single value.
84 else:
85 if self.bins is None:
86 self.bins = optimalBins(sliceCol, self.binMin, self.binMax)
87 nbins = np.round(self.bins)
88 self.binsize = (self.binMax - self.binMin) / float(nbins)
89 self.bins = np.arange(self.binMin, self.binMax+self.binsize/2.0, self.binsize, 'float')
90 # Set nbins to be one less than # of bins because last binvalue is RH edge only
91 self.nslice = len(self.bins) - 1
92 self.shape = self.nslice
93 # Set slicePoint metadata.
94 self.slicePoints['sid'] = np.arange(self.nslice)
95 self.slicePoints['bins'] = self.bins
96 # Add metadata from map if needed.
97 self._runMaps(maps)
98 # Set up data slicing.
99 self.simIdxs = np.argsort(simData[self.sliceColName])
100 simFieldsSorted = np.sort(simData[self.sliceColName])
101 # "left" values are location where simdata == bin value
102 self.left = np.searchsorted(simFieldsSorted, self.bins[:-1], 'left')
103 self.left = np.concatenate((self.left, np.array([len(self.simIdxs),])))
104 # Set up _sliceSimData method for this class.
105 @wraps(self._sliceSimData)
106 def _sliceSimData(islice):
107 """Slice simData on oneD sliceCol, to return relevant indexes for slicepoint."""
108 idxs = self.simIdxs[self.left[islice]:self.left[islice+1]]
109 return {'idxs':idxs,
110 'slicePoint':{'sid':islice, 'binLeft':self.bins[islice]}}
111 setattr(self, '_sliceSimData', _sliceSimData)
113 def __eq__(self, otherSlicer):
114 """Evaluate if slicers are equivalent."""
115 result = False
116 if isinstance(otherSlicer, OneDSlicer):
117 if self.sliceColName == otherSlicer.sliceColName:
118 # If slicer restored from disk or setup, then 'bins' in slicePoints dict.
119 # This is preferred method to see if slicers are equal.
120 if ('bins' in self.slicePoints) & ('bins' in otherSlicer.slicePoints):
121 result = np.all(otherSlicer.slicePoints['bins'] == self.slicePoints['bins'])
122 # However, even before we 'setup' the slicer with data, the slicers could be equivalent.
123 else:
124 if (self.bins is not None) and (otherSlicer.bins is not None):
125 result = np.all(self.bins == otherSlicer.bins)
126 elif ((self.binsize is not None) and (self.binMin is not None) & (self.binMax is not None) and
127 (otherSlicer.binsize is not None) and (otherSlicer.binMin is not None) and (otherSlicer.binMax is not None)):
128 if ((self.binsize == otherSlicer.binsize) and
129 (self.binMin == otherSlicer.binMin) and
130 (self.binMax == otherSlicer.binMax)):
131 result = True
132 return result