Index: sodar/trunk/sodar/__init__.py =================================================================== --- sodar/trunk/sodar/__init.py__ (revision 59) +++ sodar/trunk/sodar/__init__.py (revision 72) @@ -5,3 +5,3 @@ """ -__all__ = ['data'] +__all__ = ['rawData','processedData'] Index: sodar/trunk/sodar/processedData.py =================================================================== --- (revision ) +++ sodar/trunk/sodar/processedData.py (revision 72) @@ -1,0 +1,147 @@ +#!/usr/bin/python +""" +Classes to handle processed sodar data samples. + +""" + +__author__ = 'Chris Calloway' +__email__ = 'cbc@unc.edu' +__copyright__ = 'Copyright 2007 UNC-CH Department of Marine Science' +__license__ = 'GPL2' + +import rawData +import numpy as n +import datetime + +class ProcessedData(list): + + """Processed daily sodar file data.""" + + def __init__(self, data): + """Prepare raw sodar daily data for analysis.""" + super(ProcessedData, self).__init__() + self.data = data + self._normalize() + + def _normalize(self): + """Clean up data for analysis.""" + self._copy() + self._convert() + self._stamp() + self._sampleInterval() + # correct for missing times + self._minimumAltitude() + self._maximumAltitude() + # compute number of altitudes + # compute altitude interval + # correct for missing altitudes + # mark maximum altitude with good values for each sample + # mark minimum altitude with invalid values for each sample + # convert direction to radians + # compute u,v,c components + # compute colorspecs + # compute plotting parameters + + def _copy(self): + """Create a deep copy as a list of Sample copies.""" + self.extend([sample._copy() for sample in self.data]) + + def _convert(self): + """Convert to numbers and correct for invalid values.""" + INVALID = "-9999" + for sample in self: + for altitude in sample['body']: + for key,value in altitude.items(): + try: + if value == INVALID: + raise ValueError + altitude[key] = float(value) + except (ValueError, TypeError, KeyError): + altitude[key] = n.NaN + for key,value in sample['header'].items(): + try: + if value == INVALID: + raise ValueError + sample['header'][key] = int(value) + except (ValueError, TypeError, KeyError): + sample['header'][key] = n.NaN + + def _stamp(self): + """Add a datetime stamp to each sample.""" + for sample in self: + try: + header = sample['header'] + sample['stamp'] = datetime.datetime(header['YEAR'], + header['MONTH'], + header['DAY'], + header['HOUR'], + header['MIN']) + except (KeyError, TypeError): + sample['stamp'] = datetime.datetime.min + + def _sampleInterval(self): + """Add a sample interval attribute.""" + intervals = zip([sample['stamp'] for sample in self[:-1]], + [sample['stamp'] for sample in self[1:]]) + intervals = [interval[1] - interval[0] for interval in intervals] + accumulator = {} + for interval in intervals: + if interval in accumulator: + accumulator[interval] += 1 + else: + accumulator[interval] = 1 + maxVotes = max(accumulator.values()) + for key,value in accumulator.items(): + if value == maxVotes: + self.sampleInterval = key + break + self.sampleInterval = getattr(self, + 'sampleInterval', + datetime.timedelta.resolution) + + def _minimumAltitude(self): + """Add an overall minimum altitude attribute.""" + accumulator = {} + for sample in self: + minalt = sample['body'][0]['ALT'] + sample['header']['minalt'] = minalt + if minalt is not n.NaN: + if minalt in accumulator: + accumulator[minalt] += 1 + else: + accumulator[minalt] = 1 + maxVotes = max(accumulator.values()) + for key,value in accumulator.items(): + if value == maxVotes: + self.minimumAltitude = key + break + self.minimumAltitude = getattr(self, + 'minimumAltitude', + n.NaN) + + + def _maximumAltitude(self): + """Add an overall maximum altitude attribute.""" + accumulator = {} + for sample in self: + maxalt = sample['body'][-1]['ALT'] + sample['header']['maxalt'] = maxalt + if maxalt is not n.NaN: + if maxalt in accumulator: + accumulator[maxalt] += 1 + else: + accumulator[maxalt] = 1 + maxVotes = max(accumulator.values()) + for key,value in accumulator.items(): + if value == maxVotes: + self.maximumAltitude = key + break + self.maximumAltitude = getattr(self, + 'maximumAltitude', + n.NaN) +def _main(): + """Process as script from command line.""" + pass + +if __name__ == "__main__": + _main() Index: sodar/trunk/sodar/rawData.py =================================================================== --- sodar/trunk/sodar/rawData.py (revision 71) +++ sodar/trunk/sodar/rawData.py (revision 72) @@ -62,6 +62,4 @@ import re -import numpy as n -import datetime class RawData(list): @@ -79,5 +77,4 @@ [sample.strip() for sample in data.split('$')] if sample.strip()]) - self._normalize() def __getitem__(self, index): @@ -112,120 +109,4 @@ raise IndexError('RawData index out of range') - def _normalize(self): - """Clean up data for analysis.""" - self._copy() - self._convert() - self._stamp() - self._sampleInterval() - # correct for missing times - self._minimumAltitude() - self._maximumAltitude() - # compute number of altitudes - # compute altitude interval - # correct for missing altitudes - # mark maximum altitude with good values for each sample - # mark minimum altitude with invalid values for each sample - # convert direction to radians - # compute u,v,c components - # compute colorspecs - # compute plotting parameters - - def _copy(self): - """Create a deep copy as a list of Sample copies.""" - self.samples = [sample._copy() for sample in self] - - def _convert(self): - """Convert to numbers and correct for invalid values.""" - INVALID = "-9999" - for sample in self.samples: - for altitude in sample['body']: - for key,value in altitude.items(): - try: - if value == INVALID: - raise ValueError - altitude[key] = float(value) - except (ValueError, TypeError, KeyError): - altitude[key] = n.NaN - for key,value in sample['header'].items(): - try: - if value == INVALID: - raise ValueError - sample['header'][key] = int(value) - except (ValueError, TypeError, KeyError): - sample['header'][key] = n.NaN - - def _stamp(self): - """Add a datetime stamp to each sample.""" - for sample in self.samples: - try: - header = sample['header'] - sample['stamp'] = datetime.datetime(header['YEAR'], - header['MONTH'], - header['DAY'], - header['HOUR'], - header['MIN']) - except (KeyError, TypeError): - sample['stamp'] = datetime.datetime.min - - def _sampleInterval(self): - """Add a sample interval attribute.""" - intervals = zip([sample['stamp'] for sample in self.samples[:-1]], - [sample['stamp'] for sample in self.samples[1:]]) - intervals = [interval[1] - interval[0] for interval in intervals] - accumulator = {} - for interval in intervals: - if interval in accumulator: - accumulator[interval] += 1 - else: - accumulator[interval] = 1 - maxVotes = max(accumulator.values()) - for key,value in accumulator.items(): - if value == maxVotes: - self.sampleInterval = key - break - self.sampleInterval = getattr(self, - 'sampleInterval', - datetime.timedelta.resolution) - - def _minimumAltitude(self): - """Add an overall minimum altitude attribute.""" - accumulator = {} - for sample in self.samples: - minalt = sample['body'][0]['ALT'] - sample['header']['minalt'] = minalt - if minalt is not n.NaN: - if minalt in accumulator: - accumulator[minalt] += 1 - else: - accumulator[minalt] = 1 - maxVotes = max(accumulator.values()) - for key,value in accumulator.items(): - if value == maxVotes: - self.minimumAltitude = key - break - self.minimumAltitude = getattr(self, - 'minimumAltitude', - n.NaN) - - - def _maximumAltitude(self): - """Add an overall maximum altitude attribute.""" - accumulator = {} - for sample in self.samples: - maxalt = sample['body'][-1]['ALT'] - sample['header']['maxalt'] = maxalt - if maxalt is not n.NaN: - if maxalt in accumulator: - accumulator[maxalt] += 1 - else: - accumulator[maxalt] = 1 - maxVotes = max(accumulator.values()) - for key,value in accumulator.items(): - if value == maxVotes: - self.maximumAltitude = key - break - self.maximumAltitude = getattr(self, - 'maximumAltitude', - n.NaN) class Sample(object):