pythonpandasdataframejupyter-notebookpandas-styles

Parenthesis in negative numbers on Pandas Styler object


So I got a 3x3 dataframe that looks like this:

import pandas as pd
df = pd.DataFrame([[-232.3,43.1,"hre"],[-245.7,-943.7,"jtr"],[956.3,435.2,"fgjh"]], columns=list("ABC"))

And I'm styling it using:

df_stl = df.style.background_color(axis = None, subset = ["A", "B"], cmap = 'autumn')

I wanna be able to format the final dataframe values (on the Styler object created after all these methods) with parenthesis only on negative number, without losing the background colors.

So I want something like:

A B C
$(232.3) 43.1 "hre"
$(245.7) $(943.7) "jtr"
956.3 435.2 "fgjh"

I tried to add a .map(parent) after .background_color(), where 'parent' is something like this:

def parent(x):
    if(type(x) == float):
        if(x>=0):
            a - f"${x:.,0f}"
        else:
            a = f"$({abs(x):.,0f})"
       else:
        a = x
    return a

So, I tried this:

df_stl = df.style.background_color(axis = None, subset = ["A", "B"], cmap = 'autumn').map(parent)

But it returns a

'ValueError': Styles supplied as string must follow CSS rule formats, for exameple 'attr: val;'. '$ (232.3)' was given

I know that I can use .format({"A": "${:,.0f}"}) for each column, but I want to format conditionaly some columns after those style methods, keeping that and other methods that changes colors based on values. Is there any easy way to achieve that result?


Solution

  • The reason .map() is throwing an error is because that expects you to pass a function that returns CSS-styling, not a formatted string (see docs). E.g. something like background-color: 'red';

    You can use your parent function in a .format() call though and that won't change the underlying data or colors. So that should allow you to apply your other conditions too. For example (with a slightly cleaner parent function):

    def parent(x):
        if isinstance(x, float):
            return f"${x:,.0f}" if x >= 0 else f"$({abs(x):,.0f})"
        else:
            return x
    df_stl = df.style.background_color(axis=None, subset=["A", "B"], cmap='autumn').format(parent)
    

    enter image description here

    Applying formatting to only a single column

    [Update based on comments]

    If you'd like to only apply your parent function to a single column, you can do this by instead passing a dictionary. Let's say you want to format column "A" with parent , you'd just do this:

    df_stl = df.style.background_color(axis=None, subset=["A", "B"], cmap='autumn').format({"A": parent})
    

    If you also wanted to style column "B" with other_style_function then just do

    df_stl = df.style.background_color(axis=None, subset=["A", "B"], cmap='autumn').format({"A": parent, "B": other_style_function})