1

Migrating from python 2.7 to python 3.x, This code breaks Source:

pandas style background gradient both rows and columns

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

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 = pd.DataFrame([[3,2,10.3,4],[20,1,3.5,2],[5,4,6.9,1]])
df.style.apply(background_gradient, axis=None)

This is last line of stack trace:

TypeError: ("float() argument must be a string or a number, not 'SingleBlockManager'", 'occurred at index 0')
Merlin
  • 24,552
  • 41
  • 131
  • 206
  • This has nothing to do with python2 or 3 because the shown code also does not work in python 2 for me. First note that the other solution from the linked question runs fine. You may want to compare the versions of jupyter, IPython, pandas to see which are different and possibly responsible for this breaking. – ImportanceOfBeingErnest Mar 27 '18 at 16:57
  • The code shown works fine for me on Python 3.6; probably an issue of package versions. – root Mar 27 '18 at 16:59
  • @root --- what versions are you running? pandas. matplotlib... jupyter?? – Merlin Mar 27 '18 at 17:26
  • 1
    pandas 0.22.0; matplotlib 2.0.2; jupyter 1.0.0; notebook 5.4.1. Looks to be a matplotlib related incompatibility: upgraded to matplotlib 2.2.2 and was able to reproduce the error. – root Mar 27 '18 at 18:08

1 Answers1

2

Apparently you cannot call a matplotlib.colors.Normalize with a dataframe any more in matplotlib 2.2.

The solution would be to call it with the dataframe's values instead, changing normed = s.apply(norm) to

 normed = s.apply(lambda x: norm(x.values))

Full code

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

def background_gradient(s, m=None, M=None, cmap='PuBu', low=0, high=0):
    if m is None:
        m = s.min().min()
    if M is None:
        M = s.max().max()
    rng = M - m
    norm = colors.Normalize(m ,M)
    normed = s.apply(lambda x: norm(x.values))
    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 = pd.DataFrame([[3,2,10.3,4],[20,1,3.5,2],[5,4,6.9,1]])
df.style.apply(background_gradient, axis=None)

producing

enter image description here

ImportanceOfBeingErnest
  • 321,279
  • 53
  • 665
  • 712