Combining two heat maps in seaborn

Question:

I have 2 data tables with the dimensions 4x25. Each table is from a different point in time, but has exactly the same meta data, in essence the same column and row headers.

Given the large number of columns, I thought it best to represent this using a heatmap using the seaborn library for Python. However, I need to include both tables in the same plot. I am able to create a single heatmap representing a single data table as so.

df = pd.DataFrame(raw_data)
ax = sns.heatmap(df)
ax.set(yticklabels=labels)

However, I’m not sure how to combine two data tables into the same heatmap. The only way I can think of is to just create a new DataFrame of dimension 4x50 and then fit both tables into that one and plot that using the heatmap. But then, I need help with the following issues:

  1. I’m not sure how I’d draw a line down the middle of the heatmap to differentiate the data from the 2 tables. It’d be annoying for the reader to see where the columns start repeating to realize where the new data begins.
  2. An even better solution would be to apply 2 different coloring schemes for the 2 sets of data within the same heatmap instead of simply just drawing a line down the middle.

Any help with the above issues would be very helpful.

Note: I’m not bent on representing the data as I’ve suggested above or even using a heatmap. If there are other suggestions for plotting, please let me know.

Asked By: Jonathan

||

Answers:

One possible way of showing two seaborn heatmaps side by side in a figure would be to plot them to individual subplots. One may set the space between the subplots to very small (wspace=0.01) and position the respective colorbars and ticklabels outside of that gap.

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

df =  pd.DataFrame(np.random.rand(25,4), columns=list("ABCD"))
df2 = pd.DataFrame(np.random.rand(25,4), columns=list("WXYZ"))

fig, (ax,ax2) = plt.subplots(ncols=2)
fig.subplots_adjust(wspace=0.01)
sns.heatmap(df, cmap="rocket", ax=ax, cbar=False)
fig.colorbar(ax.collections[0], ax=ax,location="left", use_gridspec=False, pad=0.2)
sns.heatmap(df2, cmap="icefire", ax=ax2, cbar=False)
fig.colorbar(ax2.collections[0], ax=ax2,location="right", use_gridspec=False, pad=0.2)
ax2.yaxis.tick_right()
ax2.tick_params(rotation=0)
plt.show()

enter image description here

The best part about matplotlib/seaborn libraries is that everything is plotted in the same figure until you clear it. You can use the mask argument in sns.heatmap to get a diagonal heatmap plot. To get a “mixed” heatmap, such that you can have two different types of data plotted with different colormaps, you can do something like this:

from sklearn.datasets import load_iris
import seaborn as sns
import pandas as pd
import numpy as np

data = load_iris()
df= pd.DataFrame(data.data,columns = data.feature_names)
df['target'] = data.target

df_0 = df[df['target']==0]
df_1 = df[df['target']==1]

df_0.drop('target',axis=1,inplace=True)
df_1.drop('target',axis=1,inplace=True)

matrix_0 = np.triu(df_0.corr())
matrix_1 = np.tril(df_1.corr())

import seaborn as sns
from mpl_toolkits.axes_grid1.axes_divider import make_axes_locatable
from mpl_toolkits.axes_grid1.colorbar import colorbar
sns.heatmap(df_0.corr(),annot=True,mask=matrix_0,cmap="BuPu")
sns.heatmap(df_1.corr(),annot=True,mask=matrix_1,cmap="YlGnBu")

Hope this is what your second idea was. Note that this will only work when you have same column names.

Mixed Heatmap on Iris Dataset

Answered By: Quark

A slight twist of Quark’s answer to avoid 0 values in the matrix that will cause those values showing the later cmap. We can compute boolean matrices to mask the upper/ lower triangle. More info here. Also added the limits of the cbars to fix the scale.

from sklearn.datasets import load_iris
import seaborn as sns
import pandas as pd
import numpy as np

data = load_iris()
df= pd.DataFrame(data.data,columns = data.feature_names)
df['target'] = data.target

df_0 = df[df['target']==0]
df_1 = df[df['target']==1]

df_0.drop('target',axis=1,inplace=True)
df_1.drop('target',axis=1,inplace=True)

mask_0 = np.zeros_like(df_0.corr(), dtype=np.bool_)
mask_0[np.tril_indices_from(mask_0)] = True
mask_1 = mask_0.T

import seaborn as sns
from mpl_toolkits.axes_grid1.axes_divider import make_axes_locatable
from mpl_toolkits.axes_grid1.colorbar import colorbar
sns.heatmap(df_0.corr(), annot=True, mask=mask_0, cmap="Blues", vmin=0, vmax=1)
sns.heatmap(df_1.corr(), annot=True, mask=mask_1, cmap="Greens", vmin=0, vmax=1)

2

Answered By: Miroslav Afanasyev