In the below code, a DF is produced and then some basic styling is applied (borders, changing background colors, centering text, etc.)
What I would like to do is format all the values at the index 'KPI DEF'
as percentages. Some rows are to be styled as integer values and some as percentages.
Comments on some things explored:-
-
The code below already uses the Pandas
style.Styler.format
method to set target columns as percentages (https://pandas.pydata.org/docs/reference/api/pandas.io.formats.style.Styler.format.html) but this method doesn’t allow an axis to be specified. -
I also took a look at
style.Styler.apply
to see if a function could be applied to the target rows (similar to usingapply
regularly on a DF). However, the documentation suggests this method is only for HTML/CSS styling.
import pandas as pd
df = pd.DataFrame(index=pd.Index(['KPI ABC', 'KPI DEF', 'KPI GHI', 'KPI JKL']),
columns=pd.MultiIndex.from_product([
['North America', 'Europe', 'Asia'],
['Weekly', 'Monthly'],
['WK-01', 'WK-02', 'WK-03', 'WK-04', 'WK-05', 'WoW', 'Jan', 'Feb', 'Mar', 'MoM']]))
df.at['KPI ABC', ('North America', 'Weekly', 'WoW')] = 1.44
df.at['KPI ABC', ('Europe', 'Monthly', 'MoM')] = -0.24
df.at['KPI ABC', ('Asia', 'Monthly', 'MoM')] = 0
df.at['KPI DEF', ('North America', 'Weekly', 'WK-01')] = 91.21
df.at['KPI DEF', ('North America', 'Weekly', 'WK-02')] = 91.26
df.at['KPI DEF', ('North America', 'Weekly', 'WK-03')] = 90.77
df.at['KPI DEF', ('North America', 'Weekly', 'WK-04')] = 91.16
df.at['KPI DEF', ('North America', 'Weekly', 'WK-05')] = 91.37
mapper = {('North America', 'Weekly', 'WoW'): '{0:.2f}%',
('Europe', 'Monthly', 'MoM'): '{0:.2f}%',
('Asia', 'Monthly', 'MoM'): '{0:.2f}%'}
s = df.style.format(mapper).hide([
('North America', 'Weekly', 'Jan'),
('North America', 'Weekly', 'Feb'),
('North America', 'Weekly', 'Mar'),
('North America', 'Weekly', 'MoM'),
('North America', 'Monthly', 'WK-01'),
('North America', 'Monthly', 'WK-02'),
('North America', 'Monthly', 'WK-03'),
('North America', 'Monthly', 'WK-04'),
('North America', 'Monthly', 'WK-05'),
('North America', 'Monthly', 'WoW'),
('Europe', 'Weekly', 'Jan'),
('Europe', 'Weekly', 'Feb'),
('Europe', 'Weekly', 'Mar'),
('Europe', 'Weekly', 'MoM'),
('Europe', 'Monthly', 'WK-01'),
('Europe', 'Monthly', 'WK-02'),
('Europe', 'Monthly', 'WK-03'),
('Europe', 'Monthly', 'WK-04'),
('Europe', 'Monthly', 'WK-05'),
('Europe', 'Monthly', 'WoW'),
('Asia', 'Weekly', 'Jan'),
('Asia', 'Weekly', 'Feb'),
('Asia', 'Weekly', 'Mar'),
('Asia', 'Weekly', 'MoM'),
('Asia', 'Monthly', 'WK-01'),
('Asia', 'Monthly', 'WK-02'),
('Asia', 'Monthly', 'WK-03'),
('Asia', 'Monthly', 'WK-04'),
('Asia', 'Monthly', 'WK-05'),
('Asia', 'Monthly', 'WoW')],
axis="columns")
cell_hover = {'selector': 'td:hover', 'props': [('background-color', '#ffffb3')]}
headers = {'selector': 'th:not(.index_name)', 'props': 'background-color: #000066; color: white;'}
global_left_align = {'selector': 'th', 'props': 'text-align: left'}
s = s.set_table_styles([cell_hover, headers, global_left_align])
# BORDER FORMATTING ===========================
border_styles = {
('North America', 'Weekly', 'WoW'): {'selector': 'th, td', 'props': 'border-left: 1px solid #000066; border-right: 1px solid #000066'},
('North America', 'Monthly', 'MoM'): {'selector': 'th, td', 'props': 'border-left: 1px solid #000066; border-right: 1px solid #000066'},
('Europe', 'Weekly', 'WoW'): {'selector': 'th, td', 'props': 'border-left: 1px solid #000066; border-right: 1px solid #000066'},
('Europe', 'Monthly', 'MoM'): {'selector': 'th, td', 'props': 'border-left: 1px solid #000066; border-right: 1px solid #000066'},
('Asia', 'Weekly', 'WoW'): {'selector': 'th, td', 'props': 'border-left: 1px solid #000066; border-right: 1px solid #000066'},
('Asia', 'Monthly', 'MoM'): {'selector': 'th, td', 'props': 'border-left: 1px solid #000066; border-right: 1px solid #000066'}
}
for key, value in border_styles.items():
s = s.set_table_styles({key: [value]}, overwrite=False, axis=0)
# COLUMN HEADER FORMATTING ===========================
s = s.set_table_styles([{'selector': 'th.col_heading', 'props': 'text-align: center;'}], overwrite=False)
def larger_headers(val):
if val in ['North America', 'Europe', 'Asia']:
return 'font-size: 16pt'
return ''
s = s.applymap_index(larger_headers, axis='columns', level=0)