Pandas 不着色 table 内容

Pandas not coloring table contents

我正在尝试创建一个 table 来估算具有买卖价格的 DataFrame 的利润:

    import pandas as pd
    from df2img import df2img
    import matplotlib.pyplot as plt
    
    
    
    df = pd.DataFrame(
        {
            'Fruits': ['Apple', 'Apple', 'Apple', 'Orange', 'Banana', 'Orange'],
            'BuyPrice': [1000, 3000, 2400, 3000, 800, 1500],
            'SellPrice': [1200, 2800, 2500, 2500, 700, 1750]
        }
    )
    
    
    # Display DataFrame
    print('Original DataFrame:\n')
    print(df)
    
    # Add Profit percentage column
    df['Profit'] = (df['SellPrice']-df['BuyPrice'])*100/df['BuyPrice']
    df['Profit'] = df.apply(lambda x: "{:,.2f} %".format(x['Profit']), axis=1)
    
    # Rename column titles
    df = df.rename({'BuyPrice': 'Buy Price', 'SellPrice': 'Sell Price'}, axis=1)
    
    # Highlight positive and negative profits
    def highlight_cols(s):
        color = 'red' if type(s) != str and s < 0 else 'green'        
        return 'color: %s' % color
    
    df.style.applymap(highlight_cols, subset=['Profit'])


    print('\nFinal DataFrame:\n')
    print(df)
    
    
    # Now create an image file for the table
    df2img(
        df,
        file="table_fruits.png",
        header_color="white",
        header_bgcolor="orange",
        row_bgcolors=["lightgray", "white"],
        font_size=10.0,
        col_width=1.5,
        row_height=0.3
    )
    
    plt.show()

这里我想用绿色给正利润上色,用红色给负利润上色。 df.style.applymap 仅在我不在同一单元格的 Jupyter 笔记本上使用 df2img 时才起作用(尽管颜色不正确)。因此 DataFrame Styler 指令不会传递到最终图像文件。有什么不那么复杂的解决方案吗?

输出:

需要稍作修改。在确定正数或负数时,我们不希望将百分比表示为字符串。我们也不会将存储的百分比乘以 100,因为这会影响以后的格式化能力。

新设置可能如下所示:

import numpy as np
import pandas as pd

df = pd.DataFrame({
    'Fruits': ['Apple', 'Apple', 'Apple', 'Orange', 'Banana', 'Orange'],
    'BuyPrice': [1000, 3000, 2400, 3000, 800, 1500],
    'SellPrice': [1200, 2800, 2500, 2500, 700, 1750]
})

# Add Profit percentage column
df['Profit'] = (df['SellPrice'] - df['BuyPrice']) / df['BuyPrice']

# Rename column titles
df = df.rename({'BuyPrice': 'Buy Price', 'SellPrice': 'Sell Price'}, axis=1)
Fruits Buy Price Sell Price Profit
0 Apple 1000 1200 0.2
1 Apple 3000 2800 -0.0666667
2 Apple 2400 2500 0.0416667
3 Orange 3000 2500 -0.166667
4 Banana 800 700 -0.125
5 Orange 1500 1750 0.166667

*如果(无论出于何种原因)我们需要将值乘以 100,请记住在绘图和导出到图像之前再除以。


我强烈建议不要使用 Plotly Tables 来执行此特定任务,因为它们在条件格式方面不那么灵活。使用 dataframe_image and the built-in Styler object:

更容易
# pip install dataframe_image
import dataframe_image as dfi

# Highlight positive and negative profits
def highlight_cols(s):
    return np.where(s < 0, 'color: red', 'color:green')


# CSS for col_headings
headers = {
    'selector': 'th.col_heading',
    'props': 'background-color: orange; color: white;'
}

# CSS for rows
rows = [
    {
        'selector': 'tbody tr:nth-child(even)',
        'props': 'background-color: lightgray'
    },
    {
        'selector': 'tbody tr:nth-child(odd)',
        'props': 'background-color: white'
    }
]

styler = (
    df.reset_index()  # make current index a column
        .style  # Create Styler
        .hide_index()  # Hide new index (since old index is a column
        .apply(
            # apply highlighter function to Profit Column
            highlight_cols, axis=0, subset=['Profit']
        )
        .format(
            # apply percentage formatting to Profit Column
            formatter='{:.2%}', subset=['Profit']
        )
        .set_table_styles([headers, *rows])  # add CSS
)
# Export Styled Table to PNG
dfi.export(styler, 'table_fruits.png')


使用 Plotly 时,允许条件样式的开销更大,即使静态样式规则更容易应用:

# pip install df2img
from df2img import df2img

# Define Format Strings for Columns
col_formats = {'Profit': '.2%'}

# Make index a column with label
plot_df = df.reset_index()

# Build dictionary of Font colours for _all_ cells
# Using default
font_colours_df = pd.DataFrame(
    'black',  # Set default font colour
    index=plot_df.index, columns=plot_df.columns
)
# Apply Colours to Profit Column
font_colours_df['Profit'] = np.where(
    plot_df['Profit'] < 0, 'red', 'green'
)
fig = df2img.plot_dataframe(
    plot_df,
    print_index=False,  # Hide new index (old index now column)
    row_fill_color=('white', 'lightgray'),
    tbl_header={
        'font': {'color': 'white'},
        'fill': {'color': 'orange'}
    },
    tbl_cells={
        'format': [
            # Conditionally build a complete list of foramt strings
            #  Based on col_formats dict and columns
            col_formats[c] if c in col_formats else None
            for c in plot_df.columns
        ],
        'font': {
            # Needs Transposed for colours to go to the correct cells
            'color': font_colours_df.T
        }
    },
    show_fig=False,  # Don't show in by default (since we're saving instead)
    fig_size=(500, 175)  # Set some reasonable Fig Size
)
df2img.save_dataframe(fig=fig, filename="table_fruits.png")

*注意 Plotly 没有子集的概念。必须显式声明所有单元格的样式。对于 tbl_cells.format,这意味着必须为每一列提供格式字符串(或 None)。对于 tbl_cells.font.color,这意味着传递 整个 DataFrame 颜色来设置单个列的样式。

尽管如此,结果 Table 是: