[Scipy-svn] r2754 - in trunk/Lib/sandbox/timeseries: . tests

scipy-svn at scipy.org scipy-svn at scipy.org
Thu Feb 22 22:17:04 EST 2007


Author: pierregm
Date: 2007-02-22 21:16:56 -0600 (Thu, 22 Feb 2007)
New Revision: 2754

Added:
   trunk/Lib/sandbox/timeseries/.project
Modified:
   trunk/Lib/sandbox/timeseries/tdates.py
   trunk/Lib/sandbox/timeseries/tests/test_dates.py
   trunk/Lib/sandbox/timeseries/tests/test_multitimeseries.py
   trunk/Lib/sandbox/timeseries/tests/test_timeseries.py
   trunk/Lib/sandbox/timeseries/tmulti.py
   trunk/Lib/sandbox/timeseries/tseries.py
Log:
tdates : fixed a pb in DateArray where the frequence was not properly updated 
       : optimization of DateArray.__new__
tseries: optimization of TimeSeries.__getitem__
       : fixed a pb w/ _tsarraymethod when ondates=True
       : modified __check_index to allow access to rows/columns of a reshaped 1d series.
       : add transpose
tmulti : update to take into account the modidications of mrecords


Added: trunk/Lib/sandbox/timeseries/.project
===================================================================
--- trunk/Lib/sandbox/timeseries/.project	2007-02-22 21:00:31 UTC (rev 2753)
+++ trunk/Lib/sandbox/timeseries/.project	2007-02-23 03:16:56 UTC (rev 2754)
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>scipy_svn_timeseries</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.python.pydev.PyDevBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.python.pydev.pythonNature</nature>
+	</natures>
+</projectDescription>

Modified: trunk/Lib/sandbox/timeseries/tdates.py
===================================================================
--- trunk/Lib/sandbox/timeseries/tdates.py	2007-02-22 21:00:31 UTC (rev 2753)
+++ trunk/Lib/sandbox/timeseries/tdates.py	2007-02-23 03:16:56 UTC (rev 2754)
@@ -25,7 +25,6 @@
 from numpy.core.numerictypes import generic
 
 import maskedarray as MA
-#reload(MA)
 
 import mx.DateTime as mxD
 from mx.DateTime.Parser import DateFromString as mxDFromString
@@ -40,7 +39,8 @@
 'DateError', 'ArithmeticDateError', 'FrequencyDateError','InsufficientDateError',
 'datearray','date_array', 'date_array_fromlist', 'date_array_fromrange',
 'day_of_week','day_of_year','day','month','quarter','year','hour','minute','second',
-'truncateDate','monthToQuarter','thisday','today','prevbusday','asfreq'
+'truncateDate','monthToQuarter','thisday','today','prevbusday','asfreq',
+'period_break'
            ]
 
 
@@ -224,6 +224,9 @@
                                                     hour, minute, second))
         self.value = self.__value()
 
+    def __getitem__(self, indx):
+        return self
+
     @property
     def day(self):          
         "Returns the day of month."
@@ -385,6 +388,7 @@
         # A date is always valid by itself, but we need the object to support the function
         # when we're working with singletons.
         return True
+    #......................................................
         
     
 #####---------------------------------------------------------------------------
@@ -488,6 +492,52 @@
                 'equal','not_equal','less','less_equal', 'greater','greater_equal',
                 'isnan']
 
