31

The pandas style option to add a background gradient is great for quickly inspecting my output table. However, it is applied either row-wise or columns-wise. Would it be possible to apply it to the whole dataframe at once?

EDIT: A minimum working example:

df = pd.DataFrame([[3,2,10,4],[20,1,3,2],[5,4,6,1]])
df.style.background_gradient()
5
  • 4
    Did you try setting axis=None? Commented Aug 13, 2016 at 10:17
  • I did now, but it throws an error.. Good idea though ;-) Commented Aug 13, 2016 at 10:40
  • What kind of error? Could you share your code and a small snippet of the dataframe? Commented Aug 13, 2016 at 10:41
  • I added an example. The error message upon adding axis=None is: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all(). Commented Aug 13, 2016 at 10:49
  • From what I know, you can't set the background_gradient for both the rows/columns simultaneously. But however you could create a custom function and apply colors to a particular threshold of the values you want to distinguish them by. Commented Aug 13, 2016 at 11:51

4 Answers 4

32

Currently you can't set the background_gradient for both the rows/columns simultaneously as pointed by Nickil Maveli. The trick is to customize the pandas function background_gradient:

import pandas as pd
import matplotlib.pyplot as plt
from matplotlib import colors

def background_gradient(s, m, M, cmap='PuBu', low=0, high=0):
    rng = M - m
    norm = colors.Normalize(m - (rng * low),
                            M + (rng * high))
    normed = norm(s.values)
    c = [colors.rgb2hex(x) for x in plt.cm.get_cmap(cmap)(normed)]
    return ['background-color: %s' % color for color in c]

df = pd.DataFrame([[3,2,10,4],[20,1,3,2],[5,4,6,1]])
df.style.apply(background_gradient,
               cmap='PuBu',
               m=df.min().min(),
               M=df.max().max(),
               low=0,
               high=0.2)
Sign up to request clarification or add additional context in comments.

3 Comments

Thanks! Can I use the style in a loop? I have a Dictionary in which the value is dataFrame. I would like to loop through the Dictionary and Show the DataFrame with style. @Guilherme Beltramini
@JasonLi, if your dict with pandas.DataFrame is like this dict_dfs = {'df1': pd.DataFrame(...), 'df2': pd.DataFrame(...), ...}, you can do use from IPython.display import display and put display(df.style.apply(...)) inside a for-loop (e.g., for df in dict_dfs.values()) (obs.: since it's not possible to use block-formatting for code inside the comments, I had to simplify the examples, but I hope it's clear).
It works after upgrading pandas from 0.19 to 0.24. Thanks @Guiherme Beltramini
18

Setting axis=None is working for me in 1.0.5

Comments

15

You can use axis=None to get rid of the min and max computations in the call:

def background_gradient(s, m=None, M=None, cmap='PuBu', low=0, high=0):
    print(s.shape)
    if m is None:
        m = s.min().min()
    if M is None:
        M = s.max().max()
    rng = M - m
    norm = colors.Normalize(m - (rng * low),
                            M + (rng * high))
    normed = s.apply(norm)

    cm = plt.cm.get_cmap(cmap)
    c = normed.applymap(lambda x: colors.rgb2hex(cm(x)))
    ret = c.applymap(lambda x: 'background-color: %s' % x)
    return ret


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

Edit: You may need to use normed = s.apply(lambda x: norm(x.values)) for this to work on matplotlib 2.2

Comments

7

You need to set axis to None. For me best solution using seaborn:

import seaborn as sns
import pandas as pd
cm = sns.color_palette("blend:white,green", as_cmap=True)
df.style.background_gradient(cmap = cm,axis=None)

Comments

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.