def test_alignseries(self):
     "Tests align_series & align_with"
     (series, data, dates) = self.d
     #
     empty_series = time_series([], freq='d')
     a, b = align_series(series, empty_series)
     assert_equal(a.start_date, b.start_date)
     assert_equal(a.end_date, b.end_date)
     #
     aseries = time_series(data, dates+10)
     bseries = time_series(data, dates-10)
     (a, b) = align_with(series, aseries, bseries)
     assert_equal(a._dates, series._dates)
     assert_equal(b._dates, series._dates)
     assert_equal(a[-5:], series[:5])
     assert_equal(b[:5], series[-5:])
Exemple #2
0
    def __call__(self, *tseries, **kwargs):
        """generate a report

:Paramaters:
    - `*tseries` : the TimeSeries objects to be used in the report. If
      omitted, the previously set TimeSeries objects will be used
    - `**kwargs` : the options to be used in the report. See the __doc__
      string for the Report class for valid options. If omitted, the
      previously set options will be used"""

        option_dict = self.__make_dict(**kwargs)
        if len(tseries) == 0:
            tseries = self.tseries
        
        def option(kw):
            return option_dict.get(kw, _default_options[kw])
            
        dates = option('dates')
        header_row = option('header_row')
        header_char = option('header_char')
        header_justify = option('header_justify')
        row_char = option('row_char')
        footer_label = option('footer_label')
        footer_char = option('footer_char')
        footer_func = option('footer_func')
        delim = option('delim')
        justify = option('justify')
        prefix = option('prefix')
        postfix = option('postfix')
        mask_rep = option('mask_rep')
        datefmt = option('datefmt')
        fmtfunc = option('fmtfunc')
        wrapfunc = option('wrapfunc')
        col_width = option('col_width')
        nls=option('nls')
        output=option('output')
        fixed_width=option('fixed_width')
        
        if header_row is not None:
            has_header=True
            if len(header_row) == len(tseries)+1:
                # label for date column included
                rows = [header_row]
            elif len(header_row) == len(tseries):
                # label for date column not included
                rows = [['']+header_row]
            else:
                raise ValueError("mismatch with number of headers and series")
        else:
            has_header=False
            rows=[]

        if fixed_width:
        
            def _standardize_justify(userspec):
                if isinstance(userspec, str):
                    # justify all columns the the same way
                    return [userspec for x in range(len(tseries)+1)]
                elif isinstance(userspec, list):
                    if len(userspec) == len(tseries):
                        # justification for date column not included, so set that
                        # to left by default
                        return ['left'] + userspec
                else:
                    raise ValueError("invalid `justify` specification")
                    
            if justify is not None:
                justify = _standardize_justify(justify)
            else:
                # default column justification
                justify = ['left']
                for ser in tseries:
                    if ser.dtype.char in 'SUO': justify.append('left')
                    else: justify.append('right')
                    
                    
            if header_justify is not None:
                header_justify = _standardize_justify(header_justify)
            else:
                # default column justification
                header_justify = ['left' for x in range(len(tseries)+1)]
        else:
            justify = [None for x in range(len(tseries)+1)]

        if datefmt is None:
            def datefmt_func(date): return str(date)
        else:
            def datefmt_func(date): return date.strfmt(datefmt)

        if dates is None:
            tseries = ts.align_series(*tseries)
            dates = ts.date_array(start_date=tseries[0].start_date,
                                  end_date=tseries[0].end_date)
        else:
            tseries = ts.align_series(start_date=dates[0], end_date=dates[-1], *tseries)

        if isinstance(fmtfunc, list):
            fmtfunc = [fmtfunc_wrapper(f, mask_rep) for f in fmtfunc]
        else:
            fmtfunc = [fmtfunc_wrapper(fmtfunc, mask_rep)]*len(tseries)

        def wrapfunc_default(func):
            if func is None: return lambda x:x
            else: return func
            
        if isinstance(wrapfunc, list):
            if len(wrapfunc) == len(tseries):
                wrapfunc = [lambda x: x] + wrapfunc
            wrapfunc = [wrapfunc_default(func) for func in wrapfunc]
        else:
            wrapfunc = [wrapfunc_default(wrapfunc) for x in range(len(tseries)+1)]
    
            
        if isinstance(col_width, list):
            if len(col_width) == len(tseries):
                col_width = [None] + col_width
        else:
            col_width = [col_width for x in range(len(tseries)+1)]

        def getval(series, date):
            try:
                val = series[date]
            except IndexError:
                val = ma.masked
            return val

        for d in dates:
            rows.append([datefmt_func(d)]+[fmtfunc[i](getval(ser, d)) for i, ser in enumerate(tseries)])

        if footer_func is not None:
            has_footer=True
            if not isinstance(footer_func, list):
                footer_func = [footer_func]*len(tseries)

            if footer_label is None: footer_label = ['']
            else: footer_label = [footer_label]

            footer_data = []
            for i, ser in enumerate(tseries):
                if footer_func[i] is None:
                    footer_data.append('')
                else:
                    footer_data.append(fmtfunc[i](footer_func[i](ser[dates])))

            rows.append(footer_label + footer_data)
        else:
            has_footer=False
            
            
        def rowWrapper(row):
            newRows = [wrapfunc[i](item).split('\n') for i, item in enumerate(row)]
            return [[(substr or '') for substr in item] for item in map(None,*newRows)]
        # break each logical row into one or more physical ones
        logicalRows = [rowWrapper(row) for row in rows]
        numLogicalRows = len(logicalRows)
        # columns of physical rows
        columns = map(None,*reduce(operator.add,logicalRows))
        numCols = len(columns)
        colNums = list(range(numCols))

        # get the maximum of each column by the string length of its items
        maxWidths = [max(col_width[i], *[len(str(item)) for item in column])
                        for i, column in enumerate(columns)]

        def getSeparator(char, separate):
            if char is not None and separate:
                return char * (len(prefix) + len(postfix) + sum(maxWidths) + \
                                             len(delim)*(len(maxWidths)-1))
            else:
                return None

        header_separator = getSeparator(header_char, has_header)
        footer_separator = getSeparator(footer_char, has_footer)
        row_separator = getSeparator(row_char, True)

        # select the appropriate justify method
        justify_funcs = {'center':str.center, 'right':str.rjust, 'left':str.ljust,
                          'none':(lambda text, width: text)}

        if has_header and has_footer:
            data_start = 1
            data_end = numLogicalRows-3
        elif has_header:
            data_start = 1
            data_end = numLogicalRows-2
        elif has_footer:
            data_start = 0
            data_end = numLogicalRows-3
        else:
            data_start = 0
            data_end = numLogicalRows-2

        for rowNum, physicalRows in enumerate(logicalRows):
            for row in physicalRows:
                if rowNum == 0 and header_separator:
                    _justify = header_justify
                else:
                    _justify = justify
                    
                output.write(prefix \
                           + delim.join([justify_funcs[str(_justify[colNum]).lower()](str(item),width) for (colNum,item,width) in zip(colNums,row,maxWidths)]) \
                           + postfix + nls)

            if row_separator and (data_start <= rowNum <= data_end):
                output.write(row_separator + nls)
            elif header_separator and rowNum < data_start:
                output.write(header_separator + nls)
            elif footer_separator and rowNum == data_end + 1:
                output.write(footer_separator + nls)