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:])
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)