You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 08:23:01