如何在双张子图中为KDE曲线下区域着色?解决索引错误
在双张子图中为KDE曲线特定区间添加着色
问题解决代码
方法1:基于Seaborn绘图对象获取KDE数据
这种方法保留Seaborn的默认绘图风格,先绘制KDE曲线,再提取线条数据进行区间填充:
import numpy as np import matplotlib.pyplot as plt import seaborn as sns fig, axs = plt.subplots(1, 2, figsize=(11, 4.5)) N = 500 X = np.concatenate((np.random.normal(0, 1, int(0.3 * N)), np.random.normal(5, 1, int(0.7 * N)))) # 先绘制无填充的KDE曲线,确保线条被正确添加到轴对象 sns.kdeplot(data=X, linewidth=2, ax=axs[0]) # 获取KDE曲线的坐标数据 kde_line = axs[0].get_lines()[-1] kde_x, kde_y = kde_line.get_data() # 定义需要着色的x区间 mask = (kde_x > 1.8) & (kde_x < 3.2) # 填充目标区间,可自定义颜色和透明度 axs[0].fill_between(kde_x[mask], kde_y[mask], color="#1f77b4", alpha=0.3) # 绘制ECDF子图 sns.ecdfplot(X, stat='proportion', ax=axs[1]) plt.show()
方法2:手动计算KDE(更可靠,不依赖绘图对象内部结构)
通过scipy.stats.gaussian_kde直接计算核密度估计,完全控制绘图流程:
import numpy as np import matplotlib.pyplot as plt import seaborn as sns from scipy.stats import gaussian_kde fig, axs = plt.subplots(1, 2, figsize=(11, 4.5)) N = 500 X = np.concatenate((np.random.normal(0, 1, int(0.3 * N)), np.random.normal(5, 1, int(0.7 * N)))) # 手动计算KDE kde = gaussian_kde(X) # 生成覆盖数据范围的x轴采样点 kde_x = np.linspace(X.min() - 1, X.max() + 1, 1000) kde_y = kde(kde_x) # 绘制KDE曲线 axs[0].plot(kde_x, kde_y, linewidth=2, color="#1f77b4") # 填充目标区间 mask = (kde_x > 1.8) & (kde_x < 3.2) axs[0].fill_between(kde_x[mask], kde_y[mask], color="#1f77b4", alpha=0.3) # 绘制ECDF子图 sns.ecdfplot(X, stat='proportion', ax=axs[1]) plt.show()
错误原因解释
你参考的单图代码中调用了两次sns.kdeplot,第二次调用会在轴上新增一条KDE曲线,因此ax.get_lines()[-1]能获取到有效线条对象。但你的代码只调用了一次kdeplot且设置了fill=True:
- 在部分Seaborn版本中,
fill=True会优先创建填充多边形(PolyCollection),而KDE线条可能未被加入get_lines()列表,导致列表为空,触发IndexError。 - 即使线条存在,直接使用
fill=True会填充整个曲线下区域,和你需要的「特定区间着色」需求不符。
内容的提问来源于stack exchange,提问作者user22098830
相关产品推荐
相关产品推荐

