codex/total-probability-weighted-routes.py

total-probability-weighted-routes.py
"""Draw the weighted routes of an original two-component mixture.

Tested with Python 3.14, matplotlib 3.10.7 and numpy 2.3.5.
Run from _media; the opaque PNG is written to the current directory.
"""

from pathlib import Path

import matplotlib.pyplot as plt


def main():
    plt.rcParams.update({"font.family": "DejaVu Sans", "font.size": 13})
    fig, ax = plt.subplots(figsize=(10.8, 6.6), dpi=100)
    fig.patch.set_facecolor("white")
    ax.set_facecolor("white")
    ax.set(xlim=(0, 1), ylim=(0, 1))
    ax.axis("off")
    ink, blue, orange, gray = "#193047", "#1976a3", "#d97721", "#687887"
    ax.text(0.5, 0.98, "Multiply within a route; add routes to A", ha="center",
            va="top", fontsize=21, weight="bold", color=ink)
    ax.text(0.5, 0.901, "Constructed model: group weights 0.6 and 0.4",
            ha="center", color=ink)
    ax.text(0.32, 0.826, "Choose group", ha="center", color=ink)
    ax.text(0.575, 0.826, "Conditional result", ha="center", color=ink)
    ax.text(0.88, 0.826, "Joint probability", ha="center", color=ink)
    root = (0.055, 0.47)
    groups = [(0.31, 0.65), (0.31, 0.29)]
    ends = [(0.65, 0.74), (0.65, 0.56), (0.65, 0.38), (0.65, 0.20)]

    def edge(a, b, label, color, offset=0):
        ax.annotate("", xy=b, xytext=a,
                    arrowprops={"arrowstyle": "->", "color": color, "lw": 2.2,
                                "shrinkA": 10, "shrinkB": 15})
        ax.text((a[0] + b[0]) / 2, (a[1] + b[1]) / 2 + offset, label,
                ha="center", va="center", color=color, fontsize=14,
                bbox={"facecolor": "white", "edgecolor": "none", "pad": 2})

    edge(root, groups[0], "0.6", blue, 0.018)
    edge(root, groups[1], "0.4", orange, -0.018)
    edge(groups[0], ends[0], "0.1", blue, 0.022)
    edge(groups[0], ends[1], "0.9", gray, -0.022)
    edge(groups[1], ends[2], "0.25", orange, 0.022)
    edge(groups[1], ends[3], "0.75", gray, -0.022)
    ax.text(*root, "Start", ha="center", va="center", color=ink,
            bbox={"facecolor": "white", "edgecolor": ink, "boxstyle": "round,pad=0.4"})
    for loc, label, color in zip(groups, [r"$B_1$", r"$B_2$"], [blue, orange]):
        ax.text(*loc, label, ha="center", va="center", color=color, fontsize=17,
                bbox={"facecolor": "white", "edgecolor": color, "boxstyle": "round,pad=0.35"})
    labels = [r"$A$", r"$A^c$", r"$A$", r"$A^c$"]
    products = ["0.6 × 0.1 = 0.06", "0.6 × 0.9 = 0.54",
                "0.4 × 0.25 = 0.10", "0.4 × 0.75 = 0.30"]
    for loc, label, product, color in zip(ends, labels, products, [blue, gray, orange, gray]):
        ax.text(*loc, label, ha="center", va="center", color=color, fontsize=17,
                bbox={"facecolor": "white", "edgecolor": color, "boxstyle": "round,pad=0.3"})
        ax.text(0.79, loc[1], product, ha="left", va="center", color=color,
                fontsize=13, weight="bold" if label == r"$A$" else "normal")
    ax.text(0.5, 0.108, r"$P(A)=0.06+0.10=0.16$", ha="center", color=ink,
            fontsize=20, bbox={"facecolor": "#f0f6f9", "edgecolor": "none", "pad": 9})
    ax.text(0.5, 0.022, "All four routes: 0.06 + 0.54 + 0.10 + 0.30 = 1",
            ha="center", color=ink)
    fig.subplots_adjust(left=0.02, right=0.93, bottom=0.025, top=0.985)
    fig.savefig(Path.cwd() / (Path(__file__).stem + ".png"),
                facecolor="white", transparent=False, dpi=100)
    plt.close(fig)


if __name__ == "__main__":
    main()