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'值,您还可以指定多种格式规则(例如边框、背景色、前景色)

(要求:openpyxljinja2


这是一个完整的运行示例:

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 单元格的主要内容,如果未能解决你的问题,请参考以下文章

Python数据分析

Python数据分析

Python数据分析

Python - 使用 pandas 格式化 Excel 单元格

嵌套字典错误——Python Pandas

将 pandas 数据框转换为自定义 JSON 格式(然后转换为 JS 对象)