Python - 使用 pandas 格式化 Excel 单元格
Posted
技术标签:
【中文标题】Python - 使用 pandas 格式化 Excel 单元格【英文标题】:Python - Using pandas to format excel cell 【发布时间】:2017-10-24 07:23:26 【问题描述】:我有一个 pandas 数据框,如下所示。
我想将“通过/失败”列格式化为if Fail --> red background, else green background
,例如:
我尝试使用 Pandas 进行格式化,但无法为 Excel 添加颜色。以下是代码:
writer = pandas.ExcelWriter(destination,engine = 'xlsxwriter')
color = Answer.style.applymap(lambda x: 'color: red' if x == "Fail" else 'color: green',subset= pandas.IndexSlice[:,['Pass/Fail']])
color.to_excel(writer,'sheet1')
我尝试了无法安装的 StyleFrame。似乎 StyleFrame 不符合我的 python 版本 3.6。
如何根据需要格式化 Excel?
【问题讨论】:
请将原始数据放在您的问题中,而不是图片中 【参考方案1】:如果有一个或多个列并且要格式化的值超过两个,并且想要一次应用多个格式规则,那么您可以执行以下操作:
def fmt(data, fmt_dict):
return data.replace(fmt_dict)
styled = df.style.apply(fmt, fmt_dict=fmt_dict, subset=['Test_1', 'Test_2' ])
styled.to_excel('styled.xlsx', engine='openpyxl')
上面,fm_dict
是一个字典,其值映射到相应的格式:
fmt_dict =
'Pass': 'background-color: green',
'Fail': 'background-color: red',
'Pending': 'background-color: yellow; border-style: solid; border-color: blue'; color: red,
注意,对于'Pending'
值,您还可以指定多种格式规则(例如边框、背景色、前景色)
(要求:openpyxl
和 jinja2
)
这是一个完整的运行示例:
import pandas as pd
df = pd.DataFrame('Test_1':['Pass','Fail', 'Pending', 'Fail'],
'expect':['d','f','g', 'h'],
'Test_2':['Pass','Pending', 'Pass', 'Fail'],
)
fmt_dict =
'Pass': 'background-color: green',
'Fail': 'background-color: red',
'Pending': 'background-color: yellow; border-style: solid; border-color: blue; color:red',
def fmt(data, fmt_dict):
return data.replace(fmt_dict)
styled = df.style.apply(fmt, fmt_dict=fmt_dict, subset=['Test_1', 'Test_2' ])
styled.to_excel('styled.xlsx', engine='openpyxl')
【讨论】:
【参考方案2】:免责声明:我编写了以下库
我想建议使用StyleFrame:
import pandas as pd
from StyleFrame import StyleFrame, Styler
df = pd.DataFrame('Pass/Fail':['Pass','Fail','Fail'],
'expect':[1,2,3])
sf = StyleFrame(df)
sf.apply_style_by_indexes(sf[sf['Pass/Fail'] == 'Pass'], cols_to_style='Pass/Fail',
styler_obj=Styler(bg_color='green'))
sf.apply_style_by_indexes(sf[sf['Pass/Fail'] == 'Fail'], cols_to_style='Pass/Fail',
styler_obj=Styler(bg_color='red'))
sf.to_excel('test.xlsx').save()
因为它弥合了 pandas 和 openpyxl 之间的差距,所以样式是在数据帧级别而不是工作表级别完成的(例如,您不需要知道相关的单元格范围是 B2:B4
或与索引混淆。
上面的代码输出如下:
编辑:刚刚看到您提到您尝试安装但出现错误。您可以编辑您的问题并包含错误吗?
【讨论】:
【参考方案3】:你可以使用conditional_format:
df = pd.DataFrame('Pass/Fail':['Pass','Fail','Fail'],
'expect':[1,2,3])
print (df)
Pass/Fail expect
0 Pass 1
1 Fail 2
2 Fail 3
writer = pd.ExcelWriter('pandas_conditional.xlsx', engine='xlsxwriter')
df.to_excel(writer, sheet_name='Sheet1')
workbook = writer.book
worksheet = writer.sheets['Sheet1']
red_format = workbook.add_format('bg_color':'red')
green_format = workbook.add_format('bg_color':'green')
worksheet.conditional_format('B2:B4', 'type': 'text',
'criteria': 'containing',
'value': 'Fail',
'format': red_format)
worksheet.conditional_format('B2:B4', 'type': 'text',
'criteria': 'containing',
'value': 'Pass',
'format': green_format)
writer.save()
get_loc
的更多动态解决方案column
的位置和dictionary
的映射:
import string
df = pd.DataFrame('Pass/Fail':['Pass','Fail','Fail'],
'expect':[1,2,3])
print (df)
Pass/Fail expect
0 Pass 1
1 Fail 2
2 Fail 3
writer = pd.ExcelWriter('pandas_conditional.xlsx', engine='xlsxwriter')
df.to_excel(writer, sheet_name='Sheet1')
workbook = writer.book
worksheet = writer.sheets['Sheet1']
red_format = workbook.add_format('bg_color':'red')
green_format = workbook.add_format('bg_color':'green')
#dict for map excel header, first A is index, so omit it
d = dict(zip(range(25), list(string.ascii_uppercase)[1:]))
print (d)
0: 'B', 1: 'C', 2: 'D', 3: 'E', 4: 'F', 5: 'G', 6: 'H', 7: 'I', 8: 'J',
9: 'K', 10: 'L', 11: 'M', 12: 'N', 13: 'O', 14: 'P', 15: 'Q', 16: 'R',
17: 'S', 18: 'T', 19: 'U', 20: 'V', 21: 'W', 22: 'X', 23: 'Y', 24: 'Z'
#set column for formatting
col = 'Pass/Fail'
excel_header = str(d[df.columns.get_loc(col)])
#get length of df
len_df = str(len(df.index) + 1)
rng = excel_header + '2:' + excel_header + len_df
print (rng)
B2:B4
worksheet.conditional_format(rng, 'type': 'text',
'criteria': 'containing',
'value': 'Fail',
'format': red_format)
worksheet.conditional_format(rng, 'type': 'text',
'criteria': 'containing',
'value': 'Pass',
'format': green_format)
writer.save()
编辑1:
感谢jmcnamara 的评论和XlsxWriter
col = 'Pass/Fail'
loc = df.columns.get_loc(col) + 1
len_df = len(df.index) + 1
worksheet.conditional_format(1,loc,len_df,loc, 'type': 'text',
'criteria': 'containing',
'value': 'Fail',
'format': red_format)
worksheet.conditional_format(1,loc,len_df,loc, 'type': 'text',
'criteria': 'containing',
'value': 'Pass',
'format': green_format)
writer.save()
编辑:
最后一个版本的 pandas (0.20.1
) 和 styles 的另一个解决方案:
df = pd.DataFrame('Pass/Fail':['Pass','Fail','Fail'],
'expect':['d','f','g'])
print (df)
Pass/Fail expect
0 Pass d
1 Fail f
2 Fail g
def f(x):
col = 'Pass/Fail'
r = 'background-color: red'
g = 'background-color: green'
c = np.where(x[col] == 'Pass', g, r)
y = pd.DataFrame('', index=x.index, columns=x.columns)
y[col] = c
return y
styled = df.style.apply(f, axis=None)
styled.to_excel('styled.xlsx', engine='openpyxl')
【讨论】:
有什么方法可以使用列名“Pass/Fail”而不是“B2:B4”? def f(x) 中的 x 是什么?因为以后使用函数的时候,没有定义x 在style
x
中都是df
,因为Styler.apply
有参数axis=None
。它与经典 pandas f(df)
相同。通过print (x)
进行测试
在文档here中有解释
好答案。请注意,使用 conditional_format()
不需要构建和使用 B2:B4
样式字符串。也可以使用(first_row, first_col, last_row, last_col)
的零索引值,如docs 所示。以上是关于Python - 使用 pandas 格式化 Excel 单元格的主要内容,如果未能解决你的问题,请参考以下文章