首页 > 解决方案 > 使用热图居中表格

问题描述

我正在尝试在 seaborn 热图下添加一个 matplotlib 表。我已经能够绘制它们,但对齐没有运气。

# Main data
df = pd.DataFrame({"A": [20, 10, 7, 39], 
                   "B": [1, 8, 12, 9], 
                   "C": [780, 800, 1200, 250]})

# It contains min and max values for the df cols
df_info =  pd.DataFrame({"A": [22, 35], 
                   "B": [5, 10], 
                   "C": [850, 900]})

df_norm = (df - df.min())/(df.max() - df.min())


# Plot the heatmap
vmin = df_norm.min().min()
vmax = df_norm.max().max()

fig, (ax1, ax2) = plt.subplots(nrows=2, sharex=True)
sns.heatmap(df_norm, ax=ax1, annot=df, cmap='RdBu_r', cbar=True)

当我将表格添加到表格时,ax2它会绘制热图的所有宽度(包括彩条)。我已经尝试了 or 的所有可能组合,locbbox我无法将表格准确居中并赋予其与顶部热图相同的宽度(整个表格的宽度以及单个单元格的宽度)。

table = df_info
cell_text = []
for row in range(len(table)):
    cell_text.append(table.iloc[row])

ax2.axis('off')
ax2.table(cellText=cell_text,
          rowLabels=table.index,
          colLabels=None,
          loc='center')

在此处输入图像描述

有时我也会将参数传递给热图square=True以打印平方单元格,结果是这样的:

在此处输入图像描述

问题:如何将表格及其单元格附加到热图中并将其居中?

编辑:从技术上讲, tdy 的答案对于解决我的简单示例的问题是正确的。尽管我可能过度简化了它并遗漏了一条重要信息。
在我的真实案例场景中,如果我使用以下命令创建图形:

fig, (ax1, ax2) = plt.subplots(nrows=2,
                               **{"figsize": (18, 18),
                                  "dpi": 200,
                                  "tight_layout": True})

并应用上面提到的答案,我得到了这样的东西:

在此处输入图像描述

表格在底部远且比热图更宽的地方。

另外,如果我设置tight_layout=False我会获得一个宽度正确但底部仍然很远的表格:

fig, (ax1, ax2) = plt.subplots(nrows=2,
                               **{"figsize": (18, 18),
                                  "dpi": 200,
                                  "tight_layout": False})

在此处输入图像描述

我想在我的情况下"figsize": (18, 18)tight_layout我的问题有很大的影响,但我既不知道为什么也不知道如何解决它。

标签: pythonpandasmatplotlibseabornheatmap

解决方案


短方法

您可以使用 移动/调整表格大小Axes.set_position()left///参数可以根据需要进行调整bottomwidthheight

bbox1 = ax1.get_position()
bbox2 = ax2.get_position()

# modify as needed
left = bbox1.x0
bottom = bbox1.y0 - (bbox2.height * 0.8)
width = bbox1.x0 + (bbox1.width * 0.8)
height = bbox2.height

ax2.set_position([left, bottom, width, height])

热图和表格与 set_position 对齐


更长的方法

如果简单的方法效果不佳,请尝试height_ratios通过gridspec_kwin设置轴plt.subplots()。我还需要设置tight_layout=False.

用于设置(热图:表格)height_ratios的比例,并根据需要使用变量调整表格的大小/位置。这些值适用于我的系统,但您可以针对您的系统进行调整:ax1:ax2*_offset

### modify these params as needed ###

height_ratios = (20, 1) # heatmap:table ratio (20:1)
left_offset = 0         # table left position adjustment
bottom_offset = -0.025  # table bottom position adjustment
width_offset = -0.0005  # table width adjustment
height_offset = 0       # table height adjusment

#####################################

fig_kw = dict(figsize=(18, 18), dpi=200, tight_layout=False)
gridspec_kw = dict(height_ratios=height_ratios)
fig, (ax1, ax2) = plt.subplots(nrows=2, gridspec_kw=gridspec_kw, **fig_kw)

sns.heatmap(df_norm, ax=ax1, annot=df, cmap='RdBu_r', cbar=True)
ax2.table(cellText=[df_info.iloc[row] for row in range(len(df_info))],
          rowLabels=table.index,
          colLabels=None,
          loc='center')
ax2.axis('off')

bbox1 = ax1.get_position()
bbox2 = ax2.get_position()

left = bbox1.x0 + left_offset
bottom = bbox1.y0 - bbox2.height + bottom_offset
width = bbox1.width + width_offset
height = bbox2.height + height_offset

ax2.set_position([left, bottom, width, height])

热图和表格与 gridspec_kw 和 set_position 对齐


推荐阅读