如何用Matplotlib/Seaborn/Plotly绘制带1σ区间占比标签的正态分布图
在正态分布图中添加1σ区间占比标签的实现方法
我来帮你搞定这个需求!要在正态分布图上给每个1σ区间加上占比标签,用Matplotlib、Seaborn或者Plotly都能实现,下面给你一步步拆解每个库的做法:
一、使用Matplotlib实现
咱们在你原有代码的基础上扩展,核心是计算各σ区间的概率占比,然后填充区间并添加标签:
import numpy as np import matplotlib.pyplot as plt from scipy import stats # 生成示例数据(你可以替换成自己的data) np.random.seed(42) data = np.random.normal(loc=10, scale=2, size=1000) # 计算均值和标准差 hmean = np.mean(data) hstd = np.std(data) # 生成用于绘制PDF的x轴数据(比原始数据更平滑) x = np.linspace(hmean - 3*hstd, hmean + 3*hstd, 1000) pdf = stats.norm.pdf(x, hmean, hstd) # 创建画布 plt.figure(figsize=(10, 6)) plt.plot(x, pdf, 'k-', linewidth=2, label='正态分布PDF') # 定义各σ区间的边界和对应的占比(正态分布的经典数值) sigma_intervals = [ (hmean - 3*hstd, hmean - 2*hstd, 0.1359), (hmean - 2*hstd, hmean - 1*hstd, 13.59), (hmean - 1*hstd, hmean, 34.13), (hmean, hmean + 1*hstd, 34.13), (hmean + 1*hstd, hmean + 2*hstd, 13.59), (hmean + 2*hstd, hmean + 3*hstd, 0.1359) ] # 对应区间的填充颜色 colors = ['#f0f0f0', '#d9d9d9', '#bdbdbd', '#bdbdbd', '#d9d9d9', '#f0f0f0'] # 遍历每个区间,填充面积并添加标签 for (left, right, pct), color in zip(sigma_intervals, colors): # 填充区间面积 plt.fill_between(x, 0, pdf, where=(x >= left) & (x <= right), color=color) # 计算标签位置(区间中点的x,PDF曲线在中点的y值上方) mid_x = (left + right) / 2 mid_y = stats.norm.pdf(mid_x, hmean, hstd) + 0.002 # 添加占比标签,保留两位小数 plt.text(mid_x, mid_y, f'{pct:.2f}%', ha='center', fontsize=10) # 添加均值线和标注 plt.axvline(hmean, color='red', linestyle='--', label=f'均值 (μ={hmean:.2f})') plt.text(hmean, max(pdf)*0.9, 'μ', ha='center', color='red', fontsize=12) # 添加σ刻度标注 plt.axvline(hmean + hstd, color='blue', linestyle=':', label=f'±1σ (σ={hstd:.2f})') plt.axvline(hmean - hstd, color='blue', linestyle=':') plt.text(hmean + hstd, max(pdf)*0.8, 'μ+σ', ha='center', color='blue', fontsize=10) plt.text(hmean - hstd, max(pdf)*0.8, 'μ-σ', ha='center', color='blue', fontsize=10) plt.xlabel('数据值') plt.ylabel('概率密度') plt.title('带1σ区间占比标签的正态分布图') plt.legend() plt.grid(alpha=0.3) plt.show()
关键说明:
- 用
fill_between函数填充每个σ区间的面积,通过where参数指定区间范围 - 正态分布的区间占比是固定的(±1σ占68.26%,拆分到左右各34.13%),也可以用
stats.norm.cdf(right, hmean, hstd) - stats.norm.cdf(left, hmean, hstd)动态计算 text函数的位置要调整到曲线上方,保证标签不被遮挡
二、使用Seaborn实现
Seaborn是基于Matplotlib的封装,我们可以先绘制核密度曲线,再复用Matplotlib的填充和标签逻辑:
import numpy as np import seaborn as sns import matplotlib.pyplot as plt from scipy import stats # 生成示例数据 np.random.seed(42) data = np.random.normal(loc=10, scale=2, size=1000) hmean = np.mean(data) hstd = np.std(data) x = np.linspace(hmean - 3*hstd, hmean + 3*hstd, 1000) pdf = stats.norm.pdf(x, hmean, hstd) # 创建画布,绘制Seaborn核密度曲线 plt.figure(figsize=(10, 6)) sns.kdeplot(data, fill=False, color='black', linewidth=2, label='核密度估计') # 同样添加区间填充和标签,逻辑和Matplotlib一致 sigma_intervals = [ (hmean - 3*hstd, hmean - 2*hstd, 0.1359), (hmean - 2*hstd, hmean - 1*hstd, 13.59), (hmean - 1*hstd, hmean, 34.13), (hmean, hmean + 1*hstd, 34.13), (hmean + 1*hstd, hmean + 2*hstd, 13.59), (hmean + 2*hstd, hmean + 3*hstd, 0.1359) ] colors = ['#f0f0f0', '#d9d9d9', '#bdbdbd', '#bdbdbd', '#d9d9d9', '#f0f0f0'] for (left, right, pct), color in zip(sigma_intervals, colors): plt.fill_between(x, 0, pdf, where=(x >= left) & (x <= right), color=color) mid_x = (left + right) / 2 mid_y = stats.norm.pdf(mid_x, hmean, hstd) + 0.002 plt.text(mid_x, mid_y, f'{pct:.2f}%', ha='center', fontsize=10) # 添加辅助线和标注 plt.axvline(hmean, color='red', linestyle='--', label=f'均值 (μ={hmean:.2f})') plt.axvline(hmean + hstd, color='blue', linestyle=':') plt.axvline(hmean - hstd, color='blue', linestyle=':') plt.xlabel('数据值') plt.ylabel('概率密度') plt.title('Seaborn绘制带1σ区间占比标签的正态分布图') plt.legend() plt.grid(alpha=0.3) plt.show()
关键说明:
- Seaborn的
kdeplot可以快速生成平滑的密度曲线,如果你想直接用正态分布的PDF,也可以替换成plt.plot(x, pdf) - 后续的区间填充和标签逻辑完全和Matplotlib通用,不用额外调整
三、使用Plotly实现(交互式图表)
Plotly可以生成交互式的正态分布图,操作逻辑略有不同,通过添加形状和注释来实现:
import numpy as np import plotly.graph_objects as go from scipy import stats # 生成示例数据 np.random.seed(42) data = np.random.normal(loc=10, scale=2, size=1000) hmean = np.mean(data) hstd = np.std(data) x = np.linspace(hmean - 3*hstd, hmean + 3*hstd, 1000) pdf = stats.norm.pdf(x, hmean, hstd) # 创建Figure对象 fig = go.Figure() # 添加PDF曲线 fig.add_trace(go.Scatter( x=x, y=pdf, mode='lines', line=dict(color='black', width=2), name='正态分布PDF' )) # 定义σ区间和占比 sigma_intervals = [ (hmean - 3*hstd, hmean - 2*hstd, 0.1359, '#f0f0f0'), (hmean - 2*hstd, hmean - 1*hstd, 13.59, '#d9d9d9'), (hmean - 1*hstd, hmean, 34.13, '#bdbdbd'), (hmean, hmean + 1*hstd, 34.13, '#bdbdbd'), (hmean + 1*hstd, hmean + 2*hstd, 13.59, '#d9d9d9'), (hmean + 2*hstd, hmean + 3*hstd, 0.1359, '#f0f0f0') ] # 添加每个区间的填充形状 for left, right, pct, color in sigma_intervals: fig.add_shape( type='rect', x0=left, x1=right, y0=0, y1=max(pdf), fillcolor=color, opacity=0.5, line=dict(width=0) ) # 添加占比注释 mid_x = (left + right) / 2 mid_y = stats.norm.pdf(mid_x, hmean, hstd) + 0.002 fig.add_annotation( x=mid_x, y=mid_y, text=f'{pct:.2f}%', showarrow=False, font=dict(size=10) ) # 添加均值线 fig.add_vline(x=hmean, line_dash='dash', line_color='red', annotation_text=f'μ={hmean:.2f}', annotation_position='top right') # 添加±1σ线 fig.add_vline(x=hmean + hstd, line_dash='dot', line_color='blue', annotation_text='μ+σ', annotation_position='top right') fig.add_vline(x=hmean - hstd, line_dash='dot', line_color='blue', annotation_text='μ-σ', annotation_position='top right') # 配置图表布局 fig.update_layout( title='带1σ区间占比标签的交互式正态分布图', xaxis_title='数据值', yaxis_title='概率密度', height=600, width=1000, showlegend=True ) fig.show()
关键说明:
- 用
add_shape添加矩形填充区域,覆盖每个σ区间 add_annotation函数用来添加占比标签,支持更灵活的位置调整- 生成的图表是交互式的,可以缩放、悬停查看数值,体验更好
内容的提问来源于stack exchange,提问作者CYAN CEVI
相关产品推荐
相关产品推荐

