【问题标题】:Aligning subplots with a pyplot barplot and seaborn heatmap将子图与 pyplot 条形图和 seaborn 热图对齐
【发布时间】:2021-04-24 21:05:00
【问题描述】:

我正在尝试将 Seaborn 基于时间的热图放置在条形图的顶部,以指示每个 bin/时间范围内的患者数量。我可以成功地制作单独的热图和条形图,但是将两者结合起来并不能达到预期效果。

import pandas as pd
import numpy as np
import seaborn as sb
from matplotlib import pyplot as plt

# Mock data
patient_counts = [650, 28, 8]
missings_df = pd.DataFrame(np.array([[-15.8, 600/650, 580/650, 590/650],
                                     [488.2, 20/23, 21/23, 21/23],
                                     [992.2, 7/8, 8/8, 8/8]]),
                           columns=['time', 'Resp. (/min)', 'SpO2', 'Blood Pressure'])
missings_df.set_index('time', inplace=True)

# Plot heatmap
fig, (ax1, ax2) = plt.subplots(nrows=2, figsize=(26, 16), sharex=True, gridspec_kw={'height_ratios': [5, 1]})
sb.heatmap(missings_df.T, cmap="Blues", cbar_kws={"shrink": .8}, ax=ax1, xticklabels=False)
plt.xlabel('Time (hours)')

# Plot line graph under heatmap to show nr. of patients in each bin
x_ticks = [time for time in missings_df.index]
ax2.bar([i for i, _ in enumerate(x_ticks)], patient_counts, align='center')
plt.xticks([i for i, _ in enumerate(x_ticks)], x_ticks)

plt.show()

这段代码给了我下面的图表。如您所见,有两个问题:

  1. 条形图延伸得太远
  2. 第一个和第二个条形图未与顶部图形对齐,其中第一个图的刻度也不与条形图的中心对齐。

我尝试在网上查找,但找不到解决问题的好资源。有什么想法吗?

【问题讨论】:

  • 我想如果您创建一个 (2x2) 网格(或增加分辨率并将更大的部分分配给“左列”)并将颜色条绘制到单独的轴上以便于对齐热图和条形图。 (使用MVE 我本可以向您展示解决方案...)
  • @max 感谢您的评论,我已经修改了我的帖子。假设您已经安装了所有模块,现在应该可以复制和粘贴代码了。

标签: python matplotlib seaborn subplot


【解决方案1】:

一个问题是颜色条占用了热图中的空间,使其绘图比条形图更窄。您可以创建一个 2x2 网格来为颜色条腾出空间,并删除空的子图。将 sharex=True 更改为 sharex='col' 以防止颜色条与热图获得相同的 x 轴。

另一个问题是热图的单元格边界位于0, 1, 2, ... 位置,因此它们的中心位于0.5, 1.5, 2.5, ...。您可以将条形图放在这些中心而不是它们的默认位置:

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

fig, ((ax1, cbar_ax), (ax2, dummy_ax)) = plt.subplots(nrows=2, ncols=2, figsize=(26, 16), sharex='col',
                                                      gridspec_kw={'height_ratios': [5, 1], 'width_ratios': [20, 1]})
missings_df = np.random.rand(3, 3)
sns.heatmap(missings_df.T, cmap="Blues", cbar_ax=cbar_ax, xticklabels=False, linewidths=2, ax=ax1)

ax2.set_xlabel('Time (hours)')

patient_counts = np.random.randint(10, 50, 3)
x_ticks = ['Time1', 'Time2', 'Time3']
x_tick_pos = [i + 0.5 for i in range(len(x_ticks))]
ax2.bar(x_tick_pos, patient_counts, align='center')
ax2.set_xticks(x_tick_pos)
ax2.set_xticklabels(x_ticks)
dummy_ax.axis('off')

plt.tight_layout()
plt.show()

PS:注意不要将“功能”接口与“面向对象”接口混用到 matplotlib。所以,尽量不要使用plt.xlabel(),因为它并不明显会应用于“当前”斧头(问题代码中的ax2)。

【讨论】:

  • 太棒了!我怀疑那个传说是罪魁祸首,但我不认为整个右边会有那么多空白空间——即使那样我也不知道如何修复它。感谢您让我知识渊博
猜你喜欢
  • 1970-01-01
  • 2021-03-10
  • 1970-01-01
  • 2017-03-18
  • 1970-01-01
  • 2021-01-31
  • 1970-01-01
  • 2015-08-27
  • 2015-04-06
相关资源
最近更新 更多