codexribozymes-turnover-model.py
ribozymes-turnover-model.py
"""Stipulated models contrasting self-processing and catalytic turnover.
Run from _media with Python 3.14, numpy 2.3.5 and matplotlib 3.10.7.
Curves are analytic teaching models, not measurements or fitted ribozyme rates.
"""
from pathlib import Path
import matplotlib.pyplot as plt
import numpy as np
def main():
tau = np.linspace(0, 5, 501)
self_events = -np.expm1(-tau)
turnover_products = 5 * self_events
fig, ax = plt.subplots(figsize=(9, 6), dpi=110, facecolor="white")
fig.suptitle("One self-processing event or repeated catalytic turnover?",
fontsize=16, weight="bold", y=0.97)
ax.set_title("Stipulated analytic models • no experimental data or fitted rates",
fontsize=11, pad=15)
ax.plot(tau, turnover_products, color="#237747", lw=3,
label=r"Regenerated RNA: $P/R_0=5(1-e^{-\tau})$")
ax.plot(tau, self_events, color="#7550a1", lw=3,
label=r"Self-processing: $P_{\rm self}/R_0=1-e^{-\tau}$")
ax.axhline(1, color="#63727d", lw=1.5, ls="--")
ax.axhline(5, color="#63727d", lw=1.2, ls=":")
ax.text(3.4, 1.15, "One event per precursor: ceiling = 1", fontsize=10,
ha="center", color="#495863")
ax.text(3.6, 5.14, "Five separate substrates per catalyst initially", fontsize=10,
ha="center", color="#495863")
for y, color, label, dy in (
(5 * (1 - np.exp(-1)), "#237747", "3.161 products per catalyst", 0.55),
(1 - np.exp(-1), "#7550a1", "0.632 events per precursor", 0.65),
):
ax.scatter([1], [y], s=55, color=color, zorder=4)
ax.annotate(label, xy=(1, y), xytext=(1.45, y + dy),
fontsize=11, color=color,
arrowprops={"arrowstyle": "-", "color": color, "lw": 1})
ax.set(xlim=(0, 5), ylim=(0, 5.45),
xlabel=r"Dimensionless time $\tau$ (chosen equal timescales)",
ylabel=r"Completed conversions / initial RNA amount $R_0$")
ax.legend(loc="center right", bbox_to_anchor=(0.99, 0.47), frameon=True,
facecolor="white", framealpha=1, fontsize=11)
ax.grid(alpha=0.18)
ax.spines[["top", "right"]].set_visible(False)
fig.text(0.5, 0.07,
r"Self: $A+P_{\rm self}=R_0$. Turnover: $R=R_0$ and $S+P=5R_0$.",
ha="center", fontsize=12)
fig.text(0.5, 0.025,
"Effective irreversible models; no saturation, folding delays, inhibition or catalyst loss.",
ha="center", fontsize=10)
fig.subplots_adjust(left=0.11, right=0.97, top=0.83, bottom=0.21)
fig.savefig(Path(__file__).with_suffix(".png").name, facecolor="white", transparent=False)
plt.close(fig)
if __name__ == "__main__":
main()