"""Original sequence/fold/binding schematic; no protein coordinates or predictor. Tested with Python 3.14, Matplotlib 3.10.7 and NumPy 2.3.5. Save the same-basename PNG in CWD for the repository's media rule. """ from collections import Counter from pathlib import Path import matplotlib matplotlib.use("Agg") import matplotlib.pyplot as plt from matplotlib.patches import Circle, Ellipse, FancyArrowPatch import numpy as np SEQUENCE = "AMAMAMAMAMAM" REORDERED = "AAAAAAMMMMMM" COLORS = {"A": "#f3c66a", "M": "#75b5d4"} INK = "#253745" FOLD = np.array([ [-2.0, .6], [-1.55, 1.3], [-.8, 1.5], [0., 1.05], [.75, 1.55], [1.6, 1.3], [1.7, .35], [1., -.2], [.15, .15], [-.6, -.3], [-1.35, -.9], [-2., -.5], ]) def chain(ax, points, sequence, radius=.17, labels="letters"): """Connect consecutive residues only; color always follows sequence order.""" ax.plot(*points.T, color=INK, lw=2, zorder=1) for i, ((x, y), residue) in enumerate(zip(points, sequence, strict=True)): ax.add_patch(Circle((x, y), radius, facecolor=COLORS[residue], edgecolor=INK, lw=1.1, zorder=3)) ax.text(x, y, residue if labels == "letters" else str(i + 1), ha="center", va="center", fontsize=10, color=INK, zorder=4) def main(): assert Counter(SEQUENCE) == Counter(REORDERED) == {"A": 6, "M": 6} assert sum(a != b for a, b in zip(SEQUENCE, SEQUENCE[1:])) == 11 assert sum(a != b for a, b in zip(REORDERED, REORDERED[1:])) == 1 assert FOLD.shape == (12, 2) and np.isfinite(FOLD).all() assert len(np.unique(FOLD, axis=0)) == len(SEQUENCE) # Every circle is separate, and sequence positions 4 and 9 are non-neighbours. distances = np.linalg.norm(FOLD[:, None] - FOLD[None, :], axis=-1) assert distances[np.triu_indices(12, 1)].min() > 2 * .17 assert np.linalg.norm(FOLD[3] - FOLD[8]) < .95 fig = plt.figure(figsize=(10.0, 6.7), facecolor="white") plt.rcParams.update({"font.family": "DejaVu Sans", "text.color": INK}) fig.text(.5, .96, "Sequence → abstract fold → binding site", ha="center", fontsize=17, weight="bold") fig.text(.5, .915, "A = alanine M = methionine Lines = peptide connectivity", ha="center", fontsize=11) ax = fig.add_axes([.08, .62, .84, .25]) ax.set(xlim=(-1.3, 12.5), ylim=(-1.0, 2.0), aspect="equal") ax.axis("off") for y, sequence, label in [(1.35, SEQUENCE, "11 unlike neighbours"), (.05, REORDERED, "1 unlike neighbour")]: points = np.column_stack([np.arange(12), np.full(12, y)]) chain(ax, points, sequence, radius=.28) ax.text(-.7, y, "N", ha="center", va="center", fontsize=11) ax.text(11.7, y, "C", ha="center", va="center", fontsize=11) ax.text(5.5, y - .56, label, ha="center", fontsize=10) fig.text(.5, .60, "Same counts: 6 A + 6 M. Different order changes the neighbours.", ha="center", fontsize=12) folded = fig.add_axes([.06, .16, .40, .39]) folded.set(xlim=(-2.6, 2.1), ylim=(-1.5, 2.25), aspect="equal") folded.axis("off") chain(folded, FOLD, SEQUENCE, labels="numbers") folded.text(-2.35, .65, "N", fontsize=11, ha="center") folded.text(-2.35, -.5, "C", fontsize=11, ha="center") for point in FOLD[[3, 8]]: folded.add_patch(Circle(point, .24, fill=False, edgecolor="#b96724", lw=2)) folded.plot(*FOLD[[3, 8]].T, ls=":", color="#b96724", lw=2, zorder=2) folded.text(-.25, 2.04, "One imagined arrangement", ha="center", fontsize=12, weight="bold") folded.text(-.25, -1.35, "Numbers keep the sequence order", ha="center", fontsize=11) binding = fig.add_axes([.59, .16, .35, .39]) binding.set(xlim=(-1.8, 1.8), ylim=(-1.5, 2.25), aspect="equal") binding.axis("off") binding.add_patch(Ellipse((0, .65), 2.3, 1.3, facecolor="#faf2dc", edgecolor="#b96724", ls="--", lw=1.5)) # A conceptual magnification of residues 4 and 9, not an atomic surface. chain(binding, np.array([[-.9, .65]]), "M", radius=.34) chain(binding, np.array([[.9, .65]]), "A", radius=.34) binding.text(-.9, .02, "position 4", ha="center", fontsize=10) binding.text(.9, .02, "position 9", ha="center", fontsize=10) binding.add_patch(Ellipse((0, .65), .7, .46, facecolor="#a9d3af", edgecolor="#39734c", lw=1.5, zorder=4)) binding.annotate("Bound molecule", xy=(0, .65), xytext=(0, 1.65), ha="center", fontsize=11, arrowprops={"arrowstyle": "->", "color": INK}) binding.text(0, 2.04, "Binding-site idea", ha="center", fontsize=12, weight="bold") binding.text(0, -.70, "Distant positions can cooperate", ha="center", fontsize=11) binding.text(0, -1.05, "Shape AND chemistry affect binding", ha="center", fontsize=11) fig.add_artist(FancyArrowPatch((.48, .36), (.58, .36), transform=fig.transFigure, arrowstyle="->", mutation_scale=18, lw=1.8, color=INK)) fig.text(.5, .085, "The 12-residue strings are bookkeeping toys, not known functional proteins.", ha="center", fontsize=10) fig.text(.5, .045, "Original schematic: no measured coordinates, physical scale, or fold prediction.", ha="center", fontsize=10, color="#59636b") output = Path.cwd() / (Path(__file__).stem + ".png") fig.savefig(output, dpi=120, facecolor="white", transparent=False) plt.close(fig) print(f"Wrote {output.name}: 1200 × 804 pixels") if __name__ == "__main__": main()