4

I have 2 data frames with identical indices/columns:

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

df_bool = pd.DataFrame({'A':[0, 1, 0, 0, 1],
                          'B':[0, 0, 1, 0, 0],
                          'C':[1, 1, 1, 0, 0]})

I want to apply a style function to df element-wise using df_bool as a mask.

This is the expected result:

expected results

Current failed function

def color_boolean(val):
  color =''
  if df_bool == 1:
    color = 'red'
  elif df_bool == 0:
    color = 'black'
  return f'color: {color}'

df.head().style.apply(color_boolean, axis=None)
ValueError: The truth value of a DataFrame is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().

2 Answers 2

3

You can also use np.where to convert df_bool into a DataFrame of styles based on the locations of 1 values (df_bool.eq(1)).

By setting axis=None to Styler.apply we can effectively apply styles to the entire DataFrame.

true_css = 'color:red'
false_css = '' # No Styles (Change if needed)

df.style.apply(
    lambda _: np.where(df_bool.eq(1), true_css, false_css),
    axis=None
)

Styled DataFrame with red colored text where df == 1 is True


Optional format to round and match shown output:

true_css = 'color:red'
false_css = ''

df.style.apply(
    lambda _: np.where(df_bool.eq(1), true_css, false_css),
    axis=None
).format(formatter='{:1g}')

Styled DataFrame with red text including formatted rounding


Imports (and versions):

import numpy as np  # 1.22.3
import pandas as pd  # 1.4.2
Sign up to request clarification or add additional context in comments.

1 Comment

df_bool.eq(1) is not really necessary, if it's zeros and ones. I.e., this will work: df.style.apply(lambda _: np.where(df_bool, 'color:red', None), axis=None).
2

You can use a function that ignores the input and simply uses the other DataFrame:

def color_boolean(val):
    return f'color: {"red" if val else "black"}'

df.style.apply(lambda _: df_bool.applymap(color_boolean), axis=None)

or:

df.style.apply(lambda c: df_bool[c.name].apply(color_boolean))

output:

dataframe style

2 Comments

Thanks, appreciate it! I'm trying to also add on an additional condition (mode of column). ``` def highlightMode(s): # Get mode of columns mode_ = s.mode().values # Apply style if the current value is mode return ['background-color: yellow' if v in mode_ else '' for v in s] ``` I'm a little confused on how to chain them together when one is using a separate df as a mask. Appreciate any advice, thanks!
There are several options. A simple one might be to generate a DataFrame of the styles and then use this single one to apply them. Or use numpy.select with the many conditions.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.