codexenzyme-substrate-saturation.py
enzyme-substrate-saturation.py
"""Draw normalized saturation examples; write basename.png in cwd.
Uses the repository's Python 3.14, NumPy and Matplotlib dependencies.
All values illustrate a model; no experimental measurements are plotted.
"""
from pathlib import Path
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
import numpy as np
def main():
x = np.geomspace(0.01, 100, 601)
samples = np.array([0.1, 1, 10])
values = samples / (1 + samples)
blue, orange = "#176b92", "#b65f1b"
fig, (ax, bars) = plt.subplots(1, 2, figsize=(8.6, 4.5),
gridspec_kw={"width_ratios": [1.5, 1]},
layout="constrained")
fig.set_facecolor("white")
ax.plot(x, x / (1 + x), color=blue, lw=2.7)
ax.axhline(1, color="#69747d", ls="--", lw=1.2)
for point, value, label, offset in zip(
samples, values, ["1/11 ≈ 0.091", "1/2 = 0.500", "10/11 ≈ 0.909"],
[(9, 9), (9, -21), (-12, -27)],
):
ax.vlines(point, 0, value, color="#b9c6ce", ls=":")
ax.scatter(point, value, color=orange, s=38, zorder=3)
ax.annotate(label, (point, value), xytext=offset,
textcoords="offset points", fontsize=9,
ha="right" if point == 10 else "left")
ax.set(xscale="log", xlim=(0.01, 100), ylim=(0, 1.12),
xticks=[0.01, 0.1, 1, 10, 100],
xticklabels=["0.01", "0.1", "1", "10", "100"],
xlabel=r"Substrate concentration $s/K_M$ (log scale)",
ylabel=r"Initial rate $v/V_{\max}$")
ax.text(0.012, 1.035, r"Limiting rate $V_{\max}$", fontsize=10, color="#4b5964")
ax.set_title("More substrate gives diminishing returns", fontsize=11)
bars.bar(np.arange(3), values * 110, color=blue, width=0.62)
for i, value in enumerate(values * 110):
bars.text(i, value + 3, f"{value:.0f}", ha="center", fontsize=11)
bars.axhline(110, color="#69747d", ls="--", lw=1.2)
bars.set(xticks=np.arange(3), xticklabels=["0.1", "1", "10"],
ylim=(0, 125), xlabel=r"Substrate concentration $s/K_M$",
ylabel="Initial rate (μM/min)")
bars.set_title(r"Chosen $V_{\max}$ = 110 μM/min", fontsize=11)
for axes in [ax, bars]:
axes.set_facecolor("white")
axes.spines[["top", "right"]].set_visible(False)
fig.savefig(Path(Path(__file__).stem + ".png"), dpi=150,
facecolor="white", transparent=False)
plt.close(fig)
print("s/K_M:", samples.tolist())
print("v/Vmax:", values.tolist(), "; chosen rates:", (110 * values).tolist())
print("Doubling s from 10 K_M to 20 K_M: relative increase =",
(20 / 21 / (10 / 11) - 1) * 100, "%")
if __name__ == "__main__":
main()