"""Original one-box climate curves; Python 3.14, numpy 2.3.5, matplotlib 3.10.7. Run from _media to write the matching PNG to the current working directory. The curves are analytic illustrative calculations, not measured climate data. """ from pathlib import Path import matplotlib.pyplot as plt import numpy as np def main(): heat_capacity = 2.0e8 # J m^-2 K^-1 restoring = 2.0 # W m^-2 K^-1 forcing = 4.0 # W m^-2 noise_strength = 1.0e8 # (W m^-2)^2 s tau = heat_capacity / restoring variance = noise_strength / (heat_capacity * restoring) x = np.linspace(0.0, 5.0, 700) mean = forcing / restoring * (-np.expm1(-x)) spread = np.sqrt(variance * (-np.expm1(-2 * x))) w_tau = np.geomspace(0.01, 100, 700) spectrum_ratio = 1.0 / (1.0 + w_tau**2) plt.rcParams.update({"font.family": "DejaVu Sans", "font.size": 11, "axes.spines.top": False, "axes.spines.right": False}) fig, (left, right) = plt.subplots(1, 2, figsize=(12, 5.5), dpi=100) fig.patch.set_facecolor("white") fig.suptitle("A slow climate response retains memory of fast forcing", fontsize=18, y=0.97) left.fill_between(x, mean - spread, mean + spread, color="#bad6eb", alpha=1, label="Mean ± one standard deviation") left.plot(x, mean, color="#145d8a", linewidth=2.5, label="Step-forced mean") left.axhline(forcing / restoring, color="#9b5c16", linestyle="--", linewidth=1.4, label="Equilibrium mean: 2 K") t_one = forcing / restoring * (1 - np.exp(-1)) left.plot([1], [t_one], "o", color="#145d8a", markersize=6) left.annotate("At one response time:\nmean = 1.264 K", (1, t_one), xytext=(1.48, 0.60), fontsize=10, arrowprops={"arrowstyle": "->", "color": "#145d8a"}) left.set(title="A. A step forcing, starting at exactly zero", xlabel=r"Time / response time, $t/\tau$", ylabel="Temperature anomaly (K)", xlim=(0, 5), ylim=(-0.15, 2.75)) left.legend(loc="upper left", fontsize=9, frameon=False) left.grid(alpha=0.22) right.loglog(w_tau, spectrum_ratio, color="#8f3456", linewidth=2.5) right.axvline(1, color="#75808c", linestyle=":", linewidth=1.3) right.axhline(0.5, color="#75808c", linestyle=":", linewidth=1.3) right.plot([1], [0.5], "o", color="#8f3456") right.annotate("Half-power corner\nωτ = 1", (1, 0.5), xytext=(2.7, 0.6), fontsize=10, arrowprops={"arrowstyle": "->", "color": "#8f3456"}) right.text(0.022, 0.24, "Low-frequency\nplateau", fontsize=11) right.text(3.4, 0.0017, "Fast fluctuations\nare suppressed", fontsize=11) right.set(title="B. Stationary unforced temperature spectrum", xlabel=r"Angular frequency × response time, $|\omega|\tau$", ylabel=r"Normalized spectrum, $S_T(\omega)/S_T(0)$", xlim=(0.01, 100), ylim=(6e-5, 1.65)) right.grid(which="both", alpha=0.18) fig.text(0.5, 0.075, f"Chosen model: τ = {tau / (365.25 * 86400):.2f} years; " f"stationary standard deviation = {np.sqrt(variance):.2f} K. " "The shaded spread grows from a fixed initial value.", ha="center", fontsize=10) fig.text(0.5, 0.025, "Analytic model curves, not observed climate data.", ha="center", fontsize=11, color="#405464") fig.subplots_adjust(left=0.07, right=0.98, bottom=0.22, top=0.84, wspace=0.30) fig.savefig(Path.cwd() / (Path(__file__).stem + ".png"), facecolor="white", transparent=False) plt.close(fig) if __name__ == "__main__": main()