33

I have been trying to write a function to use with pandas style. I want to highlight specific columns that I specify in the arguments. This is not very elegant, but for example:

data =  pd.DataFrame(np.random.randn(5, 3), columns=list('ABC'))

def highlight_cols(df, cols, colcolor = 'gray'):
    for col in cols:
        for dfcol in df.columns:
            if col == cols:
                color = colcolor
    return ['background-color: %s' % color]*df.shape[0]

then call with:

data.style.apply(highlight_cols(cols=['B','C']))

I get an error: 'Series' object has no attribute 'columns'

I think I fundamentally don't quite understand how the styler calls and applyies the function.

Henry Ecker
  • 34,399
  • 18
  • 41
  • 57
Maria Petrova
  • 549
  • 2
  • 6
  • 10

3 Answers3

52

I think you can use Slicing in Styles for select columns B and C and then Styler.applymap for elementwise styles.

import pandas as pd
import numpy as np

data =  pd.DataFrame(np.random.randn(5, 3), columns=list('ABC'))
#print (data)

def highlight_cols(s):
    color = 'grey'
    return 'background-color: %s' % color

data.style.applymap(highlight_cols, subset=pd.IndexSlice[:, ['B', 'C']])

pic

If you want more colors or be more flexible, use Styler.apply(func, axis=None), the function must return a DataFrame with the same index and column labels:

import pandas as pd
import numpy as np

data =  pd.DataFrame(np.random.randn(5, 3), columns=list('ABC'))
#print (data)

def highlight_cols(x):
    #copy df to new - original data are not changed
    df = x.copy()
    #select all values to default value - red color
    df.loc[:,:] = 'background-color: red'
    #overwrite values grey color
    df[['B','C']] = 'background-color: grey'
    #return color df
    return df    

data.style.apply(highlight_cols, axis=None)

pic1

jezrael
  • 822,522
  • 95
  • 1,334
  • 1,252
  • Thanks for the answer, I want to return value as zero after styling. is it possible? I am encountering with Styler error., – Chandu Mar 22 '19 at 11:41
  • I have tried like returning return 'background-color: %s; data:0;' % color return 'background-color: %s; content:0;' % color – Chandu Mar 22 '19 at 11:42
  • @CSMaverick - Sorry, I am a bit confused, is possible create new question? Be free use this answer for it. – jezrael Mar 22 '19 at 11:51
  • Is there a way to count the number of rows that have been highlighted? – MOA May 18 '20 at 11:07
  • @MOA - here it depends of selected columns, e.g. cout = df[['B','C']].size should working – jezrael May 18 '20 at 11:09
  • @jezrael, How about in the case where not all rows have been highlighted? – MOA May 18 '20 at 12:31
  • 1
    @MOA - I think the best is create question, it depends of your code. – jezrael May 18 '20 at 12:32
  • 1
    @jezrael In your first code block, I tried changing it to `def highlight_cols(color)` so I could input any color that I need. But then, `data.style.applymap(highlight_cols, subset=pd.IndexSlice[:, ['B', 'C']])` didn't work any more. Could you please help? Thanks! – Huy Truong Apr 08 '22 at 16:05
  • 1
    One can use 'background-color: grey' to indicate no change – Nir Feb 02 '23 at 20:48
26

You can do it bit more dynamically:

data =  pd.DataFrame(np.random.randn(5, 3), columns=list('ABC'))

# dictionary of column colors
coldict = {'A':'grey', 'C':'yellow'}

def highlight_cols(s, coldict):
    if s.name in coldict.keys():
        return ['background-color: {}'.format(coldict[s.name])] * len(s)
    return [''] * len(s)

data.style.apply(highlight_cols, coldict=coldict)

enter image description here

MaxU - stand with Ukraine
  • 205,989
  • 36
  • 386
  • 419
2

You can use the method style.set_properties:

df = pd.DataFrame({'A': [1, 2], 'B': [3, 4], 'C': [5, 6]})

df.style.set_properties(subset=['A', 'C'], **{'background-color': 'green'})

Result:

enter image description here

Mykola Zotko
  • 15,583
  • 3
  • 71
  • 73