Clueless
Clueless

Reputation: 193

Correct row coloring with pandas dataframe styler

I spend my time to solve a problem with coloring table row if the color is basing on a previous row.

In a four point system there is following logic. If 0 or 1 point the row color should be red, if 3 or 4 points the row color should be green and if 2 points the color should be as the row before.

I was not able to determine the previous row color in a dataframe. I solved it with a 'temp' column. Unfortunately this column is shown in the HTML table.

def should_colored(sum_of_points):
    if sum_of_points > 2:
        return True
    elif sum_of_points < 2:
        return False
    else:
        return np.NaN

def determine_coloring_for_row(results):
    tmp = pd.DataFrame(results.values, columns=['color_result'])

    tmp['color_result'] = tmp['color_result'].apply(lambda i : should_colored(i))    
    tmp['color_result'].fillna(method='ffill', inplace=True)

    return tmp['color_result'].values

def color_row(row, number_of_columns):
    color = 'green' if row['color_result'] else 'red' 

    return ['background-color: %s' % color] * number_of_columns

df['color_result'] = determine_coloring_for_row(df['sum_of_points'])
df.style.apply(color_row, number_of_columns = len(df.columns), axis=1)

enter image description here

Has anybody an idea how to solve it by using style.apply or by hiding the metadata column?

Upvotes: 1

Views: 1210

Answers (1)

jezrael
jezrael

Reputation: 862731

I think new column is not necessary, need DataFrame of styles only by original DataFrame columns and index and set rows by condition with mask:

def highlight(x):
    c1 = 'background-color: green'
    c2 = 'background-color: red' 

    df1 = pd.DataFrame(c2, index=x.index, columns=x.columns)
    df1 = df1.mask(df['sum_of_points'].map(should_colored).ffill(), c1)
    #print (df1)
    return df1

df.style.apply(highlight, axis=None)

Sample:

df = pd.DataFrame({'sum_of_points':[0,1,2,1,2,3,4,1,2,2,4,5,0,1,2],
                   'A':range(15)})

print (df)
     A  sum_of_points
0    0              0
1    1              1
2    2              2
3    3              1
4    4              2
5    5              3
6    6              4
7    7              1
8    8              2
9    9              2
10  10              4
11  11              5
12  12              0
13  13              1
14  14              2

def should_colored(sum_of_points):
    if sum_of_points > 2:
        return True
    elif sum_of_points < 2:
        return False
    else:
        return np.NaN

def highlight(x):
    c1 = 'background-color: green'
    c2 = 'background-color: red' 

    df1 = pd.DataFrame(c2, index=x.index, columns=x.columns)
    df1 = df1.mask(x['sum_of_points'].map(should_colored).ffill(), c1)
    return df1

df.style.apply(highlight, axis=None)

pic

Upvotes: 2

Related Questions