codex/adsorption-sites-and-occupation.py

adsorption-sites-and-occupation.py
"""Original adsorption schematic; Python 3.14, matplotlib 3.10.7.

Run from _media; emits adsorption-sites-and-occupation.png in the CWD.
"""
from pathlib import Path

import matplotlib.pyplot as plt
from matplotlib.patches import Circle, Rectangle


def main():
    plt.rcParams.update({"font.size": 12, "font.family": "DejaVu Sans"})
    fig = plt.figure(figsize=(10, 6), facecolor="white", layout="constrained")
    grid = fig.add_gridspec(2, 6, height_ratios=(1, 1.12))
    occupied_sets = ({0, 5, 10}, {0, 2, 5, 7, 8, 10}, set(range(12)))
    blue, gray = "#167da5", "#64748b"
    for panel, (occupied, fraction) in enumerate(zip(occupied_sets, ("1/4", "1/2", "1"))):
        ax = fig.add_subplot(grid[0, 2 * panel:2 * panel + 2])
        ax.set(xlim=(-0.5, 3.5), ylim=(-0.6, 2.9), aspect="equal")
        ax.axis("off")
        for i in range(12):
            x, y = i % 4, 2 - i // 4
            ax.add_patch(Rectangle((x - 0.31, y - 0.31), 0.62, 0.62,
                                   edgecolor=gray, facecolor="#f1f5f9", linewidth=1.4))
            if i in occupied:
                ax.add_patch(Circle((x, y), 0.21, facecolor=blue, edgecolor="white"))
        ax.set_title(f"{len(occupied)} of 12 occupied\n" + rf"$\theta = {fraction}$", pad=8)
    for k, title in enumerate(("Adsorption: at the boundary", "Absorption: within the bulk")):
        ax = fig.add_subplot(grid[1, k * 3:k * 3 + 3])
        ax.set(xlim=(0, 6), ylim=(-0.4, 3), aspect="equal")
        ax.axis("off")
        ax.add_patch(Rectangle((0.3, 0), 5.4, 1.65, facecolor="#e2e8f0", edgecolor=gray))
        ax.text(3, 0.25, "Material interior", ha="center", color="#334155")
        positions = ((1.1, 1.65), (2.1, 1.65), (4.0, 1.65), (5.0, 1.65)) if k == 0 else (
            (1.0, 1.1), (2.4, 0.7), (3.5, 1.3), (4.9, 0.9))
        for x, y in positions:
            ax.add_patch(Circle((x, y), 0.14, facecolor=blue, edgecolor="white"))
        ax.annotate("Surrounding phase", (3, 2.4), ha="center", color="#334155")
        ax.set_title(title, pad=2)
    fig.suptitle("A site can be vacant or occupied by one molecule", fontsize=16)
    fig.supxlabel("Schematic configurations and locations; not microscopy or measured data", fontsize=11)
    fig.savefig(Path(__file__).stem + ".png", dpi=120, facecolor="white")
    plt.close(fig)


if __name__ == "__main__":
    main()