codexcentral-limit-distributions.py
central-limit-distributions.py
"""Generate central-limit-distributions.png in the caller's working directory.
Tested with Python 3.14.4, numpy 2.3.5, matplotlib 3.10.7.
Uses exact binomial probabilities (successive convolutions), not simulations.
Run from _media with MPLCONFIGDIR set to a writable temporary directory.
"""
from pathlib import Path
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
import numpy as np
def binomial_probabilities(n, p):
probabilities = np.array([1.0])
for _ in range(n):
probabilities = np.convolve(probabilities, [1 - p, p])
return probabilities
def main():
p = 0.2
grid = np.linspace(-4, 5, 700)
normal_density = np.exp(-grid**2 / 2) / np.sqrt(2 * np.pi)
plt.rcParams.update({"font.size": 11, "axes.spines.top": False,
"axes.spines.right": False})
fig, axes = plt.subplots(2, 2, figsize=(10, 6.7), dpi=120,
facecolor="white", sharex=True, sharey=True)
for ax, n in zip(axes.flat, [1, 5, 25, 100]):
probabilities = binomial_probabilities(n, p)
counts = np.arange(n + 1)
scale = np.sqrt(n * p * (1 - p))
positions = (counts - n * p) / scale
spacing = 1 / scale
assert np.isclose(probabilities.sum(), 1)
assert np.isclose(np.dot(positions, probabilities), 0, atol=1e-12)
assert np.isclose(np.dot(positions**2, probabilities), 1)
ax.bar(positions, probabilities / spacing, width=spacing,
color="#2b7bba", alpha=0.7, edgecolor="white", linewidth=0.5,
label="Exact mass / lattice spacing")
ax.plot(grid, normal_density, color="#b24a23", lw=2.3,
label="Standard normal density")
ax.set(title=f"n = {n} trials", xlim=(-4, 5), ylim=(0, 0.48))
ax.grid(axis="y", alpha=0.18)
for ax in axes[-1]:
ax.set_xlabel(r"Standardized count $z = (k - np)/\sqrt{np(1-p)}$")
for ax in axes[:, 0]:
ax.set_ylabel("Probability per unit z")
handles, labels = axes[0, 0].get_legend_handles_labels()
fig.legend(handles, labels, loc="lower center", ncol=2, frameon=False,
bbox_to_anchor=(0.5, 0.025))
fig.suptitle("Central limit theorem: skewed Bernoulli trials, p = 0.2",
fontsize=15, y=0.98)
fig.text(0.5, 0.005,
"Each blue rectangle has area P(K = k); every panel has mean 0 and variance 1.",
ha="center", fontsize=10)
fig.tight_layout(rect=(0, 0.085, 1, 0.95))
fig.savefig(Path.cwd() / "central-limit-distributions.png",
facecolor="white", transparent=False)
plt.close(fig)
if __name__ == "__main__":
main()