如何创建带有边缘直方图的热图(类似于联合图)?

Luk*_*rth 1 matplotlib heatmap seaborn

我想绘制二维标量数据,我通常会使用matplotlib.pyplot.imshow或来绘制sns.heatmap。考虑这个例子:

data = [[10, 20, 30], [50, 50, 100], [80, 60, 10]]
fix, ax = plt.subplots()
ax.imshow(data, cmap=plt.cm.YlGn)
Run Code Online (Sandbox Code Playgroud)

3x3 imshow 绘图

现在我还想在顶部和右侧有一维条形图,显示每列/行中的值的总和 - 就像那样sns.jointplot。然而,sns.jointplot似乎只适用于分类数据,生成直方图(带有kind='hist')、散点图等 - 如果我想直接指定单元格的值,我不知道如何使用它。对于seaborn 来说这样的事情可能吗?

我的图中的轴y将是天(一个月内),x轴将是小时。我的数据如下所示:

包含小时、日期和值的 DataFrame

该字段Cost Difference应构成图中相应字段的阴影。

Joh*_*anC 8

这是一种方法,首先创建一个虚拟对象jointplot,然后使用其轴添加热图和总和条形图。

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

D = 28
H = 24
df = pd.DataFrame({'day': np.repeat(range(1, D + 1), H),
                   'hour': np.tile(range(H), D),
                   'Cost Dif.': np.random.uniform(10, 1000, D * H)})
# change the random df to have some rows/columns stand out (debugging, checking)
df.loc[df['hour'] == 10, 'Cost Dif.'] = 150
df.loc[df['hour'] == 12, 'Cost Dif.'] = 250
df.loc[df['day'] == 20, 'Cost Dif.'] = 800

g = sns.jointplot(data=df, x='day', y='hour', kind='hist', bins=(D, H))
g.ax_marg_y.cla()
g.ax_marg_x.cla()
sns.heatmap(data=df['Cost Dif.'].to_numpy().reshape(D, H).T, ax=g.ax_joint, cbar=False, cmap='Blues')

g.ax_marg_y.barh(np.arange(0.5, H), df.groupby(['hour'])['Cost Dif.'].sum().to_numpy(), color='navy')
g.ax_marg_x.bar(np.arange(0.5, D), df.groupby(['day'])['Cost Dif.'].sum().to_numpy(), color='navy')

g.ax_joint.set_xticks(np.arange(0.5, D))
g.ax_joint.set_xticklabels(range(1, D + 1), rotation=0)
g.ax_joint.set_yticks(np.arange(0.5, H))
g.ax_joint.set_yticklabels(range(H), rotation=0)

# remove ticks between heatmao and histograms
g.ax_marg_x.tick_params(axis='x', bottom=False, labelbottom=False)
g.ax_marg_y.tick_params(axis='y', left=False, labelleft=False)
# remove ticks showing the heights of the histograms
g.ax_marg_x.tick_params(axis='y', left=False, labelleft=False)
g.ax_marg_y.tick_params(axis='x', bottom=False, labelbottom=False)

g.fig.set_size_inches(20, 8)  # jointplot creates its own figure, the size can only be changed afterwards
# g.fig.subplots_adjust(hspace=0.3) # optionally more space for the tick labels
g.fig.subplots_adjust(hspace=0.05, wspace=0.02)  # less spaced needed when there are no tick labels
plt.show()
Run Code Online (Sandbox Code Playgroud)

示例图