codex/valve-tether-angle.py

valve-tether-angle.py
"""Schematic force balance for equal valve tethers, not an anatomical drawing.
Python 3.14 / Matplotlib 3.10. Run in _media to generate cwd PNG.
Each panel balances a 1 N upward load with two equal tensile forces.
"""
from pathlib import Path
from math import sin, cos, radians
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt

fig, axes = plt.subplots(1, 2, figsize=(7.4, 3.9), dpi=100, facecolor='white')
for ax, degrees in zip(axes, (30, 60)):
    theta = radians(degrees)
    tension = 1 / (2 * cos(theta))
    ax.plot([0, 0], [0, -1.05], '--', color='#aaaaaa', linewidth=1)
    for side in (-1, 1):
        x, y = side * sin(theta), -cos(theta)
        ax.plot([0, x], [0, y], color='#1766a5', linewidth=2.5)
        ax.plot(x, y, 'o', color='#333333', markersize=6)
        ax.annotate('', xy=(.68*x, .68*y), xytext=(.28*x, .28*y),
                    arrowprops=dict(arrowstyle='->', color='#1766a5', lw=2))
    ax.plot(0, 0, 'o', color='#222222', markersize=7)
    ax.annotate('', xy=(0, .62), xytext=(0, .05),
                arrowprops=dict(arrowstyle='->', color='#c15b18', lw=2.4))
    ax.text(.07, .5, 'Load = 1 N', color='#9d4308', fontsize=10)
    ax.text(.02, -.33, rf'$\theta={degrees}^\circ$', fontsize=11)
    ax.text(0, -1.17, rf'Each tension: $T={tension:.3f}$ N', ha='center', fontsize=11)
    ax.set(xlim=(-1.05, 1.05), ylim=(-1.3, .78), aspect='equal')
    ax.axis('off')
fig.suptitle('Tether angle changes tension at the same applied load', fontsize=12)
fig.text(.5, .055, r'$2T\cos\theta=1\ \mathrm{N}$; schematic point attachment, not anatomical geometry',
         ha='center', fontsize=10)
fig.subplots_adjust(left=.03, right=.97, top=.84, bottom=.18, wspace=.15)
fig.savefig(Path('valve-tether-angle.png'), facecolor='white', dpi=100)
plt.close(fig)