{"spec_id":"feynman-basic","library":"matplotlib","language":"python","code":"\"\"\" anyplot.ai\nfeynman-basic: Feynman Diagram for Particle Interactions\nLibrary: matplotlib 3.10.9 | Python 3.13.13\nQuality: 91/100 | Updated: 2026-06-03\n\"\"\"\n\nimport os\n\nimport matplotlib.patheffects as pe\nimport matplotlib.pyplot as plt\nimport numpy as np\nfrom matplotlib.lines import Line2D\nfrom matplotlib.patches import FancyArrowPatch\n\n\nTHEME = os.getenv(\"ANYPLOT_THEME\", \"light\")\n\n# Theme-adaptive chrome — Imprint palette\nPAGE_BG = \"#FAF8F1\" if THEME == \"light\" else \"#1A1A17\"\nINK = \"#1A1A17\" if THEME == \"light\" else \"#F0EFE8\"\nINK_SOFT = \"#4A4A44\" if THEME == \"light\" else \"#B8B7B0\"\nINK_MUTED = \"#6B6A63\" if THEME == \"light\" else \"#A8A79F\"\n\n# Imprint categorical palette — particle types (positions 1–4)\nFERMION_COLOR = \"#009E73\"  # pos 1: brand green\nPHOTON_COLOR = \"#C475FD\"  # pos 2: lavender\nGLUON_COLOR = \"#4467A3\"  # pos 3: blue\nBOSON_COLOR = \"#BD8233\"  # pos 4: ochre\n\n# Two-process layout: top QED (e+e- annihilation), bottom QCD (gg -> H)\nvertices = {\"v1\": (0.28, 0.74), \"v2\": (0.72, 0.74), \"v3\": (0.28, 0.26), \"v4\": (0.72, 0.26)}\n\npropagators = [\n    # QED: e-e+ -> gamma -> mu-mu+\n    {\"from\": (0.04, 0.92), \"to\": \"v1\", \"type\": \"fermion\", \"label\": r\"$e^-$\", \"arrow_fwd\": True},\n    {\"from\": (0.04, 0.56), \"to\": \"v1\", \"type\": \"fermion\", \"label\": r\"$e^+$\", \"arrow_fwd\": False},\n    {\"from\": \"v1\", \"to\": \"v2\", \"type\": \"photon\", \"label\": r\"$\\gamma$\"},\n    {\"from\": \"v2\", \"to\": (0.96, 0.92), \"type\": \"fermion\", \"label\": r\"$\\mu^-$\", \"arrow_fwd\": True},\n    {\"from\": \"v2\", \"to\": (0.96, 0.56), \"type\": \"fermion\", \"label\": r\"$\\mu^+$\", \"arrow_fwd\": False},\n    # QCD: gg -> H -> bb-bar\n    {\"from\": (0.04, 0.44), \"to\": \"v3\", \"type\": \"gluon\", \"label\": r\"$g$\"},\n    {\"from\": (0.04, 0.08), \"to\": \"v3\", \"type\": \"gluon\", \"label\": r\"$g$\"},\n    {\"from\": \"v3\", \"to\": \"v4\", \"type\": \"boson\", \"label\": r\"$H$\"},\n    {\"from\": \"v4\", \"to\": (0.96, 0.44), \"type\": \"fermion\", \"label\": r\"$b$\", \"arrow_fwd\": True},\n    {\"from\": \"v4\", \"to\": (0.96, 0.08), \"type\": \"fermion\", \"label\": r\"$\\bar{b}$\", \"arrow_fwd\": False},\n]\n\n# Canvas: landscape 3200×1800 px (figsize=(8, 4.5), dpi=400)\nfig, ax = plt.subplots(figsize=(8, 4.5), dpi=400, facecolor=PAGE_BG)\nax.set_facecolor(PAGE_BG)\nax.set_xlim(-0.08, 1.08)\nax.set_ylim(-0.08, 1.08)\n\nfor prop in propagators:\n    start = vertices[prop[\"from\"]] if isinstance(prop[\"from\"], str) else prop[\"from\"]\n    end = vertices[prop[\"to\"]] if isinstance(prop[\"to\"], str) else prop[\"to\"]\n    sx, sy = start\n    ex, ey = end\n    mx, my = (sx + ex) / 2, (sy + ey) / 2\n    dx, dy = ex - sx, ey - sy\n    length = np.sqrt(dx**2 + dy**2)\n    ux, uy = dx / length, dy / length\n    px, py = -uy, ux  # perpendicular unit vector\n\n    if prop[\"type\"] == \"fermion\":\n        arrow_fwd = prop.get(\"arrow_fwd\", True)\n        # FancyArrowPatch: direct matplotlib Patch API for arrow rendering\n        arrow = FancyArrowPatch(\n            posA=(sx, sy) if arrow_fwd else (ex, ey),\n            posB=(ex, ey) if arrow_fwd else (sx, sy),\n            arrowstyle=\"-|>\",\n            color=FERMION_COLOR,\n            linewidth=2.5,\n            mutation_scale=20,\n            transform=ax.transData,\n            zorder=3,\n        )\n        # patheffects: background-color halo separates the arrow from any crossing lines\n        arrow.set_path_effects([pe.withStroke(linewidth=5, foreground=PAGE_BG)])\n        ax.add_patch(arrow)\n        ax.text(\n            mx + px * 0.06,\n            my + py * 0.06,\n            prop[\"label\"],\n            fontsize=14,\n            ha=\"center\",\n            va=\"center\",\n            color=FERMION_COLOR,\n            fontweight=\"bold\",\n        )\n\n    elif prop[\"type\"] == \"photon\":\n        t = np.linspace(0, 1, 500)\n        wave = 0.035 * np.sin(2 * np.pi * 8 * t) * np.sin(np.pi * t) ** 0.3\n        (line,) = ax.plot(\n            sx + t * dx + wave * px, sy + t * dy + wave * py, color=PHOTON_COLOR, lw=2.5, solid_capstyle=\"round\"\n        )\n        # patheffects: wider same-color stroke gives the wave a luminous, glowing appearance\n        line.set_path_effects([pe.withStroke(linewidth=6, foreground=PHOTON_COLOR)])\n        ax.text(\n            mx - px * 0.07,\n            my - py * 0.07,\n            prop[\"label\"],\n            fontsize=14,\n            ha=\"center\",\n            va=\"center\",\n            color=PHOTON_COLOR,\n            fontweight=\"bold\",\n        )\n\n    elif prop[\"type\"] == \"gluon\":\n        t = np.linspace(0, 1, 3000)\n        phase = 2 * np.pi * 9 * t\n        envelope = np.sin(np.pi * t) ** 0.4\n        along_mod = 0.025 * 0.7 * np.sin(phase) * envelope\n        perp_disp = 0.025 * np.cos(phase) * envelope\n        (line,) = ax.plot(\n            sx + t * dx - along_mod * ux + perp_disp * px,\n            sy + t * dy - along_mod * uy + perp_disp * py,\n            color=GLUON_COLOR,\n            lw=2.0,\n            solid_capstyle=\"round\",\n        )\n        # patheffects: wider stroke gives the coil visual weight consistent with the photon glow\n        line.set_path_effects([pe.withStroke(linewidth=5, foreground=GLUON_COLOR)])\n        ax.text(\n            mx + px * 0.06,\n            my + py * 0.06,\n            prop[\"label\"],\n            fontsize=14,\n            ha=\"center\",\n            va=\"center\",\n            color=GLUON_COLOR,\n            fontweight=\"bold\",\n        )\n\n    elif prop[\"type\"] == \"boson\":\n        ax.plot([sx, ex], [sy, ey], color=BOSON_COLOR, lw=2.5, linestyle=(0, (8, 5)), dash_capstyle=\"round\")\n        ax.text(\n            mx - px * 0.06,\n            my - py * 0.06,\n            prop[\"label\"],\n            fontsize=14,\n            ha=\"center\",\n            va=\"center\",\n            color=BOSON_COLOR,\n            fontweight=\"bold\",\n        )\n\n# Vertex dots (theme-adaptive ink)\nfor vx, vy in vertices.values():\n    ax.plot(vx, vy, \"o\", color=INK, markersize=10, zorder=5)\n\n# Separator between QED and QCD processes\nax.axhline(y=0.50, xmin=0.05, xmax=0.95, color=INK_MUTED, lw=0.8, linestyle=\"--\", alpha=0.5)\n\n# Process labels — nudged inward and bumped to 10pt for mobile readability\nax.text(0.02, 0.74, \"QED\", fontsize=10, ha=\"left\", va=\"center\", color=INK_MUTED, fontstyle=\"italic\", rotation=90)\nax.text(0.02, 0.26, \"QCD\", fontsize=10, ha=\"left\", va=\"center\", color=INK_MUTED, fontstyle=\"italic\", rotation=90)\n\n# Time arrow (inside axes area, above legend)\nax.annotate(\"\", xy=(0.95, -0.03), xytext=(0.05, -0.03), arrowprops={\"arrowstyle\": \"->\", \"color\": INK_MUTED, \"lw\": 1.2})\nax.text(0.5, -0.05, \"time\", fontsize=10, ha=\"center\", va=\"top\", color=INK_MUTED, fontstyle=\"italic\")\n\n# Title (48 chars < 67 threshold — default 12pt)\nax.set_title(\"feynman-basic · python · matplotlib · anyplot.ai\", fontsize=12, fontweight=\"medium\", pad=10, color=INK)\nax.axis(\"off\")\n\n# Legend (frameless for minimal aesthetic)\nlegend_handles = [\n    Line2D(\n        [0],\n        [0],\n        color=FERMION_COLOR,\n        lw=2.5,\n        marker=\">\",\n        markersize=6,\n        markeredgecolor=FERMION_COLOR,\n        label=\"Fermion (solid + arrow)\",\n    ),\n    Line2D([0], [0], color=PHOTON_COLOR, lw=2.5, label=\"Photon (wavy)\"),\n    Line2D([0], [0], color=GLUON_COLOR, lw=2.0, label=\"Gluon (coiled)\"),\n    Line2D([0], [0], color=BOSON_COLOR, lw=2.5, linestyle=\"--\", label=\"Boson (dashed)\"),\n    Line2D([0], [0], marker=\"o\", color=PAGE_BG, markerfacecolor=INK, markersize=7, lw=0, label=\"Vertex\"),\n]\nleg = ax.legend(\n    handles=legend_handles,\n    fontsize=8,\n    loc=\"lower center\",\n    ncol=5,\n    frameon=False,\n    handlelength=2.5,\n    columnspacing=1.5,\n    bbox_to_anchor=(0.5, 0.0),\n    bbox_transform=ax.transAxes,\n)\nplt.setp(leg.get_texts(), color=INK_SOFT)\n\n# Reserve bottom 8% of figure for legend below the axes\nplt.tight_layout(rect=[0, 0.08, 1, 1])\nplt.savefig(f\"plot-{THEME}.png\", dpi=400, facecolor=PAGE_BG)\n"}