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

Ric*_*ram 1 python statistics histogram kernel-density seaborn

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

我想sns.displot在 Seaborn 中使用>= 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')
Run Code Online (Sandbox Code Playgroud)

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

seaborn_tips_dataset_dist

Joh*_*anC 6

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

要创建组合图,您可以使用底层轴级函数: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()
Run Code Online (Sandbox Code Playgroud)

结果图

编辑:

正如评论中提到的,y 轴未对齐。左轴仅说明有关直方图的一些信息。12.618例如,高度为 68 的最高垃圾箱意味着和之间总共有 68 张钞票17.392。右轴仅说明有关 kde 的信息。0.043例如,y 值为x=20表示总帐单介于19.5和之间的概率约为 4.3% 20.5

为了与 类似地对齐两者sns.histplot(..., kde=True),可以计算直方图的面积(箱宽乘以数据值的数量)并将其用作缩放因子。当以像素为单位测量时,这种缩放将使直方图的面积和 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)
Run Code Online (Sandbox Code Playgroud)

缩放的 kde 图

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

  • 对图形级别/轴级别区别的很好解释,但如果您确实希望 KDE 曲线*位于*直方图之上,您应该将 `kde=True` 添加到 `histplot` (或 `displot`)调用中。确实,这不会给你两个 y 轴,但它们实际上并不等同于绘图所暗示的方式(限制是由 matplotlib 对艺术家的自动缩放设置的,而不是计数/密度之间的数学关系)和密度轴无论如何都无法真正解释。 (2认同)
  • 很好的阐述;您在编辑中完全正确地说明了密度值的解释。只是请其他人注意,“密度”作为 y 轴值很可能会被误解,因此在显示这样的图时要小心。 (2认同)