codexdietary-divergence-mating-assay.py
dietary-divergence-mating-assay.py
"""Draw a design schematic, without experimental counts or inferred rates.
Tested with Python 3.14.4, matplotlib 3.10.7 and numpy 2.3.5.
Run from _media; the matching PNG is written to the working directory.
"""
from pathlib import Path
import matplotlib.pyplot as plt
from matplotlib.patches import FancyArrowPatch, FancyBboxPatch
def main():
fig, ax = plt.subplots(figsize=(10, 7.4), dpi=120, facecolor="white")
ax.set(xlim=(0, 10), ylim=(0, 7.4))
ax.axis("off")
ink, blue, amber = "#183245", "#2171a1", "#a56813"
def box(x, y, w, h, label, edge=ink, fill="white", size=12):
ax.add_patch(FancyBboxPatch(
(x, y), w, h, boxstyle="round,pad=0.06,rounding_size=0.08",
linewidth=1.5, edgecolor=edge, facecolor=fill))
ax.text(x+w/2, y+h/2, label, ha="center", va="center",
fontsize=size, color=ink, linespacing=1.45)
def arrow(a, b, color=ink):
ax.add_patch(FancyArrowPatch(a, b, arrowstyle="-|>",
mutation_scale=14, lw=1.6, color=color))
ax.text(5, 7.13, "Dietary divergence → mating assay", ha="center",
fontsize=19, weight="bold", color=ink)
ax.text(5, 6.82, "Drosophila pseudoobscura · procedure schematic", ha="center",
fontsize=12, color=ink, style="italic")
box(3.25, 5.94, 3.5, .6, "One source population")
arrow((4, 5.92), (2.55, 5.42), blue)
arrow((6, 5.92), (7.45, 5.42), amber)
box(.65, 4.58, 3.8, .78, "Starch medium\n4 separate populations", blue, "#eef6fa")
box(5.55, 4.58, 3.8, .78, "Maltose medium\n4 separate populations", amber, "#fff6e7")
arrow((2.55, 4.51), (2.55, 4.04), blue)
arrow((7.45, 4.51), (7.45, 4.04), amber)
box(.65, 3.3, 3.8, .69, "Common medium\n1 generation", blue)
box(5.55, 3.3, 3.8, .69, "Common medium\n1 generation", amber)
arrow((2.55, 3.22), (3.3, 2.84), blue)
arrow((7.45, 3.22), (6.7, 2.84), amber)
box(2.35, 2.08, 5.3, .7, "Select two populations → mating chamber\n12 females from each; males from both", size=12)
ax.text(.5, 2.52, "Cross-diet AND\nsame-diet pairs", fontsize=10.5,
color=ink, ha="left", va="center", linespacing=1.5)
ax.text(8.05, 2.52, "Reverse wing\nmarking in repeats", fontsize=10.5,
color=ink, ha="left", va="center", linespacing=1.5)
arrow((5, 2), (5, 1.61))
ax.text(5, 1.39, "Score observed mating categories", ha="center", fontsize=13,
weight="bold", color=ink)
for x, label in zip([.7, 3, 5.3, 7.6],
["A female × A male", "A female × B male",
"B female × A male", "B female × B male"]):
box(x, .65, 1.75, .45, label, size=9.5)
ax.text(5, .18, "A/B label the two populations in a test · no mating counts or isolation rates plotted",
fontsize=10.5, color=ink, ha="center")
fig.subplots_adjust(left=.025, right=.975, top=.99, bottom=.02)
fig.savefig(Path.cwd() / (Path(__file__).stem + ".png"), facecolor="white")
plt.close(fig)
if __name__ == "__main__":
main()