【问题标题】:Python - Using pandas to format excel cellPython - 使用 pandas 格式化 Excel 单元格
【发布时间】: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?

【问题讨论】:

  • 请将原始数据放在您的问题中,而不是图片中

标签: python excel pandas dataframe format


【解决方案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 所示。
      猜你喜欢
      • 2021-06-21
      • 2013-11-27
      • 1970-01-01
      • 2023-03-20
      • 1970-01-01
      • 2016-04-23
      • 2017-02-07
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多