codex/linked-locus-gamete-probabilities.py

linked-locus-gamete-probabilities.py
"""Original AB/ab two-locus toy diagram; save a basename PNG to cwd.

Tested with Python 3.14.4, Matplotlib 3.10.7 (+dfsg1), NumPy 2.3.5.
Assumptions: fair segregation and equal reciprocal gamete probabilities.
Run from _media: MPLCONFIGDIR=/tmp/codex-wiki-matplotlib python ../linked-locus-gamete-probabilities.py
"""

from pathlib import Path

import matplotlib

matplotlib.use("Agg")
import matplotlib.pyplot as plt
from matplotlib.patches import Patch


def main():
    fig, axes = plt.subplots(1, 3, figsize=(9.6, 4.5), sharey=True, facecolor="white")
    parental, recombinant = "#246c94", "#c06923"
    for ax, r, subtitle in zip(axes, (0, 0.2, 0.5),
                               ("Complete linkage", "Partial linkage", "Independent assortment")):
        probabilities = ((1 - r) / 2, (1 - r) / 2, r / 2, r / 2)
        ax.set_facecolor("white")
        ax.bar(range(4), probabilities, color=(parental, parental, recombinant, recombinant),
               width=0.68, zorder=3)
        for x, probability in enumerate(probabilities):
            ax.text(x, probability + 0.014, f"{probability:g}", ha="center", fontsize=12)
        ax.set_xticks(range(4), ("AB", "ab", "Ab", "aB"), fontsize=12)
        ax.set_title(f"r = {r:g}\n{subtitle}", fontsize=12)
        ax.set_ylim(0, 0.57)
        ax.set_yticks((0, 0.1, 0.2, 0.3, 0.4, 0.5))
        ax.grid(axis="y", color="#dddddd", zorder=0)
        ax.spines[["top", "right"]].set_visible(False)
        ax.set_xlabel("Gamete haplotype", fontsize=11)
    axes[0].set_ylabel("Probability per transmitted gamete", fontsize=11)
    fig.suptitle("Two linked loci: parental phase AB/ab", fontsize=17, y=0.97)
    fig.legend(handles=(Patch(color=parental, label="Parental: AB, ab"),
                        Patch(color=recombinant, label="Recombinant: Ab, aB")),
               loc="lower center", bbox_to_anchor=(0.5, 0.065), ncol=2, frameon=False, fontsize=11)
    fig.text(0.5, 0.035, "Fair segregation; equal reciprocal gamete probabilities. r is the total recombinant probability.",
             ha="center", fontsize=10, color="#444444")
    fig.subplots_adjust(left=0.085, right=0.98, bottom=0.25, top=0.76, wspace=0.15)
    fig.savefig(Path(__file__).with_suffix(".png").name, dpi=120, facecolor="white", transparent=False)
    plt.close(fig)


if __name__ == "__main__":
    main()