Sfspace
Sfspace

Reputation: 53

Heatmap on only a part of the dataframe?

I'm trying to make a heatmap plot but would like to omit the first row from it. So that I have a table where the first row wouldn't have any background colour. Somewhat like this paint example

But I'm not even sure if that is possible. I've tried making a mulitIndex as a column so that the first row would become a part of the column name, but I want the row name, 'fixed' to still be there. Is it even possible?

This is what I'm working with so far. I would appreciate any input!

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import seaborn as sns

SO = pd.DataFrame(np.random.randint(100,size=(4,5)))
SO.iloc[0] = [5, 10, 15, 10, 5]
SO.index = ['fixed','val1', 'sd2', 'val2']
SO.columns = ['Prod1', 'Prod2', 'Prod3', 'Prod4', 'Prod5']

sns.set(font_scale=1.5)
fig, ax = plt.subplots(figsize=(20,10))
ax = sns.heatmap(SO, annot=True, fmt="", cbar=False, cmap="RdYlGn", vmin=0, vmax=100)
plt.tick_params(axis='both', which='major', labelsize=19, labelbottom = False, bottom=False, top = False, labeltop=True)

Upvotes: 5

Views: 2527

Answers (2)

BhishanPoudel
BhishanPoudel

Reputation: 17144

The masking idea of Stupid Wolf is great, but if you are looking for simpler ways you can simply incorporate the first row in the column names and plot the heatmap as usual.

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import seaborn as sns

SO = pd.DataFrame(np.random.randint(100,size=(4,5)))
SO.iloc[0] = [5, 10, 15, 10, 5]
SO.index = ['fixed','val1', 'sd2', 'val2']
SO.columns = ['Prod1', 'Prod2', 'Prod3', 'Prod4', 'Prod5']
first_row = [str(i) for i in SO.iloc[0]]
labels = [i + '\n' + j for i,j in zip(SO.columns, first_row)]

sns.set(font_scale=1.5)
fig, ax = plt.subplots(figsize=(20,10))
ax = sns.heatmap(SO.iloc[1:], annot=True, fmt="", cbar=False, cmap="RdYlGn",
                 vmin=0, vmax=100)

ax.set_xticklabels(labels)
plt.tick_params(axis='both', which='major', labelsize=19,
                labelbottom = False, bottom=False, top = False, labeltop=True)

Result

enter image description here

Upvotes: 2

StupidWolf
StupidWolf

Reputation: 46898

A quick solution, is to plot your first row first, masking the rest, then plot over with the inverse:

This is the mask, where the first row is masked:

MASK = SO.apply(lambda x:np.arange(len(x))==0)

        Prod1   Prod2   Prod3   Prod4   Prod5
fixed   True    True    True    True    True
val1    False   False   False   False   False
sd2     False   False   False   False   False
val2    False   False   False   False   False

Set a colour for the first row:

COL = [(0.9690888119953864, 0.9664744329104191, 0.9649365628604383)]

Then we plot:

sns.set(font_scale=1.5)
fig, ax = plt.subplots(figsize=(20,10))
sns.heatmap(SO, annot=True, fmt="", cbar=False, mask=~MASK,cmap=COL,vmin=0, vmax=100,ax=ax)
sns.heatmap(SO, annot=True, fmt="", cbar=False, mask=MASK,cmap="RdYlGn",vmin=0, vmax=100,ax=ax)

plt.tick_params(axis='both', which='major', labelsize=19, 
                labelbottom = False, bottom=False, top = False, labeltop=True)

enter image description here

Upvotes: 1

Related Questions