Skip to content

Instantly share code, notes, and snippets.

@ajdavis
Created April 6, 2026 02:03
Show Gist options
  • Select an option

  • Save ajdavis/73d7d5fb3fd39dd7c75e0ef59241c2d4 to your computer and use it in GitHub Desktop.

Select an option

Save ajdavis/73d7d5fb3fd39dd7c75e0ef59241c2d4 to your computer and use it in GitHub Desktop.
Living vs. cumulative dead through history, 10,000 BCE to 2100 CE
"""Living vs. cumulative dead through history, 10,000 BCE to 2100 CE.
Cumulative births anchored to PRB (Haub & Kaneda 2022) era totals (~117B by 2022).
Living interpolated from standard population benchmarks; post-2022 follows UN WPP 2024
medium variant. Dead = ever-born - living.
"""
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.ticker import FuncFormatter
# PRB era cumulative births, scaled to hit 117B at 2022.
prb_cum = [
(-10000, 0.9),
(-8000, 1.2),
(1, 51.1),
(1200, 79.9),
(1650, 93.8),
(1750, 97.2),
(1850, 101.6),
(1900, 104.7),
(1950, 108.4),
(2000, 113.9),
(2022, 117.0),
(2050, 117.0 + 0.130 * 28),
(2100, 117.0 + 0.130 * 28 + 0.115 * 50),
]
# Living population benchmarks (millions)
pop_knots = [
(-10000, 4), (-8000, 5), (-1000, 50), (1, 300), (1000, 310),
(1500, 500), (1650, 500), (1750, 795), (1800, 980), (1850, 1260),
(1900, 1650), (1950, 2520), (1970, 3700), (2000, 6070), (2022, 7960),
(2050, 9700), (2086, 10300), (2100, 10200),
]
years = np.arange(-10000, 2101)
cum_years = np.array([c[0] for c in prb_cum])
cum_vals = np.array([c[1] for c in prb_cum]) * 1e9
cum_births = np.interp(years, cum_years, cum_vals)
knot_years = np.array([k[0] for k in pop_knots])
knot_pops = np.array([k[1] for k in pop_knots]) * 1e6
pop = np.exp(np.interp(years, knot_years, np.log(knot_pops)))
dead = cum_births - pop
ratio = dead / pop
# x = years before 2101, log-scaled then inverted so modern era gets spread
# out on the right and ancient era gets compressed on the left.
x = 2101 - years
def year_fmt(val, _):
y = 2101 - val
if y <= 0:
return f"{-y+1} BCE"
if y < 1000:
return f"{int(y)} CE"
return f"{int(y)}"
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(10, 7), sharex=True)
ax1.plot(x, dead / 1e9, color="#444", lw=2, label="Cumulative dead")
ax1.plot(x, pop / 1e9, color="#c44", lw=2, label="Living")
ax1.set_xscale("log")
ax1.set_yscale("log")
ax1.invert_xaxis()
ax1.set_ylabel("People (billions, log scale)")
ax1.set_ylim(0.001, 200)
ax1.grid(which="both", alpha=0.3)
ax1.legend(loc="upper left", framealpha=0.9)
ax1.set_title("The living, the dead, and their ratio (10,000 BCE – 2100 CE)")
ax2.plot(x, ratio, color="#2a7", lw=2)
ax2.set_xscale("log")
ax2.set_yscale("log")
ax2.set_ylabel("Dead per living (log scale)")
ax2.set_xlabel("Year")
ax2.set_ylim(1, 3000)
ax2.grid(which="both", alpha=0.3)
# Put ticks at recognizable years
tick_years = [-10000, -3000, -1000, 1, 1000, 1500, 1800, 1900, 1950, 2000, 2050, 2100]
tick_x = [2101 - y for y in tick_years]
tick_labels = ["10000 BCE", "3000 BCE", "1000 BCE", "1 CE",
"1000", "1500", "1800", "1900", "1950", "2000", "2050", "2100"]
ax2.set_xticks(tick_x)
ax2.set_xticklabels(tick_labels, rotation=30, ha="right")
ax2.minorticks_off()
plt.tight_layout()
out = "/Users/emptysquare/co/emptysquare-hugo/emptysquare/content/the-dead-majority/dead-living.png"
plt.savefig(out, dpi=150)
print("saved", out)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment