# 教材位置：第4章，第4.3节；图 4-1。
# 单位、变量与形状：x 为 (6,)；观测使用一般测量单位，密度单位是测量单位的倒数。
# 学习目标：用均匀分布把“概率密度、区间概率、累积分布函数”联系起来。
# 核心数学关系：若 X ~ Uniform(a,b)，则区间内密度为 1/(b-a)，
# F(x) 在 [a,b] 内等于 (x-a)/(b-a)，方差为 (b-a)^2/12。
# 数据与输出：本例取区间 [2,6]，打印一点的密度和一段区间的概率，
# 并生成 e13_uniform.png；左图的阴影面积对应概率，右图展示 累积分布函数。
# 运行方式：安装 NumPy、SciPy、Matplotlib 后，在终端运行
# python e13_uniform.py；图片写入运行命令时的当前工作目录。

# NumPy 负责数组和浮点比较，SciPy 提供分布对象，Matplotlib 负责作图。
import numpy as np
from scipy import stats
import matplotlib.pyplot as plt
# 在创建第一幅图之前配置可跨系统选择的中文字体。
from plot_style import configure_chinese_plot

configure_chinese_plot()

# SciPy 的 uniform 用 loc 表示左端点，用 scale 表示区间宽度，
# 因而这里右端点是 loc + scale = 6；scale 不是右端点本身。
# “冻结”后的 rv 保存这组参数，后续 pdf、cdf、var 都针对同一个分布。
rv = stats.uniform(loc=2, scale=4)
# 长度为 6 的一维浮点数组；特意覆盖支持区间左侧、内部、边界和右侧。
# rv.cdf 接受整个数组并逐元素返回结果，不必手写循环。
x = np.array([0, 2, 3, 5, 6, 8], dtype=float)
# pdf(4)=1/4 是密度高度，而不是 P(X=4)；连续分布在单点的概率为 0。
print("x=4 处的概率密度：", rv.pdf(4))
# 区间概率是 累积分布函数 的差，也等于“宽度 2 × 密度 1/4”的面积。
# 连续分布的端点概率为零，因此这里开区间和闭区间的概率相同。
print("P(3<X<5):", rv.cdf(5) - rv.cdf(3))
# assert 将理论公式变成可执行的自检；浮点运算用 isclose 而非直接 ==。
assert np.isclose(rv.cdf(5) - rv.cdf(3), 0.5)
# 方差由区间宽度决定：4^2/12；平移区间不会改变方差。
assert np.isclose(rv.var(), 16 / 12)
# 创建一行两列子图；axes[0] 和 axes[1] 分别访问左右两个坐标轴。
fig, axes = plt.subplots(1, 2, figsize=(6.3, 2.8))
# 重复的横坐标 2、6 用于画密度函数的竖直边界，不代表边界处有概率质量。
axes[0].plot([0, 2, 2, 6, 6, 8], [0, 0, 0.25, 0.25, 0, 0])
# 在 3 到 5 之间填充至密度曲线的面积；alpha 是显示透明度。
axes[0].fill_between([3, 5], [0.25, 0.25], alpha=0.3)
# 累积分布函数 在区间左侧为 0，内部线性上升，区间右侧为 1。
# 这些采样点覆盖斜率变化处，所以连接后的折线能表达本例的完整 累积分布函数。
axes[1].plot(x, rv.cdf(x))
# 标注纵轴，帮助区分“密度高度”和“累计概率”这两种不同量。
axes[0].set(xlabel="x", ylabel="概率密度")
axes[1].set(xlabel="x", ylabel="累积分布函数")
# tight_layout 调整子图间距；savefig 按 160 dpi 保存图片。
fig.tight_layout()
fig.savefig("e13_uniform.png", dpi=160)
# 释放本图资源，便于连续运行多个案例。
plt.close(fig)
