codex/past-exam-of-the-mathematics-course-of-the-university-of-cambridge/2012/iii/paper-41-mixture-hazard.py

past-exam-of-the-mathematics-course-of-the-university-of-cambridge/2012/iii/paper-41-mixture-hazard.py
"""Render the exponential-mixture example to a PNG basename in cwd.

Tested with Python 3.14.4, NumPy 2.3.5 and Matplotlib 3.10.7.
The caller owns MPLCONFIGDIR; this script does not change it.
"""
import numpy as np
import matplotlib

matplotlib.use("Agg")
import matplotlib.pyplot as plt

t = np.linspace(0.0, 6.0, 601)
slow = np.exp(-t)
fast = np.exp(-2.0 * t)
survival = 0.25 * slow + 0.75 * fast
hazard = (slow + 6.0 * fast) / (slow + 3.0 * fast)

with plt.rc_context({"font.size": 11, "axes.labelsize": 12, "axes.titlesize": 12}):
    fig, axes = plt.subplots(1, 2, figsize=(8.4, 4.2), dpi=100, facecolor="white")
    fig.suptitle("Survival selection in a two-rate exponential mixture", fontsize=14, y=0.96)
    ax = axes[0]
    ax.plot(t, slow, "--", color="#5980a6", label="Rate 1 component")
    ax.plot(t, fast, "--", color="#b56544", label="Rate 2 component")
    ax.plot(t, survival, color="#172c40", linewidth=2.4, label="Mixture survival")
    ax.set(title="Weighted exponential survival", xlabel="Time", ylabel="Survival probability", xlim=(0, 6), ylim=(0, 1.04))
    ax.legend(frameon=False, fontsize=9)
    ax = axes[1]
    ax.axhline(2.0, linestyle="--", color="#b56544", linewidth=1.3, label="Rate 2")
    ax.axhline(1.0, linestyle="--", color="#5980a6", linewidth=1.3, label="Rate 1 limit")
    ax.plot(t, hazard, color="#172c40", linewidth=2.4, label="Population hazard")
    ax.scatter([0], [1.75], color="#172c40", zorder=3)
    ax.annotate("Initial hazard 1.75", xy=(0, 1.75), xytext=(0.65, 1.82), fontsize=10)
    ax.set(title="Survivors favor the slower rate", xlabel="Time", ylabel="Hazard", xlim=(0, 6), ylim=(0.88, 2.10))
    ax.legend(frameon=False, fontsize=9, loc="center right")
    for ax in axes:
        ax.set_facecolor("white")
        ax.grid(alpha=0.20)
        ax.spines[["top", "right"]].set_visible(False)
    fig.subplots_adjust(left=0.08, right=0.98, bottom=0.14, top=0.79, wspace=0.33)
    fig.savefig("paper-41-mixture-hazard.png", dpi=100, facecolor="white", transparent=False)
    plt.close(fig)