Last active
July 28, 2025 15:04
-
-
Save cavedave/a11fa410a471b4fb50b656e76e3edbe0 to your computer and use it in GitHub Desktop.
staircase.ipynb
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 1) find every record‐breaking year ≥ 1980 | |
post80 = ts.where(ts.index >= 1980) | |
current_max = -np.inf | |
record_years = [] | |
record_values = [] | |
for yr, val in post80.items(): | |
if np.isnan(val): | |
continue | |
if val >= current_max: | |
current_max = val | |
record_years.append(yr) | |
record_values.append(val) | |
# 2) build ALL steps | |
all_steps = [(s, e, y) for s, e, y in zip(record_years, record_years[1:], record_values)] | |
# 3) filter to only multi‑year “flat” periods (>=3 yr) | |
steps = [(s, e, y) for (s, e, y) in all_steps if (e - s) >= 3] | |
# 4) pre‑compute limits & frame list | |
xmin, xmax = ts.index.min(), ts.index.max() | |
ymin, ymax = ts.min() - 0.1, ts.max() + 0.1 | |
frame_files = [] |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import numpy as np | |
import matplotlib.pyplot as plt | |
# Assume df is your DataFrame and ts = df['Anomaly'], indexed by Year | |
# 1) Identify every record-breaking year ≥ 1980 | |
post80 = ts.where(ts.index >= 1980) | |
current = -np.inf | |
records = [] | |
values = [] | |
for yr, val in post80.items(): | |
if np.isnan(val): continue | |
if val >= current: | |
current = val | |
records.append(yr) | |
values.append(val) | |
# 2) Build steps between successive records | |
all_steps = list(zip(records, records[1:], values)) | |
# 3) Keep only multi‑year flats (>=3 yr) | |
steps = [(s, e, y) for s, e, y in all_steps if (e - s) >= 3] | |
# 4) Plot once, statically | |
fig, ax = plt.subplots(figsize=(10, 6)) | |
# zero‑line highlight | |
ax.axhline(0, linestyle='--', linewidth=1, alpha=0.3) | |
# full anomaly series | |
ax.plot(ts.index, ts.values, lw=1, color='lightgray') | |
# draw and label each plateau | |
for s, e, y in steps: | |
ax.hlines(y, s, e, linewidth=3, color='C0') | |
mid = s + (e - s) / 2 | |
ax.text( | |
mid, y + 0.02, | |
f"{e - s}yr", | |
ha='center', va='bottom', | |
fontweight='bold', fontsize=10 | |
) | |
# lock your limits | |
ax.set_xlim(ts.index.min(), ts.index.max()) | |
ax.set_ylim(ts.min() - 0.1, ts.max() + 0.1) | |
# labels & title | |
ax.set_xlabel('Year') | |
ax.set_ylabel('Temperature anomaly (°C)') | |
ax.set_title( | |
"Staircase of Denial\n" | |
"“No Warming in Years”", | |
fontsize=14, fontweight='bold' | |
) | |
# light horizontal grid lines at major ticks | |
ax.grid( | |
True, | |
which='major', | |
axis='y', | |
linestyle='--', | |
linewidth=0.5, | |
alpha=0.3 | |
) | |
# 6) source & notes | |
ax.text(0.99, -0.1, | |
"Source: HadCRUT5 by @iamreddave", | |
ha='right', va='top', | |
transform=ax.transAxes, | |
fontsize=9, color='gray') | |
ax.text(0.20, -0.1, | |
"Anomalies relative to 1961-1990", | |
ha='right', va='top', | |
transform=ax.transAxes, | |
fontsize=9, color='gray') | |
# save | |
output_path = '/content/staircase_static.png' | |
fig.savefig(output_path, dpi=150, bbox_inches='tight') | |
plt.show() | |
print("Saved static image to", output_path) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment