Pandas DataFrame按条件设单元格背景色并导出HTML报错求助
解决Pandas Styler背景色设置及HTML保存报错问题
问题背景
拥有一个包含6个分类列和6个日期数值列的Pandas DataFrame,示例如下:
import pandas as pd import numpy as np df = pd.DataFrame({'DIVISION': ['FRA', 'FRA', 'FRA', 'FRA', 'FRA'], 'MONTH': ['FEB', 'FEB', 'FEB', 'FEB', 'FEB'], 'YEAR': [2023, 2023, 2023, 2023, 2023], 'RANGE': ['C', 'C', 'C', 'C', 'I'], 'CABIN': ['C', 'C', 'M', 'M', 'C'], 'BP_TYPE': ['SYS', 'USR', 'SYS', 'USR', 'SYS'], '2023-01-27': [60.92, 64.89, 112.47, 112.47, 779.78], '2023-01-28': [63.18, 66.76, 132.17, 132.17, 763.60], '2023-01-29': [61.95, 64.94, 129.21, 129.21, 753.88], '2023-01-30': [59.40, 62.09, 118.04, 118.04, 720.08], '2023-01-31': [52.69, 55.53, 104.28, 104.28, 687.73], '2023-02-01': [85.56, 89.64, 123.53, 124.62, 789.50]})
需求说明
从第7列(索引为6)开始,根据当前列与前一列的偏差百分比设置单元格背景色,规则如下:
- 偏差 > +5%: 红色
- 偏差 < -5%: 蓝色
- 偏差 > +2.5% 且 <= +5%: 浅红色
- 偏差 < -2.5% 且 >= -5%: 浅蓝色
尝试过的失败方法
方法1:自定义颜色函数并按行应用
def color_cell(val): color = 'green' if val > 0: if val > 0.01: color = 'red' elif val > 0.025: color = 'lightred' elif val < 0: if val < -0.01: color = 'blue' elif val < -0.025: color = 'lightblue' return 'background-color: %s' % color df_style = df.style.apply(color_cell, axis=1, subset=pd.IndexSlice[:, 6:])
方法2:直接对数值列应用样式
df_style = df_pivot.iloc[:, 6:].style.applymap(color_cell).render()
错误的HTML保存代码
html_content = df_style.render().to_html() with open("color.html", "w") as f: f.write(html_content)
参考代码及报错
使用参考代码时出现AttributeError:
bins = np.array([-np.inf, -5, -2.5, 2.5, 5, np.inf])/100 labels = ['background-color: blue', 'background-color: lightblue', '', 'background-color: lightred', 'background-color: red'] def color(df): return (df.drop(columns=['DIVISION', 'MONTH', 'YEAR', 'RANGE', 'CABIN', 'BP_TYPE']) .pct_change(axis=1).apply(lambda s: pd.cut(s, bins=bins, labels=labels), ) .reindex_like(df) ) html = (df.style.apply(color, axis=1, subset=df.columns[7:]).to_html()) with open('table.html', 'w') as f: f.write(html)
错误信息:
Traceback (most recent call last): File "./test.py", line 28, in html = (df.style.apply(color, axis=1, subset=df.columns[7:]).to_html()) AttributeError: 'Styler' object has no attribute 'to_html'
解决方案
核心问题分析
to_html()方法错误:Pandas的Styler对象没有to_html()方法,正确获取HTML字符串的方法是render()。- 样式应用逻辑问题:之前的
apply方式没有正确关联偏差百分比与单元格,需要先计算每行的偏差率,再针对数值列应用颜色规则。
正确代码实现
import pandas as pd import numpy as np df = pd.DataFrame({'DIVISION': ['FRA', 'FRA', 'FRA', 'FRA', 'FRA'], 'MONTH': ['FEB', 'FEB', 'FEB', 'FEB', 'FEB'], 'YEAR': [2023, 2023, 2023, 2023, 2023], 'RANGE': ['C', 'C', 'C', 'C', 'I'], 'CABIN': ['C', 'C', 'M', 'M', 'C'], 'BP_TYPE': ['SYS', 'USR', 'SYS', 'USR', 'SYS'], '2023-01-27': [60.92, 64.89, 112.47, 112.47, 779.78], '2023-01-28': [63.18, 66.76, 132.17, 132.17, 763.60], '2023-01-29': [61.95, 64.94, 129.21, 129.21, 753.88], '2023-01-30': [59.40, 62.09, 118.04, 118.04, 720.08], '2023-01-31': [52.69, 55.53, 104.28, 104.28, 687.73], '2023-02-01': [85.56, 89.64, 123.53, 124.62, 789.50]}) # 计算数值列的偏差百分比(当前列/前一列 -1) numeric_cols = df.columns[6:] pct_changes = df[numeric_cols].pct_change(axis=1) # 定义颜色映射函数 def get_bg_color(pct): if pd.isna(pct): # 第一列没有前一列,返回空样式 return '' if pct > 0.05: return 'background-color: red' elif 0.025 < pct <= 0.05: return 'background-color: lightcoral' # lightred不是标准CSS色,用lightcoral替代 elif pct < -0.05: return 'background-color: blue' elif -0.05 <= pct < -0.025: return 'background-color: lightblue' else: return '' # 应用样式:对每个数值列(从第7列开始)的单元格,根据偏差率设置背景色 df_style = df.style.applymap(lambda val, col: get_bg_color(pct_changes.loc[val.name, col]), subset=numeric_cols, col=df.columns) # 保存为HTML文件 html_content = df_style.render() with open('color_table.html', 'w') as f: f.write(html_content)
代码说明
- 偏差率计算:用
pct_change(axis=1)计算每行中当前列与前一列的百分比变化,得到偏差率DataFrame。 - 颜色函数:处理NaN值(第一列无前置列),并根据偏差率范围返回对应的CSS背景色样式,注意
lightred不是标准CSS颜色,改用lightcoral保证显示正常。 - 样式应用:使用
applymap遍历每个数值单元格,结合对应的偏差率值返回样式,subset指定仅处理第7列及以后的数值列。 - HTML保存:调用
Styler.render()获取完整的HTML字符串,直接写入文件即可。
内容的提问来源于stack exchange,提问作者Glammy
相关产品推荐
相关产品推荐

