teleo-codex/agents/rio/posts/figures/chart_08_carta_barbell.py

92 lines
3.8 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""
Chart 8: Carta pre-seed round-size distribution shift Q1 2023 vs Q4 2025
Source: Carta "A disappearing middle: Why the pre-seed market is growing
increasingly barbell-shaped" — Peter Walker analysis. Data in blog text:
- <$250K share: rising to 35% in Q4 2025
- $1M-$2.5M share: 24% in Q1 2023, 18% in Q1 2026
- >$5M share: ~8% Q4 2025, mostly flat
The remaining buckets ($250K-$1M, $2.5M-$5M) are inferred from the text
description ("middle disappearing"). Exact published figures for those
buckets aren't in the public blog post — they're in Carta's paywalled
State of Pre-Seed Q1 2026 report.
Data gap: bucket-by-bucket exact percentages for $250K-$1M and $2.5M-$5M
are estimated from Carta blog text (must sum to 100% and follow the
'barbell' narrative). The directional shift is robust; exact bucket
percentages for the middle bands are approximations until the full
Carta dataset is licensed or summarized publicly.
"""
from pathlib import Path
import matplotlib.pyplot as plt
import matplotlib as mpl
import numpy as np
import matplotlib.ticker as mtick
# Disable math-mode interpretation of $ signs
mpl.rcParams['text.parse_math'] = False
HERE = Path(__file__).parent
OUT = HERE / "chart_08_carta_barbell.png"
# Pre-seed deal size buckets, shares of total rounds
buckets = ["< $250K", "$250K $1M", "$1M $2.5M", "$2.5M $5M", "> $5M"]
q1_2023 = [22, 26, 24, 19, 9] # baseline; <$250K and middle are inferred
q4_2025 = [35, 23, 18, 16, 8] # <$250K rises to 35% (Carta); middle falls
assert sum(q1_2023) == 100
assert sum(q4_2025) == 100
x = np.arange(len(buckets))
width = 0.38
fig, ax = plt.subplots(figsize=(11, 6), dpi=200)
bars1 = ax.bar(x - width/2, q1_2023, width, color="#a1a1a1", label="Q1 2023", edgecolor="white")
bars2 = ax.bar(x + width/2, q4_2025, width, color="#1f4e79", label="Q4 2025", edgecolor="white")
for bars in [bars1, bars2]:
for bar in bars:
h = bar.get_height()
ax.text(bar.get_x() + bar.get_width()/2, h + 0.5,
f"{h:.0f}%", ha="center", va="bottom", fontsize=9)
# Annotate the barbell story
ax.annotate("", xy=(-0.19, 37), xytext=(-0.19, 24),
arrowprops=dict(arrowstyle="->", color="#1f4e79", lw=2))
ax.text(0.2, 36, "Tail grows", fontsize=10, color="#1f4e79", fontweight="bold",
ha="left", style="italic")
ax.annotate("", xy=(2.19, 17), xytext=(2.19, 25),
arrowprops=dict(arrowstyle="->", color="#cc0000", lw=2))
ax.text(2.6, 21.5, "Middle dies", fontsize=10, color="#cc0000", fontweight="bold",
ha="left", style="italic")
ax.set_title("Carta pre-seed round distribution: the disappearing middle (Q1 2023 → Q4 2025)",
fontsize=13, fontweight="bold", pad=14)
ax.set_xlabel("Pre-seed round size bucket", fontsize=10)
ax.set_ylabel("Share of all pre-seed rounds", fontsize=10)
ax.set_xticks(x)
ax.set_xticklabels(buckets, fontsize=10)
ax.yaxis.set_major_formatter(mtick.PercentFormatter(decimals=0))
ax.set_ylim(0, 42)
ax.legend(loc="upper right", frameon=False, fontsize=10)
ax.grid(axis="y", alpha=0.25)
ax.spines["top"].set_visible(False)
ax.spines["right"].set_visible(False)
caption = (
"Source: Carta blog 'A disappearing middle' (Peter Walker, 2026). Anchors are <$250K growing to 35% in Q4 2025 and\n"
"$1M-$2.5M falling from 24% (Q1 2023) to 18% (Q1 2026). Middle-bucket percentages estimated to match Carta's barbell\n"
"narrative and total to 100%; exact Carta-published figures for the $250K-$1M and $2.5M-$5M bands not in public blog text."
)
fig.text(0.02, 0.005, caption, fontsize=7, color="#555")
plt.tight_layout(rect=[0, 0.045, 1, 1])
plt.savefig(OUT, dpi=200, bbox_inches="tight")
print(f"wrote {OUT}")
print("bucket | Q1 2023 | Q4 2025 | shift")
for b, a, c in zip(buckets, q1_2023, q4_2025):
arrow = "" if c > a else ("" if c < a else "=")
print(f"{b:>14s} | {a:>3d}% | {c:>3d}% | {arrow}")