codexrandom-walk-paths-and-drift.py
random-walk-paths-and-drift.py
"""Illustrate unit-step random walks; tested with Python 3.14, NumPy/Matplotlib.
Run through make _media/random-walk-paths-and-drift.png. Output goes to CWD.
The shaded mean +/- one standard deviation is a scale, not a coverage claim.
"""
from pathlib import Path
import matplotlib.pyplot as plt
import numpy as np
def main():
rng = np.random.default_rng(1905)
n = np.arange(81)
plt.rcParams.update({"font.size": 11, "axes.titlesize": 13})
fig, axes = plt.subplots(1, 2, figsize=(10.8, 5.4), dpi=120,
facecolor="white", sharex=True, sharey=True)
for ax, p, count, colors in zip(
axes, (0.5, 0.65), (4, 2),
(("#2274a5", "#d27727", "#43876d", "#9258a2"),
("#2274a5", "#d27727")),
):
mean = n * (2 * p - 1)
sigma = np.sqrt(4 * n * p * (1 - p))
ax.fill_between(n, mean - sigma, mean + sigma, color="#dfe5ec",
label=r"Mean $\pm$ one SD")
for i, color in enumerate(colors):
steps = np.where(rng.random(80) < p, 1, -1)
path = np.concatenate(([0], np.cumsum(steps)))
assert np.all(np.abs(np.diff(path)) == 1)
assert np.all((path - n) % 2 == 0)
ax.plot(n, path, color=color, lw=1.5, alpha=0.95,
label=f"Path {i + 1}")
ax.plot(n, mean, color="#182b40", ls="--", lw=2.2,
label=r"Mean $n(2p-1)$")
ax.set(title=f"{'Fair' if p == 0.5 else 'Biased'}: p = {p:.2f}; {count} paths",
xlabel="Step count n", xlim=(0, 80), ylim=(-23, 46))
ax.set_xticks([0, 20, 40, 60, 80])
ax.grid(color="#edf0f3")
ax.set_axisbelow(True)
ax.spines[["top", "right"]].set_visible(False)
ax.legend(loc="upper left", fontsize=9, frameon=False)
axes[0].set_ylabel(r"Position $S_n$ (unit steps)")
fig.suptitle("Independent steps accumulate into wandering paths", fontsize=16)
fig.text(0.5, 0.045,
"Seed 1905; illustrative paths. Shading measures spread at each n;\n"
"it is not a confidence interval or a guarantee that a path stays inside.",
ha="center", fontsize=10)
fig.subplots_adjust(left=0.075, right=0.985, bottom=0.22, top=0.83, wspace=0.13)
fig.savefig(Path.cwd() / Path(__file__).with_suffix(".png").name,
facecolor="white", transparent=False)
plt.close(fig)
if __name__ == "__main__":
main()