Pandas:为Styler添加WoW/MoM列颜色样式及解决层叠问题
Pandas Styler实现WoW/MoM列正负值颜色样式层叠
问题背景
现有一段生成带样式DataFrame的Pandas代码,需为WoW和MoM列添加额外样式规则:正值显示为绿色,负值显示为红色,其余值保持默认样式。遇到以下问题:
- 多个样式函数层叠时,后续应用的样式会覆盖之前的样式
- 出现
'Styler' object has no attribute 'map'错误
解决方案
核心说明
- Pandas Styler的样式支持增量叠加,通过链式调用或保留Styler对象的连续赋值,配合
subset参数指定作用范围,即可实现多样式共存 - 不存在
Styler.map方法,正确用于单元格级样式的方法是Styler.applymap,行/列级样式使用Styler.apply
修改后的完整代码
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 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_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) 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) # --- 新增:WoW/MoM列正负值颜色样式 --- def color_pos_neg(val): if pd.notna(val): if val > 0: return 'color: green' elif val < 0: return 'color: red' return '' # 筛选所有WoW和MoM列 wow_mom_cols = df.columns[df.columns.get_level_values(2).isin(['WoW', 'MoM'])] # 应用颜色样式,subset指定作用列,增量叠加不覆盖原有样式 s = s.applymap(color_pos_neg, subset=wow_mom_cols) # --- 新增结束 --- tooltips = pd.DataFrame('', index=df.index, columns=df.columns) tooltips.at['KPI JKL', ('Europe', 'Monthly', 'Feb')] = 'Tooltip for Europe, Monthly, Feb [KPI JKL]' tooltips.at['KPI GHI', ('Asia', 'Weekly', 'WK-04')] = 'Tooltip for Asia, Weekly, WK-04 [KPI GHI]' s = s.set_tooltips(tooltips) html = s.to_html() tooltips_index = { 'KPI ABC': 'Tooltip for KPI ABC', 'KPI DEF': 'Tooltip for KPI DEF', 'KPI GHI': 'Tooltip for KPI GHI', 'KPI JKL': 'Tooltip for KPI JKL' } for kpi, tooltip in tooltips_index.items(): html = html.replace(f'>{kpi}<', f' title=\"{tooltip}\">{kpi}<') with open('styled_table_with_index_tooltips.html', 'w') as f: f.write(html) from IPython.core.display import display, HTML display(HTML(html))
关键修改点解析
- 颜色样式函数定义:
color_pos_neg函数判断单元格值的正负,返回对应的CSS颜色样式,空值或0返回默认样式。 - 精准作用于目标列:
通过df.columns.get_level_values(2).isin(['WoW', 'MoM'])筛选MultiIndex中第三层为WoW/MoM的列,用subset参数传递给applymap,确保样式只作用于目标列。 - 样式叠加规则:
所有set_table_styles调用都添加overwrite=False,新增的applymap操作直接叠加在原有Styler对象上,不会覆盖之前的边框、悬停等样式。
内容的提问来源于stack exchange,提问作者lummers
相关产品推荐
相关产品推荐

