如何在 Seaborn 中为同一图形上的直方图生成两个单独的 Y 轴

问题描述

我想生成一个具有两个 y 轴的图形:Count(来自直方图)和 Density(来自 KDE)。

我想在 Seaborn sns.displot 中使用 >= v 0.11

import seaborn as sns

df = sns.load_dataset('tips')

# graph 1: This should be the Y-Axis on the left side of the figure
sns.displot(df['total_bill'],kind='hist',bins=10)

# graph 2: This should be the Y-axis on the right side of the figure
sns.displot(df['total_bill'],kind='kde')

我编写的代码生成了两个独立的图形;我可以只对两个单独的图形使用一个分面网格,但我想更简洁,将两个单独网格上的两个 y 轴放在一个共享相同 x 轴的图形中。

seaborn_tips_dataset_dist

解决方法

displot() 是一个 figure-level function,它可以在一个图形内创建多个子图。因此,您无法控制各个轴。

要创建组合图,您可以使用底层轴级函数:histplot()kdeplot()(适用于 Seaborn v.0.11)。这些函数接受一个 ax= 参数。 twinx() 创建第二个 y 轴。

import matplotlib.pyplot as plt
import seaborn as sns

df = sns.load_dataset('tips')

fig,ax = plt.subplots()

sns.histplot(df['total_bill'],bins=10,ax=ax)

ax2 = ax.twinx()
sns.kdeplot(df['total_bill'],ax=ax2)

plt.tight_layout()
plt.show()

resulting plot

编辑:

如评论中所述,y 轴未对齐。左轴仅说明有关直方图的一些信息。例如。高度为 68 的最高 bin 意味着 12.61817.392 之间总共有 68 张钞票。右轴仅说明有关 kde 的一些信息。例如。 0.043x=20 y 值意味着总账单在 19.520.5 之间的概率约为 4.3%。

为了将两者对齐,类似于 sns.histplot(...,kde=True),可以计算直方图的面积(bin 宽度乘以数据值的数量)并用作缩放因子。当以像素为单位进行测量时,这种缩放会使直方图的面积和 kde 曲线下方的面积相等:

num_bins = 10
bin_width = (df['total_bill'].max() - df['total_bill'].min()) / num_bins
hist_area = len(df) * bin_width
ax2.set_ylim(ymax=ax.get_ylim()[1] / hist_area)

scaled kde plot

请注意,如果直方图使用 10 次幂的 bin 宽度(例如 sns.histplot(...,bins=np.arange(0,df['total_bill'].max()+10,10)),则右轴将更类似于百分比。哪些 bin 最合适很大程度上取决于您想如何解释数据。