Use center diverging colormap in a pandas dataframe heatmap display
Asked Answered
D

2

7

I would like to use a diverging colormap to color the background of a pandas dataframe. The aspect that makes this trickier than one would think is the centering. In the example below, a red to blue colormap is used, but the middle of the colormap isn't used for values around zero. How to create a centered background color display where zero is white, all negatives are a red hue, and all positives are a blue hue?

import pandas as pd
import numpy as np
import seaborn as sns

np.random.seed(24)
df = pd.DataFrame()
df = pd.concat([df, pd.DataFrame(np.random.randn(10, 4)*10, columns=list('ABCD'))],
               axis=1)
df.iloc[0, 2] = 0.0
cm = sns.diverging_palette(5, 250, as_cmap=True)
df.style.background_gradient(cmap=cm).set_precision(2)

enter image description here

The zero in the above display has a red hue and the closest to white background is used for a negative number.

Decurrent answered 4/1, 2020 at 3:19 Comment(1)
I think the background_gradient function is applying the colormap row by row, you need to apply it to the overall dataframe. This answer might help you: https://mcmap.net/q/467992/-pandas-style-background-gradient-both-rows-and-columnsChane
C
5
import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
from matplotlib import colors

np.random.seed(24)
df = pd.DataFrame()
df = pd.concat([df, pd.DataFrame(np.random.randn(10, 4)*10, columns=list('ABCD'))],
               axis=1)
df.iloc[0, 2] = 0.0
cm = sns.diverging_palette(5, 250, as_cmap=True)

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]

even_range = np.max([np.abs(df.values.min()), np.abs(df.values.max())])
df.style.apply(background_gradient,
               cmap=cm,
               m=-even_range,
               M=even_range).set_precision(2)

centered diverging colormap dataframe background

Chane answered 5/1, 2020 at 4:3 Comment(0)
J
0

The following is a bit easier to follow and uses matplotlib built in normalizer.

import pandas as pd
import numpy as np
import seaborn as sns
from matplotlib import colors

np.random.seed(24)
df = pd.DataFrame()
df = pd.concat([df, pd.DataFrame(np.random.randn(10, 4)*10, columns=list('ABCD'))],
               axis=1)
df.iloc[0, 2] = 0.0
cm = sns.diverging_palette(5, 250, as_cmap=True)
divnorm = colors.TwoSlopeNorm(vmin=df.values.min(), vcenter=0, vmax=df.values.max())
df.style.background_gradient(cmap=cm, axis=None, vmin=0, vmax=1, gmap=df.apply(divnorm)).format(precision=2)

resulting table

The use of vmin=0, vmax=1 is to make sure the mapping uses those values as reference to lowest and highest color map values, instead of the actual data points, since we mapped all the original values of the data to this range. For reference, here are the mapped normalized values that are used to determine the corresponding color in the cmap:

df.apply(divnorm).style.background_gradient(cmap=cm, axis=None, gmap=df.apply(divnorm)).format(precision=2)

enter image description here

Johnsten answered 16/11, 2023 at 12:21 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.