如何在Seaborn中对齐KDE图和条形图?

0 投票
1 回答
40 浏览
提问于 2025-04-13 14:16

我在调整Seaborn的KDE图时遇到了一些麻烦,想把它和我的条形图对齐。虽然我尝试了很多方法,比如修改bw_adjust参数和手动缩放KDE图,但还是没能达到想要的效果。

我的目标是为数据框中的一列绘制KDE图和条形图,以便可视化数据分布,同时也能看到数据点与KDE的关系。条形图还用不同的颜色来分类数据。

首先,如果我单独绘制条形图,代码如下:

sns.stripplot(data=df, x="values", hue="category")

我得到的图是这样的: stripplot alone

然后,如果我单独绘制KDE图,代码如下:

sns.kdeplot(data=df, x="values", ax=ax)

我得到的图是这样的: kde plot alone

但是,当我尝试把两者结合在一起时,代码如下:

fig, ax = plt.subplots(figsize=(16, 8))
sns.stripplot(data=df, x="values", hue="category")
sns.kdeplot(data=df, x="values", ax=ax)

我得到的图是这样的: kde and strip plots together

奇怪的是,当KDE图和条形图一起绘制时,KDE图竟然变成了倒置的,我不太明白为什么会这样。所以我有两个问题想要解决:

  1. 把KDE图倒置回来,让它看起来像单独绘制时的样子。
  2. 正确缩放KDE图(或条形图),让数据点能和KDE图很好地结合在一起。

首先,我尝试在seaborn的stripplot和kdeplot函数中更改一些参数,代码如下:

sns.stripplot(data=df, x="values", hue="category", jitter=0.1, dodge=True, ax=ax)
sns.kdeplot(data=df, x="values", ax=ax, bw_adjust=-1)

看起来把bw_adjust设置为负数解决了第一个问题,结果如下(虽然我不太明白为什么这样有效): first try

不过,条形图的数据点仍然没有很好地表示出来,我不确定如何正确缩放KDE图,以便与条形图的数据更好地匹配。

所以,为了解决这个问题,我尝试手动绘制KDE图(不使用seaborn):

import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np
from scipy.stats import gaussian_kde


df = pd.read_csv("inputs/desired_data.csv")
fig, ax = plt.subplots(figsize=(16, 8))
# Strip plot
sns.stripplot(data=df, x="values", hue="category", jitter=0.1, dodge=True, ax=ax)

# Computing KDE manually
x = df["values"].values
kde = gaussian_kde(x, bw_method=1)
x_grid = np.linspace(x.min(), x.max(), 1000)
y = kde.evaluate(x_grid)

# Normalize and scale the KDE plot
y_scaled = y / y.max()  # Example normalization, adjust as needed

# Plot the scaled KDE
ax.plot(x_grid, y_scaled, color='blue')

用这段代码,我得到的图是这样的: Plot with manual KDE 1

这样在可视化数据点方面效果更好。但是,KDE图又变成了倒置的。如果我把bw_method=1改成bw_method=-1,在kde = gaussian_kde(x, bw_method=1)中,我得到的图是这样的: Plot with manual KDE 2

结果又变得更糟了。理想情况下,我希望得到这样的图: enter image description here

1 个回答

1

你想要画一个有点特别的图。stripplot 是把y轴翻转了,并且把范围设置在 -0.50.5 之间。而 kdeplot 则把y轴的最小值设置为0(这样它就“坐”在x轴上),而且它的高度是为了让曲线下面的面积标准化为 1

最简单的方法是使用双轴。把 kdeplot 画在原来的轴上,这样左边的y轴就会显示 kdeplot 的高度。stripplot 可以放在双轴上,y轴是独立的。

下面是一些示例代码:

import  seaborn as sns
import matplotlib.pyplot as plt
iris = sns.load_dataset('iris')
fig, ax = plt.subplots()
sns.kdeplot(iris, x='sepal_width', ax=ax)
ax2 = ax.twinx()
sns.stripplot(iris, x='sepal_width', hue='species', ax=ax2, palette='turbo', dodge=True)
plt.tight_layout()
plt.show()

结合kdeplot和stripplot

撰写回答