Reputation: 494
I have a DataFrame containing multiple features along with their associated t-test results and p-values. I aim to generate a combined heatmap in Python using Seaborn. In this heatmap, one section should display the features with normalized data using z-scores (to ensure visibility of both high and low values), while the other section should present the original t-test values and p-values.
I intend to create a single heatmap with distinct color schemes for each section to clearly differentiate between them. However, my attempts to plot two separate heatmaps and combine them have resulted in separate plots rather than a unified heatmap.
Could someone guide me on how to create a single combined heatmap where both sections appear attached?
Here's the code I've attempted so far: import pandas as pd import numpy as np import seaborn as sns import matplotlib.pyplot as plt from matplotlib import gridspec
# Example DataFrame
data = {
'Feature1': np.random.randn(10),
'Feature2': np.random.randn(10),
'Feature3': np.random.randn(10),
't test': np.random.randn(10),
'p value': np.random.rand(10)
}
df = pd.DataFrame(data)
# Drop the last two columns
df_heatmap = df.iloc[:, :-2]
# Calculate z-scores for the DataFrame
df_heatmap_zscore = (df_heatmap - df_heatmap.mean()) / df_heatmap.std()
# Set up the layout
fig = plt.figure(figsize=(12, 8))
gs = gridspec.GridSpec(1, 4, width_ratios=[1, 1, 0.05, 0.05]) # 4 columns: 2 for heatmaps, 2 for colorbars
# Heatmap for the DataFrame excluding t-test and p-value columns
ax1 = plt.subplot(gs[0])
sns.heatmap(df_heatmap_zscore, cmap='coolwarm', annot=True, cbar=False)
plt.title('Heatmap without t-test and p-value')
# Heatmap for t-test p-values
ax2 = plt.subplot(gs[1])
sns.heatmap(df[['t test', 'p value']], cmap='viridis', annot=True, fmt=".4f", cbar=False, ax=ax2)
plt.title('Heatmap for t-test p-values')
# Create a single colorbar for the z-score
cbar_ax1 = plt.subplot(gs[2])
cbar1 = plt.colorbar(ax1.collections[0], cax=cbar_ax1, orientation='vertical')
cbar1.set_label('Z-score')
# Create a single colorbar for the t-test p-values
cbar_ax2 = plt.subplot(gs[3])
cbar2 = plt.colorbar(ax2.collections[0], cax=cbar_ax2, orientation='vertical')
cbar2.set_label('p-value')
plt.tight_layout()
plt.show()
Is there a way to combine these heatmaps into a single plot, so they appear attached and have different color pattern and legend bar?
Upvotes: 1
Views: 155
Reputation: 5075
For the figure below I added each axis in sequence using fig.add_axes
(rather than gridspec
) as I'm more familiar with that method.
from matplotlib import pyplot as plt
import seaborn as sns
import pandas as pd
import numpy as np
# Example DataFrame
data = {
'Feature1': np.random.randn(10),
'Feature2': np.random.randn(10),
'Feature3': np.random.randn(10),
't test': np.random.randn(10),
'p value': np.random.rand(10)
}
df = pd.DataFrame(data)
# Drop the last two columns
df_heatmap = df.iloc[:, :-2]
# Calculate z-scores for the DataFrame
df_heatmap_zscore = (df_heatmap - df_heatmap.mean()) / df_heatmap.std()
# Set up the layout
fig = plt.figure(figsize=(12, 5))
heatmap1_width = 0.15
heatmap2_width = 0.1
cbar1_left_gap = 0.015
cbar2_left_gap = 0.06
cbar_width = 0.02
start_x = 0
heatmap_kwargs = dict(annot=True, cbar=False, annot_kws={'size': 9})
# Heatmap for the DataFrame excluding t-test and p-value columns
ax1 = fig.add_axes([start_x, 0, heatmap1_width, 1])
sns.heatmap(df_heatmap_zscore, cmap='coolwarm', ax=ax1, **heatmap_kwargs)
ax1.set_title('Heatmap without\nt-test and p-value\n' + '_'*24, fontsize=10)
start_x += heatmap1_width
# Heatmap for t-test p-values
ax2 = fig.add_axes([start_x, 0, heatmap2_width, 1])
sns.heatmap(df[['t test', 'p value']], cmap='viridis', fmt=".4f", ax=ax2, **heatmap_kwargs)
ax2.tick_params(axis='y', left=False, labelleft=False) #no ticks on ax2
ax2.set_title('Heatmap for\nt-test p-values\n' + '_'*16, fontsize=10)
start_x += heatmap2_width
#rotate if desired & remove tick marks
[ax.tick_params(axis='x', rotation=45, bottom=False) for ax in [ax1, ax2]]
#Colorbar 1
cax1 = fig.add_axes([start_x + cbar1_left_gap, 0, cbar_width, 1])
cbar1 = plt.colorbar(ax1.collections[0], cax=cax1, orientation='vertical')
cbar1.set_label('Z-score', size=9)
start_x += cbar1_left_gap + cbar_width
#Colorbar 2
cax2 = fig.add_axes([start_x + cbar2_left_gap, 0, cbar_width, 1])
cbar2 = plt.colorbar(ax2.collections[0], cax=cax2, orientation='vertical')
cbar2.set_label('p-value', size=9)
Upvotes: 1