+class _datearithmetics(object):
+    """Defines a wrapper for arithmetic methods.
+Instead of directly calling a ufunc, the corresponding method of  the `array._data` 
+object is called instead.
+If `asdates` is True, a DateArray object is returned , else a regular ndarray
+is returned.
+    """
+    def __init__ (self, methodname, asdates=True):
+        """
+:Parameters:
+    - `methodname` (String) : Method name.
+        """
+        self.methodname = methodname
+        self._asdates = asdates
+        self.__doc__ = getattr(methodname, '__doc__')
+        self.obj = None
+    #
+    def __get__(self, obj, objtype=None):
+        self.obj = obj
+        return self
+    #
+    def __call__ (self, other, *args, **kwargs):
+        "Execute the call behavior."
+        instance = self.obj
+        freq = instance.freq
+        if 'context' not in kwargs:
+            kwargs['context'] = 'DateOK'
+        method = getattr(super(DateArray,instance), self.methodname)
+        if isinstance(other, DateArray):
+            if other.freq != freq:
+                raise FrequencyDateError("Cannot operate on dates", \
+                                         freq, other.freq)
+        elif isinstance(other, Date):
+            if other.freq != freq:
+                raise FrequencyDateError("Cannot operate on dates", \
+                                         freq, other.freq)
+            other = other.value
+        elif isinstance(other, ndarray):
+            if other.dtype.kind not in ['i','f']:
+                raise ArithmeticDateError
+        if self._asdates:
+            return instance.__class__(method(other, *args), 
+                                      freq=freq)
+        else:
+            return method(other, *args)
+
 class DateArray(ndarray):  
     """Defines a ndarray of dates, as ordinals.
     
@@ -506,12 +556,14 @@
         if freq is None:
             _freq = getattr(dates, 'freq', -9999)
         else:
-            _freq = freq
-        cls._defaultfreq = corelib.check_freq(freq)
+            _freq = corelib.check_freq(freq)
+        cls._defaultfreq = corelib.check_freq(_freq)
         # Get the dates ..........
-        _dates = numeric.array(dates, copy=copy, dtype=int_, subok=1).view(cls)
+        _dates = numeric.array(dates, copy=copy, dtype=int_, subok=1)
         if _dates.ndim == 0:
             _dates.shape = (1,)
+        _dates = _dates.view(cls)
+        _dates.freq = _freq
         return _dates
     
     def __array_wrap__(self, obj, context=None):
@@ -551,6 +603,17 @@
     def __repr__(self):
         return ndarray.__repr__(self)
     #......................................................
+    __add__ = _datearithmetics('__add__', asdates=True)
+    __radd__ = _datearithmetics('__add__', asdates=True)
+    __sub__ = _datearithmetics('__sub__', asdates=True)
+    __rsub__ = _datearithmetics('__rsub__', asdates=True)
+    __le__ = _datearithmetics('__le__', asdates=False)
+    __lt__ = _datearithmetics('__lt__', asdates=False)
+    __ge__ = _datearithmetics('__ge__', asdates=False)
+    __gt__ = _datearithmetics('__gt__', asdates=False)
+    __eq__ = _datearithmetics('__eq__', asdates=False)
+    __ne__ = _datearithmetics('__ne__', asdates=False)
+    #......................................................
     @property
     def day(self):          
         "Returns the day of month."
@@ -717,64 +780,10 @@
         "Returns whether the DateArray is valid: no missing/duplicated dates."
         return  (self.isfull() and not self.has_duplicated_dates())
     #......................................................
-class _datearithmetics(object):
-    """Defines a wrapper for arithmetic methods.
-Instead of directly calling a ufunc, the corresponding method of  the `array._data` 
-object is called instead.
-If `asdates` is True, a DateArray object is returned , else a regular ndarray
-is returned.
-    """
-    def __init__ (self, methodname, asdates=True):
-        """
-:Parameters:
-    - `methodname` (String) : Method name.
-        """
-        self.methodname = methodname
-        self._asdates = asdates
-        self.__doc__ = getattr(methodname, '__doc__')
-        self.obj = None
-    #
-    def __get__(self, obj, objtype=None):
-        self.obj = obj
-        return self
-    #
-    def __call__ (self, other, *args, **kwargs):
-        "Execute the call behavior."
-        instance = self.obj
-        freq = instance.freq
-        if 'context' not in kwargs:
-            kwargs['context'] = 'DateOK'
-        method = getattr(super(DateArray,instance), self.methodname)
-        if isinstance(other, DateArray):
-            if other.freq != freq:
-                raise FrequencyDateError("Cannot operate on dates", \
-                                         freq, other.freq)
-#            other = 
-        elif isinstance(other, Date):
-            if other.freq != freq:
-                raise FrequencyDateError("Cannot operate on dates", \
-                                         freq, other.freq)
-            other = other.value
-        elif isinstance(other, ndarray):
-            if other.dtype.kind not in ['i','f']:
-                raise ArithmeticDateError
-        if self._asdates:
-            return instance.__class__(method(other, *args), 
-                                      freq=freq)
-        else:
-            return method(other, *args)
+
 #............................
-DateArray.__add__ = _datearithmetics('__add__', asdates=True)
-DateArray.__radd__ = _datearithmetics('__add__', asdates=True)
-DateArray.__sub__ = _datearithmetics('__sub__', asdates=True)
-DateArray.__rsub__ = _datearithmetics('__rsub__', asdates=True)
-DateArray.__le__ = _datearithmetics('__le__', asdates=False)
-DateArray.__lt__ = _datearithmetics('__lt__', asdates=False)
-DateArray.__ge__ = _datearithmetics('__ge__', asdates=False)
-DateArray.__gt__ = _datearithmetics('__gt__', asdates=False)
-DateArray.__eq__ = _datearithmetics('__eq__', asdates=False)
-DateArray.__ne__ = _datearithmetics('__ne__', asdates=False)
 
+
 #####---------------------------------------------------------------------------
 #---- --- DateArray functions ---
 #####---------------------------------------------------------------------------  
@@ -892,6 +901,8 @@
             start_date = dlist
     # Case #2: we have a starting date ..........
     if start_date is None:
+        if length == 0:
+            return DateArray([], freq=freq)
         raise InsufficientDateError
     if not isDate(start_date):
         dmsg = "Starting date should be a valid Date instance! "
@@ -905,7 +916,7 @@
     else:
         if not isDate(end_date):
             raise DateError, "Ending date should be a valid Date instance!"
-        length = end_date - start_date
+        length = int(end_date - start_date)
         if include_last:
             length += 1
 #    dlist = [(start_date+i).value for i in range(length)]
@@ -968,6 +979,20 @@
 second = _frommethod('second')
 
 
+def period_break(dates, period):
+    """Returns the indices where the given period changes.
+
+:Parameters:
+    dates : DateArray
+        Array of dates to monitor.
+    period : string
+        Name of the period to monitor.
+    """
+    current = getattr(dates, period)
+    previous = getattr(dates-1, period)
+    return (current - previous).nonzero()[0]
+
+
 ################################################################################
 
 if __name__ == '__main__':
@@ -981,4 +1006,17 @@
         # Using a date
         lag = mdates.find_dates(mdates[0])
         print mdates[lag]
-        assert_equal(mdates[lag], mdates[0])
\ No newline at end of file
+        assert_equal(mdates[lag], mdates[0])
+    if 1:
+        hodie = today('D')
+        D = DateArray(today('D'))
+        assert_equal(D.freq, 6000)
+    
+    if 1:
+        freqs = [x[0] for x in corelib.freq_dict.values() if x[0] != 'U']
+        print freqs
+        for f in freqs:
+            print f
+            today = thisday(f)
+            assert(Date(freq=f, value=today.value) == today)
+    
\ No newline at end of file

Modified: trunk/Lib/sandbox/timeseries/tests/test_dates.py
===================================================================
--- trunk/Lib/sandbox/timeseries/tests/test_dates.py	2007-02-22 21:00:31 UTC (rev 2753)
+++ trunk/Lib/sandbox/timeseries/tests/test_dates.py	2007-02-23 03:16:56 UTC (rev 2754)
@@ -26,15 +26,12 @@
 from maskedarray.testutils import assert_equal, assert_array_equal
 
 import timeseries.tdates as tdates
-reload(tdates)
 #from timeseries import tdates
-##reload(tdates)
 #from timeseries.tdates import date_array_fromlist, Date, DateArray, date_array,\
 #    mxDFromString, today
 from timeseries.tdates import *
 from timeseries.tdates import mxDFromString
 from timeseries import tcore
-#reload(tcore)
 
 
 class test_creation(NumpyTestCase):

Modified: trunk/Lib/sandbox/timeseries/tests/test_multitimeseries.py
===================================================================
--- trunk/Lib/sandbox/timeseries/tests/test_multitimeseries.py	2007-02-22 21:00:31 UTC (rev 2753)
+++ trunk/Lib/sandbox/timeseries/tests/test_multitimeseries.py	2007-02-23 03:16:56 UTC (rev 2754)
@@ -18,16 +18,15 @@
 from numpy.testing.utils import build_err_msg
 
 import maskedarray.testutils
-#reload(maskedarray.testutils)
 from maskedarray.testutils import assert_equal, assert_array_equal
 
 import maskedarray.core as MA
 import maskedarray.mrecords as MR
+from maskedarray.mrecords import addfield
 
 from maskedarray.core import getmaskarray, nomask, masked_array
 
 from timeseries import tmulti
-reload(tmulti)
 from timeseries.tmulti import MultiTimeSeries, TimeSeries,\
     fromarrays, fromtextfile, fromrecords, \
     date_array, time_series
@@ -63,11 +62,14 @@
         assert_equal(mts['f0']._mask, m)
         #
         assert(isinstance(mts[0], MultiTimeSeries))
-        assert_equal(mts[0]._data, mrec[0])
-        assert_equal(mts[0]._dates, dates[0])       
+        assert_equal(mts._data[0], mrec[0])
+        # We can't use assert_equal here, as it tries to convert the tuple into a singleton
+        assert(mts[0]._data.view(N.ndarray) == mrec[0])
+        assert_equal(mts._dates[0], dates[0])  
+        assert_equal(mts[0]._dates, dates[0])
         #
         assert(isinstance(mts['2007-01'], MultiTimeSeries))
-        assert_equal(mts['2007-01']._data, mrec[0])
+        assert(mts['2007-01']._data == mrec[0])
         assert_equal(mts['2007-01']._dates, dates[0])       
         #
         assert_equal(mts.f0, time_series(d, dates=dates, mask=m))
@@ -131,7 +133,7 @@
     def test_addfield(self):
         "Tests addfield"
         [d, m, mrec, dlist, dates, ts, mts] = self.data
-        mts.addfield(masked_array(d+10, mask=m[::-1]))
+        mts = addfield(mts, masked_array(d+10, mask=m[::-1]))
         assert_equal(mts.f2, d+10)
         assert_equal(mts.f2._mask, m[::-1])            
 

Modified: trunk/Lib/sandbox/timeseries/tests/test_timeseries.py
===================================================================
--- trunk/Lib/sandbox/timeseries/tests/test_timeseries.py	2007-02-22 21:00:31 UTC (rev 2753)
+++ trunk/Lib/sandbox/timeseries/tests/test_timeseries.py	2007-02-23 03:16:56 UTC (rev 2754)
@@ -26,7 +26,6 @@
 from maskedarray.testutils import assert_equal, assert_array_equal
 
 from timeseries import tseries
-#reload(tseries)
 from timeseries.tseries import Date, date_array_fromlist, date_array, thisday
 from timeseries.tseries import time_series, TimeSeries, adjust_endpoints, \
     mask_period, align_series, fill_missing_dates, tsmasked, concatenate_series
@@ -263,6 +262,44 @@
         assert_equal(ser_x[:,0], time_series(a, d)) 
         assert_equal(ser_x[:,:], ser_x) 
         
+    def test_onnd(self):
+        "Tests getitem on a nD series"
+        hodie = thisday('D')
+        # Case 1D
+        series = time_series(N.arange(5), mask=[1,0,0,0,0], start_date=hodie)
+        assert_equal(series[0], 0)
+        # Case 1D + mask
+        series = time_series(N.arange(5), mask=[1,0,0,0,0], start_date=hodie)
+        assert series[0] is tsmasked
+        # Case 2D
+        series = time_series(N.arange(10).reshape(5,2), start_date=hodie)
+        assert_equal(len(series), 5)
+        assert_equal(series[0], [[0,1]])
+        assert_equal(series[0]._dates, (hodie))
+        assert_equal(series[:,0], [0,2,4,6,8])
+        assert_equal(series[:,0]._dates, series._dates)
+        # Case 2D + mask
+        series = time_series(N.arange(10).reshape(5,2), start_date=hodie,
+                             mask=[[1,1],[0,0],[0,0],[0,0],[0,0]])
+        assert_equal(len(series), 5)
+        assert_equal(series[0], [[0,1]])
+        assert_equal(series[0]._mask, [[1,1]])
+        assert_equal(series[0]._dates, (hodie))
+        assert_equal(series[:,0]._data, [0,2,4,6,8])
+        assert_equal(series[:,0]._mask, [1,0,0,0,0])
+        assert_equal(series[:,0]._dates, series._dates)       
+        # Case 3D
+        series = time_series(N.arange(30).reshape(5,3,2), start_date=hodie)
+        x = series[0]
+        assert_equal(len(series), 5)
+        assert_equal(series[0], [[[0,1],[2,3],[4,5]]])
+        assert_equal(series[0]._dates, (hodie))
+        assert_equal(series[:,0], series._data[:,0])
+        assert_equal(series[:,0]._dates, series._dates)
+        x = series[:,:,0]
+        assert_equal(series[:,:,0], series._data[:,:,0])
+        assert_equal(series[:,:,0]._dates, series._dates)
+        
 class test_functions(NumpyTestCase):
     "Some getitem tests"
     def __init__(self, *args, **kwds):

Modified: trunk/Lib/sandbox/timeseries/tmulti.py
===================================================================
--- trunk/Lib/sandbox/timeseries/tmulti.py	2007-02-22 21:00:31 UTC (rev 2753)
+++ trunk/Lib/sandbox/timeseries/tmulti.py	2007-02-23 03:16:56 UTC (rev 2754)
@@ -27,8 +27,6 @@
 from numpy.core.records import fromarrays as recfromarrays
 
 import maskedarray as MA
-#import numpy.core.ma as MA
-#reload(MA)
 #MaskedArray = MA.MaskedArray
 from maskedarray.core import MaskedArray, MAError, default_fill_value, \
     masked_print_option
@@ -36,7 +34,6 @@
     make_mask_none, mask_or, masked_array, filled
 
 import maskedarray.mrecords as MR
-#reload(MR)
 from maskedarray.mrecords import _checknames, _guessvartypes, openfile,\
     MaskedRecords
 from maskedarray.mrecords import fromrecords as mrecfromrecords
@@ -74,7 +71,6 @@
         formats += ','
     return formats[:-1]    
 
-
     
 
 
@@ -102,12 +98,12 @@
                          byteorder=byteorder, aligned=aligned)
         #
         if isinstance(data, MultiTimeSeries):
-            cls._defaultfieldmask = data._series._fieldmask
-            cls._defaulthardmask = data._series._hardmask | hard_mask
-            cls._fill_value = data._series._fill_value
-            return data._data.view(cls)
+#            if copy:
+#                data = data.copy()
+            data._hardmask = data._hardmask | hard_mask
+            return data
         # .......................................
-        _data = MaskedRecords(data, mask=mask, dtype=dtype, **mroptions)
+        _data = MaskedRecords(data, mask=mask, dtype=dtype, **mroptions).view(cls)
         if dates is None:
             length = _getdatalength(data)
             newdates = date_array(start_date=start_date, length=length,
@@ -116,72 +112,67 @@
             newdates = date_array(dlist=dates, freq=freq)
         else:
             newdates = dates
-        cls._defaultdates = newdates    
-        cls._defaultobserved = observed  
+        _data._dates = newdates    
+        _data._observed = observed  
         cls._defaultfieldmask = _data._fieldmask
         #
-        return _data.view(cls)
-#    
-#        #..................................
-#    def __array_wrap__(self, obj, context=None):
-#        """Special hook for ufuncs.
-#Wraps the numpy array and sets the mask according to context.
-#        """
-##        mclass = self.__class__
-#        #..........
-#        if context is None:
-##            return mclass(obj, mask=self._mask, copy=False)
-#            return MaskedArray(obj, mask=self._mask, copy=False,
-#                               dtype=obj.dtype,
-#                               fill_value=self.fill_value, )
-#        #..........
-#        (func, args) = context[:2]
-# 
-##        return mclass(obj, copy=False, mask=m)
-#        return MultiTimeSeries(obj, copy=False, mask=m,)
-##                           dtype=obj.dtype, fill_value=self._fill_value)        
-    def __array_finalize__(self,obj):
-        if isinstance(obj, MultiTimeSeries):
-            self.__dict__.update(_dates=obj._dates,
-                                 _series=obj._series,
-                                 _data=obj._series._data,
-                                 _fieldmask=obj._series._fieldmask,
-                                 _hardmask=obj._series._hardmask,
-                                 _fill_value=obj._fill_value                                 
+        return _data
+
+    def __array_finalize__(self,obj):        
+        if isinstance(obj, (MaskedRecords)):
+            self.__dict__.update(_fieldmask=obj._fieldmask,
+                                 _hardmask=obj._hardmask,
+                                 _fill_value=obj._fill_value,                                 
                                  )
+            if isinstance(obj, MultiTimeSeries):
+                self.__dict__.update(observed=obj.observed,
+                                     _dates=obj._dates)
+            else:
+                self.__dict__.update(observed=None,
+                                     _dates=[])
         else:     
-            self.__dict__.update(_data = obj.view(recarray),
-                                 _dates = self._defaultdates,
-                                 _series = MaskedRecords(obj, dtype=obj.dtype),
-                                 _fieldmask = self._defaultfieldmask,
-                                 _hardmask = self._defaulthardmask,
-                                 fill_value = self._fill_value
+            self.__dict__.update(_dates = [],
+                                 observed=None,
+                                 _fieldmask = nomask,
+                                 _hardmask = False,
+                                 fill_value = None
                                 )
-            MultiTimeSeries._defaultfieldmask = nomask
-            MultiTimeSeries._defaulthardmask = False
         return
+    
+        
+    def _getdata(self):
+        "Returns the data as a recarray."
+        return self.view(recarray)
+    _data = property(fget=_getdata)
+    
+    def _getseries(self):
+        "Returns the data as a MaskedRecord array."
+        return self.view(MaskedRecords)
+    _series = property(fget=_getseries)
+    
     #......................................................
     def __getattribute__(self, attr):
-        try:
-            # Returns a generic attribute
-            return object.__getattribute__(self,attr)
-        except AttributeError: 
-            # OK, so attr must be a field name
-            pass
-        # Get the list of fields ......
-        _names = self.dtype.names
-        _local = self.__dict__
-        _mask = _local['_fieldmask']
-        if attr in _names:
-            _data = _local['_data']
-            obj = numeric.asarray(_data.__getattribute__(attr)).view(MaskedArray)
-            obj._mask = make_mask(_mask.__getattribute__(attr))
-            return obj
-        elif attr == '_mask':
-            if self.size > 1:
-                return _mask.view((bool_, len(self.dtype))).all(1)
-            return _mask.view((bool_, len(self.dtype)))
-        raise AttributeError,"No attribute '%s' !" % attr
+        return MaskedRecords.__getattribute__(self,attr)
+#        try:
+#            # Returns a generic attribute
+#            return object.__getattribute__(self,attr)
+#        except AttributeError: 
+#            # OK, so attr must be a field name
+#            pass
+#        # Get the list of fields ......
+#        _names = self.dtype.names
+#        _local = self.__dict__
+#        _mask = _local['_fieldmask']
+#        if attr in _names:
+#            _data = self._data
+#            obj = numeric.asarray(_data.__getattribute__(attr)).view(MaskedArray)
+#            obj._mask = make_mask(_mask.__getattribute__(attr))
+#            return obj
+#        elif attr == '_mask':
+#            if self.size > 1:
+#                return _mask.view((bool_, len(self.dtype))).all(1)
+#            return _mask.view((bool_, len(self.dtype)))
+#        raise AttributeError,"No attribute '%s' !" % attr
             
     def __setattr__(self, attr, val):
         newattr = attr not in self.__dict__
@@ -195,7 +186,7 @@
                 exctype, value = sys.exc_info()[:2]
                 raise exctype, value
         else:
-            if attr not in list(self.dtype.names) + ['_mask']:
+            if attr not in list(self.dtype.names) + ['_dates','_mask']:
                 return ret
             if newattr:         # We just added this one
                 try:            #  or this setattr worked on an internal
@@ -234,59 +225,36 @@
         _localdict = self.__dict__
         # We want a field ........
         if indx in self.dtype.names:
-            obj = _localdict['_series'][indx].view(TimeSeries)
+            obj = self._data[indx].view(TimeSeries)
+            obj._dates = _localdict['_dates']
             obj._mask = make_mask(_localdict['_fieldmask'][indx])
             return obj
         # We want some elements ..
-        (sindx, dindx) = super(MultiTimeSeries, self)._TimeSeries__checkindex(indx)
-        return MultiTimeSeries(_localdict['_series'][sindx], 
-                               dates=_localdict['_dates'][dindx],
-#                              mask=_localdict['_fieldmask'][indx],
-                               dtype=self.dtype)
+        (sindx, dindx) = self._TimeSeries__checkindex(indx)
+#        obj = numeric.array(self._data[sindx],
+#                            copy=False, subok=True).view(type(self))
+        obj = numeric.array(self._data[sindx], copy=False, subok=True)
+        obj = obj.view(type(self))
+        obj.__dict__.update(_dates=_localdict['_dates'][dindx],
+                            _fieldmask=_localdict['_fieldmask'][sindx],
+                            _fill_value=_localdict['_fill_value'])
+        return obj
         
     def __getslice__(self, i, j):
         """Returns the slice described by [i,j]."""
         _localdict = self.__dict__
         (si, di) = super(MultiTimeSeries, self)._TimeSeries__checkindex(i)
         (sj, dj) = super(MultiTimeSeries, self)._TimeSeries__checkindex(j)
-        return MultiTimeSeries(_localdict['_data'][si:sj], 
-                               mask=_localdict['_fieldmask'][si:sj],
-                               dates=_localdict['_dates'][di:dj],
-                               dtype=self.dtype)      
+        newdata = self._data[si:sj].view(type(self))
+        newdata.__dict__.update(_dates=_localdict['_dates'][di:dj],
+                                _mask=_localdict['_fieldmask'][si:sj])
+        return newdata    
         
     def __setslice__(self, i, j, value):
         """Sets the slice described by [i,j] to `value`."""
-        _localdict = self.__dict__
-        d = _localdict['_data']
-        t = _localdict['_dates']
-        m = _localdict['_fieldmask']
-        names = self.dtype.names
-        if value is masked:
-            for n in names:
-                m[i:j][n] = masked
-        elif not self._hardmask:
-            fval = filled(value)
-            mval = getmaskarray(value)
-            for n in names:
-                d[n][i:j] = fval
-                m[n][i:j] = mval
-        else:
-            mindx = getmaskarray(self)[i:j]
-            val = masked_array(value, mask=mindx, keep_mask=True)
-            valmask = getmask(value)
-            if valmask is nomask:
-                for n in names:
-                    mval = mask_or(m[n][i:j], valmask)
-                    d[n][i:j][~mval] = filled(value)
-            elif valmask.size > 1:
-                for n in names:
-                    mval = mask_or(m[n][i:j], valmask)
-                    d[n][i:j][~mval] = fval[~mval]
-                    m[n][i:j] = mask_or(m[n][i:j], mval) 
+        self.view(MaskedRecords).__setslice__(i,j,value)
+        return   
             
-        return MultiTimeSeries(d, mask=m, dates=t[i:j], dtype=self.dtype)      
-            
-        
     #......................................................
     def __str__(self):
         """x.__str__() <==> str(x)
@@ -320,25 +288,6 @@
                         fmt % ('    fill_value', self._fill_value), 
                          '               )'])
         return str("\n".join(reprstr))
-    #......................................................
-    def view(self, obj):
-        """Returns a view of the mrecarray."""
-        try:
-            if issubclass(obj, ndarray):
-                return ndarray.view(self, obj)
-        except TypeError:
-            pass
-        dtype = numeric.dtype(obj)
-        if dtype.fields is None:
-            return self.__array__().view(dtype)
-        return ndarray.view(self, obj)            
-    #............................................
-#    def harden_mask(self):
-#        "Forces the mask to hard"
-#        self._hardmask = True
-#    def soften_mask(self):
-#        "Forces the mask to soft"
-#        self._hardmask = False
     #.............................................
     def copy(self):
         "Returns a copy of the argument."
@@ -347,10 +296,8 @@
                        dates=_localdict['_dates'].copy(),
                         mask=_localdict['_fieldmask'].copy(),
                        dtype=self.dtype)
-    #.............................................
-    def addfield(self, newfield, newfieldname=None):
-        MaskedRecords.addfield(self, newfield, newfieldname)
 
+
 #####---------------------------------------------------------------------------
 #---- --- Constructors ---
 #####---------------------------------------------------------------------------
@@ -561,13 +508,11 @@
     return MultiTimeSeries(_datalist, dates=newdates, dtype=mdescr)
     
 
-
-################################################################################
-
     
 ################################################################################
 if __name__ == '__main__':
     import numpy as N
+    from maskedarray.testutils import assert_equal
     if 1:
         d = N.arange(5)
         m = MA.make_mask([1,0,0,1,1])
@@ -579,4 +524,17 @@
         dates = date_array(dlist)
         ts = time_series(mrec,dates)
         mts = MultiTimeSeries(mrec,dates)
-        self_data = [d, m, mrec, dlist, dates, ts, mts]
\ No newline at end of file
+        self_data = [d, m, mrec, dlist, dates, ts, mts]
+        
+    if 1:        
+        mts[:2] = 5
+        assert_equal(mts.f0._data, [5,5,2,3,4])
+        assert_equal(mts.f1._data, [5,5,2,1,0])
+        assert_equal(mts.f0._mask, [0,0,0,1,1])
+        assert_equal(mts.f1._mask, [0,0,0,0,1])
+        mts.harden_mask()
+        mts[-2:] = 5
+        assert_equal(mts.f0._data, [5,5,2,3,4])
+        assert_equal(mts.f1._data, [5,5,2,5,0])
+        assert_equal(mts.f0._mask, [0,0,0,1,1])
+        assert_equal(mts.f1._mask, [0,0,0,0,1]) 
\ No newline at end of file

Modified: trunk/Lib/sandbox/timeseries/tseries.py
===================================================================
--- trunk/Lib/sandbox/timeseries/tseries.py	2007-02-22 21:00:31 UTC (rev 2753)
+++ trunk/Lib/sandbox/timeseries/tseries.py	2007-02-23 03:16:56 UTC (rev 2754)
@@ -32,27 +32,23 @@
 import numpy.core.fromnumeric as fromnumeric
 import numpy.core.numeric as numeric
 import numpy.core.umath as umath
-#from numpy.core.records import recarray
+from numpy.core.records import recarray
 from numpy.core.records import fromarrays as recfromarrays
 
 import maskedarray.core as MA
-#reload(MA)
 from maskedarray.core import MaskedArray, MAError, masked, nomask, \
     filled, getmask, getmaskarray, make_mask_none, mask_or, make_mask, \
     masked_array
 
 import tcore as corelib
-#reload(corelib)
 from tcore import *
 
 import tdates
-#reload(tdates)
 from tdates import DateError, InsufficientDateError
 from tdates import Date, isDate, DateArray, isDateArray, \
-    date_array, date_array_fromlist, date_array_fromrange, thisday
+    date_array, date_array_fromlist, date_array_fromrange, thisday, today
 
 import cseries
-#reload(cseries)
 
 
 
@@ -162,7 +158,8 @@
     if dsize == tsize:
         return True
     elif data.ndim > 1:
-        dsize = numeric.asarray(data.shape)[:-1].prod()
+        #dsize = numeric.asarray(data.shape)[:-1].prod()
+        dsize = data.shape[0]
         if dsize == tsize:
             return True 
     elif data.ndim == 0 and tsize <= 1:
@@ -241,11 +238,40 @@
         func_series = getattr(super(TimeSeries, instance), _name)
         result = func_series(*args)
         if self._ondates:
-            result._dates = getattr(instance._dates, _name)
+            result._dates = getattr(instance._dates, _name)(*args)
         else:
             result._dates = instance._dates
         return result
 
+class _tsaxismethod(object):
+    """Defines a wrapper for array methods working on an axis (mean...).
+When called, returns a ndarray, as the result of the method applied on the series.
+    """
+    def __init__ (self, methodname):
+        """abfunc(fillx, filly) must be defined.
+           abinop(x, filly) = x for all x to enable reduce.
+        """
+        self._name = methodname
+    #
+    def __get__(self, obj, objtype=None):
+        self.obj = obj
+        return self
+    #
+    def __call__ (self, *args, **params):
+        "Execute the call behavior."
+        (_dates, _series) = (self.obj._dates, self.obj._series)
+        func = getattr(_series, self._name)
+        result = func(*args, **params)
+        if _dates.size == _series.size:
+            return result
+        else:
+            try:
+                axis = params.get('axis', args[0])
+                if axis in [-1, _series.ndim-1]:
+                    result = TimeSeries(result, dates=_dates)
+            except IndexError:
+                pass
+            return result
 
 class TimeSeries(MaskedArray, object):     
     """Base class for the definition of time series.
@@ -284,9 +310,9 @@
             if freq is not None and newdates.freq != freq:
                 newdates = newdates.tofreq(freq)
         else:
-            length = _getdatalength(data)
-            if length > 0:
-                newdates = date_array(start_date=start_date, length=length,
+            dshape = _data.shape
+            if len(dshape) > 0:
+                newdates = date_array(start_date=start_date, length=dshape[0],
                                       freq=freq)
             else:
                 newdates = date_array([], freq=freq)          
@@ -304,8 +330,8 @@
     #............................................
     def __array_finalize__(self,obj):
         MaskedArray.__array_finalize__(self, obj)        
-        self._dates = getattr(obj, '_dates', None)
-        self.observed = getattr(obj, 'observed', self._defaultobserved)
+        self._dates = getattr(obj, '_dates', [])
+        self.observed = getattr(obj, 'observed', None)
         return
     #..................................
     def __array_wrap__(self, obj, context=None):
@@ -323,7 +349,7 @@
         "Checks the validity of an index."
         if isinstance(indx, int):
             return (indx, indx)
-        if isinstance(indx, str):
+        elif isinstance(indx, str):
             indx = self._dates.date_to_index(Date(self._dates.freq, string=indx))
             return (indx, indx)
         elif isDate(indx):
@@ -345,9 +371,12 @@
         elif isinstance(indx, tuple):
             if len(indx) > self.shape:
                 raise IndexError, "Too many indices"
-            elif len(indx)==2:
-                return (indx,indx[0])
-            return (indx,indx[:-1])
+            if self._dates.size == self.size:
+                return (indx, indx)
+            return (indx,indx[0])
+#            elif len(indx)==2:
+#                return (indx,indx[0])
+#            return (indx,indx[:-1])
         elif isTimeSeries(indx):
             indx = indx._series
         if getmask(indx) is not nomask:
@@ -360,31 +389,47 @@
 Returns the item described by i. Not a copy as in previous versions.
         """
         (sindx, dindx) = self.__checkindex(indx)
-        data = self._series[sindx]
-        date = self._dates[dindx]
+        newdata = numeric.array(self._series[sindx], copy=False, subok=True)
+        newdate = self._dates[dindx]
         m = self._mask
-        
-        singlepoint = (len(numeric.shape(date))==0)
-
+        singlepoint = (len(numeric.shape(newdate))==0)
         if singlepoint:
-            if data is not masked and self.ndim > 1:
-                data = data.reshape((list((1,)) + list(data.shape)))
-            date = date_array(start_date=date, length=1, freq=date.freq)
-            
-        if m is nomask:
-            return TimeSeries(data, dates=date, mask=nomask, keep_mask=True,
-                      copy=False)
+            if newdata is masked:
+                newdata = tsmasked
+                newdata._dates = newdate
+                return newdata
+            elif self.ndim > 1:
+                # CHECK: use reshape, or set shape ?
+                newshape = (list((1,)) + list(newdata.shape))
+                newdata.shape = newshape
+        newdata = newdata.view(type(self))    
+        newdata._dates = newdate
+        return newdata
+# CHECK : The implementation below should work, but does not. Why ?
+#        newdata = numeric.array(self._data[sindx], copy=False)
+#        newdates = self._dates[dindx]
+#        if self._mask is not nomask:
+#            newmask = self._mask.copy()[sindx]
+#        else:
+#            newmask = nomask
+#        singlepoint = (len(numeric.shape(newdates))==0)
+#        if singlepoint:
+#            if newmask.ndim == 0 and newmask:
+#                output = tsmasked
+#                output._dates = newdates
+#                return output
+#            if self.ndim > 1:
+#                # CHECK: use reshape, or set shape ?
+#                newdata = newdata.reshape((list((1,)) + list(newdata.shape)))
+#                if newmask is not nomask:
+#                    newmask.shape = newdata.shape
+#        newdata = newdata.view(type(self))    
+#        newdata._dates = newdates
+#        newdata._mask = newmask
+#        return newdata
 
-        mi = m[sindx]
-        if mi.size == 1:
-            if mi:
-                output = tsmasked
-                output._dates = date
-                return output
-            return TimeSeries(data, dates=date, mask=nomask)
-        else:
-            return TimeSeries(data, dates=date, mask=mi)
 
+
     #........................
     def __setitem__(self, indx, value):
         """x.__setitem__(i, y) <==> x[i]=y
@@ -465,7 +510,6 @@
     __gt__ = _tsmathmethod('__gt__')
     __ge__ = _tsmathmethod('__ge__')
     
-    astype = _tsarraymethod('astype')
     reshape = _tsarraymethod('reshape', ondates=True)
     copy = _tsarraymethod('copy', ondates=True)
     compress = _tsarraymethod('compress', ondates=True)
@@ -474,6 +518,17 @@
     cumprod = _tsarraymethod('cumprod',ondates=False)
     anom = _tsarraymethod('anom',ondates=False)
     
+    sum = _tsaxismethod('sum')
+    prod = _tsaxismethod('prod')
+    mean = _tsaxismethod('mean')
+    var = _tsaxismethod('var')
+    varu = _tsaxismethod('varu')
+    std = _tsaxismethod('std')
+    stdu = _tsaxismethod('stdu')
+    all = _tsaxismethod('all')
+    any = _tsaxismethod('any')
+
+    
 #    def nonzero(self):
 #        """Returns a tuple of ndarrays, one for each dimension of the array,
 #    containing the indices of the non-zero elements in that dimension."""
@@ -599,6 +654,21 @@
         "Converts the dates to another frequency, and adapt the data."
         return convert(self, freq, func=func, position=position)
     #.....................................................
+    def transpose(self, *axes):
+        if self._dates.size == self.size:
+            result = super(TimeSeries, self).transpose(*axes)
+            result._dates = self._dates.transpose(*axes)
+        else:
+            errmsg = "Operation not permitted on multi-variable series"
+            print "AXES:",axes
+            if (len(axes)==0) or axes[0] != 0:
+                raise ValueError, errmsg
+            else:
+                result = super(TimeSeries, self).transpose(*axes)
+                result._dates = self._dates
+        return result
+    
+    
         
 def _attrib_dict(series, exclude=[]):
     """this function is used for passing through attributes of one
@@ -612,45 +682,7 @@
 ##--- ... Additional methods ...
 ##### --------------------------------------------------------------------------
 
-class _tsaxismethod(object):
-    """Defines a wrapper for array methods working on an axis (mean...).
-When called, returns a ndarray, as the result of the method applied on the series.
-    """
-    def __init__ (self, methodname):
-        """abfunc(fillx, filly) must be defined.
-           abinop(x, filly) = x for all x to enable reduce.
-        """
-        self._name = methodname
-    #
-    def __get__(self, obj, objtype=None):
-        self.obj = obj
-        return self
-    #
-    def __call__ (self, *args, **params):
-        "Execute the call behavior."
-        (_dates, _series) = (self.obj._dates, self.obj._series)
-        func = getattr(_series, self._name)
-        result = func(*args, **params)
-        if _series.ndim < 2 or _dates.size == _series.size:
-            return result
-        else:
-            try:
-                axis = params.get('axis', args[0])
-                if axis in [-1, _series.ndim-1]:
-                    result = TimeSeries(result, dates=_dates)
-            except IndexError:
-                pass
-            return result
 #.......................................
-TimeSeries.sum = _tsaxismethod('sum')
-TimeSeries.prod = _tsaxismethod('prod')
-TimeSeries.mean = _tsaxismethod('mean')
-TimeSeries.var = _tsaxismethod('var')
-TimeSeries.varu = _tsaxismethod('varu')
-TimeSeries.std = _tsaxismethod('std')
-TimeSeries.stdu = _tsaxismethod('stdu')
-TimeSeries.all = _tsaxismethod('all')
-TimeSeries.any = _tsaxismethod('any')
 
 
 class _tsblockedmethods(object):
@@ -668,7 +700,7 @@
     #
     def __call__ (self, *args, **params):
         raise NotImplementedError
-TimeSeries.transpose = _tsarraymethod('transpose', ondates=True)
+#TimeSeries.transpose = _tsarraymethod('transpose', ondates=True)
 TimeSeries.swapaxes = _tsarraymethod('swapaxes', ondates=True)
 
 
@@ -851,14 +883,15 @@
     `data` : 
         Array of data.
     """
-    data = numeric.asanyarray(data)
+    data = numeric.array(data, copy=False, subok=True)
     if dates is None:
-        length = _getdatalength(data)
-        if length > 0:
+        dshape = data.shape
+        if len(dshape) > 0:
             dates = date_array(start_date=start_date, end_date=end_date,
-                               length=length, include_last=include_last, freq=freq) 
+                               length=dshape[0], include_last=include_last, 
+                               freq=freq) 
         else:
-            dates = date_array([], freq=freq)
+            dates = date_array([], freq=freq)   
     elif not isinstance(dates, DateArray):
         dates = date_array(dlist=dates, freq=freq)
     return TimeSeries(data=data, dates=dates, mask=mask, observed=observed,
@@ -1310,8 +1343,31 @@
     
 ################################################################################
 if __name__ == '__main__':
-    from maskedarray.testutils import assert_equal
+    from maskedarray.testutils import assert_equal, assert_array_equal
     import numpy as N
-       
-
     
+    if 1:
+        dlist = ['2007-01-%02i' % i for i in range(1,11)]
+        dates = date_array_fromlist(dlist)
+        data = masked_array(numeric.arange(10), mask=[1,0,0,0,0]*2, dtype=float_)
+        ser1d = time_series(data, dlist)
+        
+        serfolded = ser1d.reshape((5,2))
+        assert_equal(serfolded._dates.shape, (5,2))
+        assert_equal(serfolded[0], time_series([0,1],mask=[1,0],
+                                               start_date=dates[0]))
+        assert_equal(serfolded[:,0], 
+                     time_series(ser1d[::2], dates=dates[::2]))
+        sertrans = serfolded.transpose()
+        assert_equal(sertrans.shape, (2,5))
+        
+        assert ser1d[0] is tsmasked
+        print "OK"
+    if 1:
+        hodie = today('D')
+        ser2d = time_series(N.arange(10).reshape(5,2), start_date=hodie,
+                            mask=[[1,1],[0,0],[0,0],[0,0],[0,0]])
+    if 1:
+        hodie = today('D')
+        ser3d = time_series(N.arange(30).reshape(5,3,2), start_date=hodie,)
+    




More information about the Scipy-svn mailing list