使用单独的颜色条绘制多个 seaborn 热图

Plotting multiple seaborn heatmaps with individual color bar

是否可以将多个 seaborn 热图绘制成一个图形,具有共享的 yticklabel 和单独的颜色条,如下图所示?

我能做的是使用以下代码单独绘制热图:

#图1

plt.figure()
sns.set()
comp = sns.heatmap(df, cmap="coolwarm", linewidths=.5, xticklabels=True, yticklabels=True, cbar_kws={"orientation": "horizontal", "label": "Pathway completeness", "pad": 0.004})
comp.set_xticklabels(comp.get_xticklabels(), rotation=-90)
comp.xaxis.tick_top() # x axis on top
comp.xaxis.set_label_position('top')
cbar = comp.collections[0].colorbar
cbar.set_ticks([0, 50, 100])
cbar.set_ticklabels(['0%', '50%', '100%'])          
figure = comp.get_figure()
figure.savefig("hetmap16.png", format='png', bbox_inches='tight')

#图2(图3一样,只是数据库不同)

plt.figure()
sns.set()
df = pd.DataFrame(heatMapFvaMinDictP)
fvaMax = sns.heatmap(df, cmap="rocket_r", linewidths=.5, xticklabels=True, cbar_kws={"orientation": "horizontal", "label": "Minimum average flux", "pad": 0.004})
fvaMax.set_xticklabels(fvaMax.get_xticklabels(), rotation=-90)
fvaMax.xaxis.tick_top() # x axis on top
fvaMax.xaxis.set_label_position('top')
fvaMax.tick_params(axis='y', labelleft=False)
figure = fvaMax.get_figure()
figure.savefig("fva1.png", format='png', bbox_inches='tight')

Seaborn 建立在 matplotlib 之上,可用于进一步自定义图表。 plt.subplots(ncols=3, sharey=True, ...) 创建三个具有共享 y-axis 的子图。添加 ax=ax1sns.heatmap(..., ax=...) 在所需的子图上创建热图。请注意,sns.heatmap 的 return 值再次与 ax 相同。

以下代码显示了一个示例。 vminvmax 为第一个热图明确设置,以确保这两个值都将出现在颜色条中(默认颜色条在遇到的值的最小值和最大值之间运行)。

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

sns.set()
fig, (ax1, ax2, ax3) = plt.subplots(ncols=3, sharey=True, figsize=(20, 8))

N = 20
labels = [''.join(np.random.choice(list('abcdefghi '), 40)) for _ in range(N)]
df = pd.DataFrame({'column 1': np.random.uniform(0, 100, N), 'column 2': np.random.uniform(0, 100, N)},
                  index=labels)
sns.heatmap(df, cmap="coolwarm", linewidths=.5, xticklabels=True, yticklabels=True, ax=ax1, vmin=0, vmax=100,
            cbar_kws={"orientation": "horizontal", "label": "Pathway completeness", "pad": 0.004})
ax1.set_xticklabels(ax1.get_xticklabels(), rotation=-90)
ax1.xaxis.tick_top()  # x axis on top
ax1.xaxis.set_label_position('top')
cbar = ax1.collections[0].colorbar
cbar.set_ticks([0, 50, 100])
cbar.set_ticklabels(['0%', '50%', '100%'])

for ax in (ax2, ax3):
    max_value = 10 if ax == ax2 else 1000
    df = pd.DataFrame({'column 1': np.random.uniform(0, max_value, N), 'column 2': np.random.uniform(0, max_value, N)},
                      index=labels)
    sns.heatmap(df, cmap="rocket_r", linewidths=.5, xticklabels=True, ax=ax,
                cbar_kws={"orientation": "horizontal", "pad": 0.004,
                          "label": ("Minimum" if ax == ax2 else "Minimum") + " average flux"})
    ax.set_xticklabels(ax.get_xticklabels(), rotation=-90)
    ax.xaxis.tick_top()  # x axis on top
    ax.xaxis.set_label_position('top')

plt.tight_layout()
fig.savefig("subplots.png", format='png', bbox_inches='tight')
plt.show()

您可以连接两个数据帧并使用 FacetGridFacetGrid.map_dataframe,我想您可能需要稍微调整一下美学。没有你的数据,所以我用示例数据试试:

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

np.random.seed(111)
df1 = pd.DataFrame({'A':np.random.randn(15),'B':np.random.randn(15)},
                   index=['row_variable'+str(i+1) for i in range(15)])

df2 = pd.DataFrame({'A':np.random.randn(15),'B':np.random.randn(15)},
                   index=['row_variable'+str(i+1) for i in range(15)])

我们像您一样用指示数据库的列对 data.frames 进行注释,并为每个数据帧的配色方案设置字典:

df1['database'] = "database1"
df2['database'] = "database2"

dat = pd.concat([df1,df2])
cdict = {'database1':'rocket_r','database2':'coolwarm'}

并定义绘制热图的函数:

def heat(data,color):
    sns.heatmap(data[['A','B']],cmap=cdict[data['database'][0]],
                cbar_kws={"orientation": "horizontal"})

然后方面:

fg = sns.FacetGrid(data=dat, col='database',aspect=0.7,height=4)
fg.map_dataframe(heat)