In [1]:
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
In [2]:
# The goal is to build a table which looks like the following
display.Image('returns.png')
In [3]:
# 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
Out[3]:
In [4]:
# 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
Out[4]:
In [13]:
# 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()
In [ ]: