Search code examples
pythonpandasdataframepandas-styles

How to style all cells in a row of a specific MultiIndex value in pandas


SETUP

I have the following df:

import pandas as pd
import numpy as np

arrays = [
    np.array(["fruit", "fruit", "fruit","vegetable", "vegetable", "vegetable"]),
    np.array(["one", "two", "total", "one", "two", "total"]),
]

df = pd.DataFrame(np.random.randn(6, 4), index=arrays)

df.index.set_names(['item','count'],inplace=True)

WHAT I AM TRYING TO DO

I am trying to style df so that each cell where count == 'total' is bolded.

WHAT I HAVE TRIED

I was able to index all rows where count == 'total' with the following code:

idx = pd.IndexSlice
totals = df.loc[idx[:, 'total'],:]

but when I try to apply a function:

def df_style(val):
    return "font-weight: bold"

df.style.applymap(df_style,subset=totals)

I get the following error:

KeyError: 0

How can I style this df so that all cells where count == 'total' are bolded?

Here is a similar question, albeit with just a regular index rather than MultiIndex.


Solution

  • Here's one approach:

    # used `np.random.seed(0)` for reproducibility
    
    def highlight_total(s):
        m = s.index.get_level_values('count') == 'total'
        return np.where(m, 'font-weight: bold', None)
        
    df.style.apply(highlight_total)
    

    Output:

    df with total rows in bold

    Explanation


    Specifically traversing the df row-wise, you could do:

    def highlight_total(s):
        return ['font-weight: bold']*len(s) if s.name[1] == 'total' else [None]*len(s)
        
    df.style.apply(highlight_total, axis=1)
    

    So, here we are accessing s.name[1], with name understood as ('fruit', 'total'), ('vegetable', 'total'), etc. Leads to the same result.