feat(chart): agentic AI market size forecasts

This commit is contained in:
Orchestrator
2026-06-04 17:54:15 -05:00
parent 05e72224dd
commit 6c5eb49b15

View File

@@ -0,0 +1,177 @@
"""Agent Market Forecasts Chart"""
import matplotlib
matplotlib.use("Agg")
import matplotlib.lines as mlines
import matplotlib.pyplot as plt
import numpy as np
from src.data.agent_adoption import agent_market_forecasts
from src.utils.styling import get_theme, EXPORT_DPI, AGENT_GROWTH, AI_SPEND, GRAY_DARK
def _interpolate_forecast(forecast: dict) -> dict:
"""Interpolate yearly values from start/end using the stated CAGR."""
start_val = forecast["year_2025_billions"]
cagr = forecast["cagr_percent"]
# Determine end year key
if "year_2033_billions" in forecast:
end_key = "year_2033_billions"
end_year = 2033
else:
end_key = "year_2030_billions"
end_year = 2030
end_val = forecast[end_key]
# Interpolate yearly values using CAGR
values = {}
for year in range(2025, 2035):
if year <= end_year:
values[year] = start_val * ((1 + cagr / 100) ** (year - 2025))
else:
# No forecast beyond end year — leave as None
values[year] = None
return {
"source": forecast["source"],
"category": forecast.get("category", ""),
"cagr": cagr,
"start": start_val,
"end_val": end_val,
"end_year": end_year,
"values": values,
}
def plot_market_forecasts() -> str:
plt.rcParams.update(get_theme())
fig, ax = plt.subplots(figsize=(14, 8))
# Define colors per source
colors = {
"Omdia": "#e74c3c",
"BCC Research": "#2980b9",
"MarketsandMarkets": "#27ae60",
"Grand View Research": "#8e44ad",
}
# Process forecasts
processed = [_interpolate_forecast(f) for f in agent_market_forecasts]
all_years = list(range(2025, 2035))
# Collect per-year min/max for shaded band (only where forecasts exist)
min_vals = []
max_vals = []
for year in all_years:
vals = [p["values"][year] for p in processed if p["values"][year] is not None]
if vals:
min_vals.append(min(vals))
max_vals.append(max(vals))
else:
min_vals.append(None)
max_vals.append(None)
# Plot each forecast line
handles = []
labels = []
for p in processed:
pts_x = []
pts_y = []
for year in all_years:
v = p["values"][year]
if v is not None:
pts_x.append(year)
pts_y.append(v)
if pts_x:
label = f'{p["source"]} ({p["cagr"]}% CAGR)'
color = colors.get(p["source"], AI_SPEND)
line, = ax.plot(
pts_x, pts_y,
color=color,
linewidth=2.5,
label=label,
marker="o",
markersize=5,
)
handles.append(line)
labels.append(label)
# Annotate endpoint
ax.annotate(
f"${p['end_val']:.1f}B",
xy=(pts_x[-1], pts_y[-1]),
xytext=(5, 8),
textcoords="offset points",
fontsize=9,
fontweight="bold",
color=color,
)
# Shaded confidence band between min and max
band_x = []
band_min = []
band_max = []
for i, year in enumerate(all_years):
if min_vals[i] is not None:
band_x.append(year)
band_min.append(min_vals[i])
band_max.append(max_vals[i])
if band_x:
ax.fill_between(
band_x, band_min, band_max,
alpha=0.12,
color=AGENT_GROWTH,
label="Forecast Range",
)
handles.append(
mlines.Line2D([], [], color=AGENT_GROWTH, alpha=0.3, linewidth=2)
)
labels.append("Forecast Range")
# Axes configuration
ax.set_yscale("log")
ax.set_ylim(0.8, 250)
ax.set_xlim(2024.5, 2034.5)
ax.set_xticks(all_years)
ax.set_xlabel("Year", fontsize=12)
ax.set_ylabel("Market Size ($ Billions, log scale)", fontsize=12)
ax.set_title(
"Agentic AI Market Size Forecasts",
fontsize=16,
fontweight="bold",
)
# Subtitle
fig.text(
0.5,
0.93,
"Multiple analyst projections 2025\u20132034",
fontsize=11,
ha="center",
style="italic",
color=GRAY_DARK,
)
ax.legend(handles=handles, labels=labels, loc="upper left", fontsize=9)
ax.grid(True, alpha=0.3)
fig.savefig(
"output/charts/11_agent_market_forecasts.png",
dpi=EXPORT_DPI,
facecolor=fig.get_facecolor(),
edgecolor="none",
)
plt.close(fig)
return "output/charts/11_agent_market_forecasts.png"
def main():
path = plot_market_forecasts()
print(f"Chart saved: {path}")
if __name__ == "__main__":
main()