#!/usr/bin/env python3 """Constructed expiration models: identical final volume, different emptying rates. Run in the desired output directory; uses the repository NumPy/Matplotlib environment. """ import numpy as np import matplotlib matplotlib.use("Agg") import matplotlib.pyplot as plt def main(): t = np.linspace(0, 8, 801) fig, axes = plt.subplots(1, 2, figsize=(8, 3.5), dpi=120, facecolor="white") for tau, color in [(1.0, "#2367a1"), (2.0, "#b85224")]: volume = 4 * (1 - np.exp(-t / tau)) flow = 4 / tau * np.exp(-t / tau) axes[0].plot(t, volume, color=color, label=rf"$\tau={tau:g}$ s") axes[1].plot(t, flow, color=color) v1 = 4 * (1 - np.exp(-1 / tau)) axes[0].scatter([1], [v1], color=color, s=22, zorder=5) axes[0].annotate(f"{v1:.2f} L", (1, v1), xytext=(1.8, v1 - 0.05), fontsize=9, color=color, arrowprops={"arrowstyle": "-", "color": color}) axes[0].axhline(4, color="0.5", ls=":", lw=1) axes[0].axvline(1, color="0.55", ls="--", lw=1) axes[0].set(xlabel="Time (s)", ylabel="Expelled volume (L)", ylim=(0, 4.3)) axes[0].legend(loc="lower right", fontsize=9) axes[1].set(xlabel="Time (s)", ylabel="Outward flow (L/s)", ylim=(0, 4.3)) for ax in axes: ax.set_xlim(0, 8) ax.grid(alpha=0.18) ax.set_facecolor("white") fig.suptitle("Same final volume, different emptying rates", fontsize=13) fig.text(0.5, 0.015, "Constructed exponential curves; not patient traces", ha="center", fontsize=9) fig.tight_layout(rect=(0, 0.06, 1, 0.96)) fig.savefig("spirometry-volume-flow-model.png", dpi=120, facecolor="white", transparent=False) plt.close(fig) if __name__ == "__main__": main()