feat(chart): real-world developer AI adoption and code quality

This commit is contained in:
Orchestrator
2026-06-04 17:55:08 -05:00
parent 6c5eb49b15
commit e44721a422

View File

@@ -0,0 +1,222 @@
"""Real-World Developer AI Adoption and Code Quality Chart"""
import sys
from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parent.parent.parent))
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
from src.data.agent_adoption import (
developer_ai_adoption, code_acceptance_rates,
code_quality_in_production, failure_modes
)
from src.utils.styling import (
get_theme, EXPORT_DPI, AGENT_GROWTH, BUBBLE_ZONE,
WARNING_ZONE, NORMAL_ZONE, GRAY_DARK, GRAY_LIGHT
)
def plot_developer_reality() -> str:
plt.rcParams.update(get_theme())
fig = plt.figure(figsize=(16, 12))
fig.set_facecolor("#ffffff")
# --- Layout: 3 panels via GridSpec ---
from matplotlib.gridspec import GridSpec
gs = GridSpec(2, 2, figure=fig,
height_ratios=[1, 1.5],
hspace=0.45, wspace=0.30,
left=0.07, right=0.93, top=0.88, bottom=0.06)
ax1 = fig.add_subplot(gs[0, 0]) # Panel A — Adoption
ax2 = fig.add_subplot(gs[0, 1]) # Panel B — Acceptance
ax3 = fig.add_subplot(gs[1, :]) # Panel C — Code Quality (full width)
# =========================================================
# Panel A: AI Coding Tool Adoption Rates
# =========================================================
adoption_labels = [
"84% use or plan AI tools\n(Stack Overflow 2025)",
"51% professional devs\nuse AI daily (Stack Overflow)",
"85% regular AI usage\n(JetBrains 2025)",
"62% rely on coding\nassistant (JetBrains)",
"91% AI adoption in active\nrepos (DX DevCycle)",
]
adoption_values = [84, 51, 85, 62, 91]
adoption_colors = [
AGENT_GROWTH, AGENT_GROWTH,
"#5b2d8e", "#3c1d6e",
AGENT_GROWTH,
]
bars_a = ax1.barh(
range(len(adoption_labels)),
adoption_values,
color=adoption_colors,
edgecolor="white",
height=0.55,
)
ax1.set_yticks(range(len(adoption_labels)))
ax1.set_yticklabels(adoption_labels, fontsize=9.5)
ax1.set_xlim(0, 105)
ax1.set_xticks(range(0, 110, 10))
ax1.tick_params(axis="x", labelsize=8)
ax1.invert_yaxis()
for bar, val in zip(bars_a, adoption_values):
ax1.text(val + 1.5, bar.get_y() + bar.get_height() / 2,
f"{val}%", va="center", fontsize=10,
fontweight="bold", color=GRAY_DARK)
ax1.set_title("AI Coding Tool Adoption Rates",
fontsize=14, fontweight="bold", pad=10)
ax1.grid(True, alpha=0.3, axis="x")
ax1.spines["top"].set_visible(False)
ax1.spines["right"].set_visible(False)
# =========================================================
# Panel B: Code Acceptance Rates
# =========================================================
acceptance_labels = [
"~30% acceptance rate\n(GitHub Copilot)",
"88% code retention rate\n(GitHub Copilot)",
"22% of merged code is\nAI-authored (DX DevCycle)",
"71% do NOT merge AI code\nwithout manual review",
]
acceptance_values = [30, 88, 22, 71]
acceptance_colors = [
WARNING_ZONE, # 30% acceptance — warning
NORMAL_ZONE, # 88% retention — good
AGENT_GROWTH, # 22% AI-authored — neutral
GRAY_DARK, # 71% manual review — caution signal
]
bars_b = ax2.barh(
range(len(acceptance_labels)),
acceptance_values,
color=acceptance_colors,
edgecolor="white",
height=0.55,
)
ax2.set_yticks(range(len(acceptance_labels)))
ax2.set_yticklabels(acceptance_labels, fontsize=9.5)
ax2.set_xlim(0, 105)
ax2.set_xticks(range(0, 110, 10))
ax2.tick_params(axis="x", labelsize=8)
ax2.invert_yaxis()
for bar, val in zip(bars_b, acceptance_values):
ax2.text(val + 1.5, bar.get_y() + bar.get_height() / 2,
f"{val}%", va="center", fontsize=10,
fontweight="bold", color=GRAY_DARK)
ax2.set_title("Code Acceptance Rates",
fontsize=14, fontweight="bold", pad=10)
ax2.grid(True, alpha=0.3, axis="x")
ax2.spines["top"].set_visible(False)
ax2.spines["right"].set_visible(False)
# Annotation: adoption vs acceptance gap
ax2.annotate(
"HUGE GAP:\nHigh adoption,\nlow acceptance",
xy=(30, 1.8), xytext=(58, 0.8),
arrowprops=dict(arrowstyle="->", color=BUBBLE_ZONE, lw=2),
fontsize=10, fontweight="bold", color=BUBBLE_ZONE,
ha="center",
bbox=dict(boxstyle="round,pad=0.3", facecolor=GRAY_LIGHT,
edgecolor=BUBBLE_ZONE, linewidth=1.2),
)
# =========================================================
# Panel C: Code Quality in Production
# =========================================================
quality_labels = [
"29.1% Python AI code has\nsecurity weaknesses",
"24.2% JavaScript AI code has\nsecurity weaknesses",
"48% AI-generated code has\npotential vulnerabilities",
"1.7x more issues in\nAI-coauthored PRs (CodeRabbit)",
"7.2% drop in delivery\nstability (Google DORA)",
]
quality_values = [29.1, 24.2, 48, 1.7, 7.2]
# All bars use BUBBLE_ZONE to signal danger
quality_colors = [BUBBLE_ZONE] * len(quality_labels)
bars_c = ax3.barh(
range(len(quality_labels)),
quality_values,
color=quality_colors,
edgecolor="white",
height=0.45,
)
ax3.set_yticks(range(len(quality_labels)))
ax3.set_yticklabels(quality_labels, fontsize=10)
# X-axis scaled to the max value
ax3.set_xlim(0, max(quality_values) * 1.25)
ax3.set_xticks([0, 10, 20, 30, 40, 50])
ax3.tick_params(axis="x", labelsize=9)
ax3.invert_yaxis()
for bar, val in zip(bars_c, quality_values):
label = f"{val}x" if val < 5 and val != int(val) else f"{val}"
ax3.text(val + 1, bar.get_y() + bar.get_height() / 2,
label, va="center", fontsize=11,
fontweight="bold", color="#c0392b")
ax3.set_title("Code Quality Concerns in Production",
fontsize=14, fontweight="bold", pad=10,
color=BUBBLE_ZONE)
ax3.grid(True, alpha=0.3, axis="x")
ax3.spines["top"].set_visible(False)
ax3.spines["right"].set_visible(False)
# =========================================================
# Figure-level title and disclaimer
# =========================================================
fig.suptitle(
"Real-World Developer AI: Adoption vs. Code Quality",
fontsize=18, fontweight="bold", y=0.96,
color=GRAY_DARK,
)
fig.text(
0.5, 0.925,
"Benchmarks measure lab tasks, not production shipping",
ha="center", fontsize=13, style="italic",
color=GRAY_DARK, alpha=0.8,
)
# Prominent disclaimer banner
fig.text(
0.5, 0.015,
"⚠ Benchmarks measure controlled lab tasks, NOT production shipping",
ha="center", fontsize=12, fontweight="bold",
color=BUBBLE_ZONE,
bbox=dict(
boxstyle="round,pad=0.5",
facecolor=GRAY_LIGHT,
edgecolor=BUBBLE_ZONE,
linewidth=2,
),
)
# =========================================================
# Save
# =========================================================
out_path = "output/charts/12_developer_ai_reality.png"
fig.savefig(
out_path, dpi=EXPORT_DPI,
facecolor=fig.get_facecolor(),
edgecolor="none",
)
plt.close(fig)
return out_path
def main():
path = plot_developer_reality()
print(f"Chart saved: {path}")
if __name__ == "__main__":
main()