How to combine different styles in one styler map?

83 views Asked by At

I have a dataframe with 3 kind of data types - int64, float64 and object (string). How to apply format for two different data types in one function?

Sample:

def abc_style_format(cell_val):
    default = ""
    style_a = "background-color: green"
    style_b = "background-color: gold"
    style_c = "background-color: salmon"
    style_float = "precision=2"

    match cell_val:
        case "A":
            return style_a
        case "B":
            return style_b
        case "C":
            return style_c

    if type(cell_val) == "float64":
        return style_float

    return default

df_abc.style.map(abc_style_format)

Block match/case works properly, but part precision=2 doesn't work.

The result:

enter image description here

1

There are 1 answers

2
Laurent On BEST ANSWER

Here is one way to do it by defining as many helper functions as needed:

import pandas as pd


def _abc_style_format(s: pd.Series) -> list[str]:
    """Helper function to format 'abc' columns.

    Args:
        s: target column.

    Returns:
        list of styles to apply to each target column cell.

    """
    background_colors = []
    for v in s:
        match v:
            case "A":
                background_colors.append("background-color: green")
            case "B":
                background_colors.append("background-color: gold")
            case "C":
                background_colors.append("background-color: salmon")
    return background_colors
def _qty_format(s: pd.Series) -> list[str]:
    """Helper function to format 'qty' column.

    Args:
        s: target column.

    Returns:
        list of styles to apply to each target column cell.

    """
    font_colors = []
    for v in s:
        if v > 150:
            font_colors.append("color: red")
        else:
            font_colors.append("color: green")
    return font_colors

And one main function:

from pandas.io.formats.style import Styler


def style(df: pd.DataFrame) -> Styler:
    """Function to style whole dataframe.

    Args:
        df: target dataframe.

    Returns:
        styled dataframe.

    """
    styler = df.style
    for col in df.columns:
        match df[col].dtype:
            case "object":
                styler = styler.apply(_abc_style_format, subset=col)
            case "float64":
                styler = styler.format(precision=2, subset=col)
            case "int64":
                styler = styler.apply(_qty_format, subset=col)
            case _:
                pass
    return styler

Then, with the following toy dataframe:

df = pd.DataFrame(
    {
        "description": ["product1", "product2", "product3"],
        "qty": [130, 160, 110],
        "gm": [43.20000, 40.70000, 35.20000],
        "abc_gm_category": ["A", "B", "C"],
        "abc_amount_category": ["C", "A", "B"],
    }
)

You can simply do:

styled_df = style(df)

styled_df

Which gets you the expected output:

enter image description here