codex/idler-gear-force-balance.py

idler-gear-force-balance.py
"""Draw an ideal collinear idler's tangential force balance.

Tested with Python 3.14.4; Matplotlib dependency in the root pyproject.toml.
Run from the output directory; writes idler-gear-force-balance.png there.
"""
from pathlib import Path
import os
os.environ.setdefault("MPLCONFIGDIR", "/tmp/codex-wiki-laplace-mpl")
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
from matplotlib.patches import Circle

fig, ax = plt.subplots(figsize=(7.2, 4.0), dpi=100)
fig.patch.set_facecolor("white")
for x, r, color in [(0,20,"#7893a3"),(50,30,"#138396"),(130,50,"#7893a3")]:
    ax.add_patch(Circle((x,0),r,edgecolor=color,facecolor="#f7fafb",linewidth=1.7))
    ax.plot(x,0,"o",color=color,markersize=3)
for x in [20,80]:
    ax.annotate("",xy=(x,37),xytext=(x,0),arrowprops=dict(arrowstyle="-|>",color="#bd6817",lw=2.2))
    ax.text(x,41,"100 N",ha="center",va="bottom",fontsize=11,color="#925111")
ax.annotate("",xy=(50,-48),xytext=(50,0),arrowprops=dict(arrowstyle="-|>",color="#233f67",lw=2.2))
ax.text(53,-43,"200 N",ha="left",va="center",fontsize=11,color="#233f67")
ax.text(0,-10,"Input\n20 teeth",ha="center",va="center",fontsize=9)
ax.text(50,17,"Idler\n30 teeth",ha="center",va="center",fontsize=9)
ax.text(130,-2,"Output\n50 teeth",ha="center",va="center",fontsize=10)
ax.text(50,-60,"Tangential components shown; opposite radial components cancel.",ha="center",fontsize=9)
ax.set_title("Idler: cancelling torques, nonzero support reaction",fontsize=12,pad=12)
ax.set_xlim(-27,184)
ax.set_ylim(-66,57)
ax.set_aspect("equal")
ax.axis("off")
fig.subplots_adjust(left=.02,right=.98,bottom=.04,top=.89)
fig.savefig(Path.cwd()/"idler-gear-force-balance.png",facecolor="white")
plt.close(fig)