将子图与 pyplot barplot 和 seaborn 热图对齐
Aligning subplots with a pyplot barplot and seaborn heatmap
我试图将 Seaborn 基于时间的热图放在条形图的顶部,指示每个 bin/timeframe 中的患者数量。我可以成功地制作一个单独的热图和条形图,但将两者结合起来并不能按预期工作。
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()
此代码为我提供了下图。如您所见,有两个问题:
- 条形图延伸得太远
- 第一个和第二个条形图没有与顶部图表对齐,其中第一个图的刻度也不与条形图的中心对齐。
我试过在线查找,但找不到解决问题的好资源。有什么想法吗?
一个问题是颜色条从热图中带走了 space,使其图比条形图窄。您可以创建一个 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
)。
我试图将 Seaborn 基于时间的热图放在条形图的顶部,指示每个 bin/timeframe 中的患者数量。我可以成功地制作一个单独的热图和条形图,但将两者结合起来并不能按预期工作。
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()
此代码为我提供了下图。如您所见,有两个问题:
- 条形图延伸得太远
- 第一个和第二个条形图没有与顶部图表对齐,其中第一个图的刻度也不与条形图的中心对齐。
我试过在线查找,但找不到解决问题的好资源。有什么想法吗?
一个问题是颜色条从热图中带走了 space,使其图比条形图窄。您可以创建一个 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
)。