import numpy as np import pandas as pd import IPython.display as display from reportlab.lib import colors from tia.analysis.perf import returns_cumulative import tia.rlab as rlab # The goal is to build a table which looks like the following display.Image('returns.png') # create fake returns for year index = pd.PeriodIndex(start='1/2014', end='12/2014', freq='M') returns = pd.DataFrame(.025 * np.random.randn(12, 3), index=index, columns=['Portfolio_{0}'.format(i) for i in range(1, 4)]) # remove last month to see how table handles no data returns.iloc[-1, :] = np.nan returns['Fund'] = returns.sum(axis=1) returns # Create the View for the pdf view = returns.copy() view.index = [i.strftime('%b') for i in view.index] # YTD Returns ytd = returns_cumulative(view) ytd.name = 'YTD' # transpose so dates are the columns view = view.append(ytd.to_frame().T) view = view.T view.index.name = 'Portfolio' # make a multi-level header view.columns = pd.MultiIndex.from_arrays([ ['2014 Returns']*len(view.columns), view.columns]) view # Setup the builder and any templates FONT_SZ = 8 FONT = 'Helvetica' FONT_BOLD = 'Helvetica-Bold' FONT_COLOR = colors.HexColor('#3b595f') GRID_COLOR = colors.HexColor('#a8c2cb') RPAD = LPAD = 3 TPAD = BPAD = 4 LEADING = FONT_SZ ROW_COLORS = [colors.HexColor('#eff4f6'), colors.white] pdf_path = 'returns_example.pdf' pdf = rlab.PdfBuilder(pdf_path, showBoundary=0) t = rlab.GridTemplate('page1', 100, 100) t.define_frames({'tbl': t[5:95, 5:95]}) # whole page t.register(pdf) # helper method to place box around a region def add_box(rng): rng.apply_style('BOX', .7, GRID_COLOR) tf = rlab.TableFormatter(view) # Styles for all cells # Use direct method tf.all.apply_styles({ 'FONTSIZE': FONT_SZ, 'FONTNAME': FONT, 'TEXTCOLOR': FONT_COLOR, 'VALIGN': 'MIDDLE', 'ALIGN': 'RIGHT', 'LEADING': LEADING, 'RIGHTPADDING': RPAD, "BOTTOMPADDING": BPAD, 'TOPPADDING': TPAD, 'LEFTPADDING': LPAD, }) # # Can use methods which means you do not have to remember style names and arguments # box_args = {'weight': .7, 'color': GRID_COLOR} regions = [tf.all, tf.cells, tf.header, tf.index, tf.all.iloc[-1:, :], tf.header.iloc[:1, :]] [region.set_box(**box_args) for region in regions] # cells Style tf.cells.set_row_backgrounds(ROW_COLORS) # make the last column bold tf.all.iloc[-1:, :].set_font(FONT_BOLD) # make the last row bold tf.all.iloc[:, -1:].set_font(FONT_BOLD) # format as percent and use red for negatives tf.cells.percent_format() # Header tf.header.set_fontname(FONT_BOLD) tf.header.set_align_center() tf.header.detect_colspans() # Index tf.index.set_font(FONT_BOLD) tf.index.set_row_backgrounds(ROW_COLORS) # Index-Header tf.index_header.set_fontname(FONT_BOLD) # don't allow table to expand or shrink pdf.build_page('page1', {'tbl': tf.build(expand=None, shrink=None)}) # allow table to expand both width and height wise pdf.build_page('page1', {'tbl': tf.build(expand='wh', shrink=None)}) pdf.save()