"""Agent Adoption Survey Comparison Chart Grouped horizontal bar chart comparing key enterprise AI adoption metrics across three major 2025 surveys: LangChain, McKinsey, and PwC. """ import matplotlib matplotlib.use("Agg") # Patch matplotlib Path.__deepcopy__ to break Python 3.14 recursion loop try: from matplotlib.path import Path _original_path_deepcopy = Path.__deepcopy__ def _safe_path_deepcopy(self, memo): if id(self) in memo: return memo[id(self)] memo[id(self)] = self return self Path.__deepcopy__ = _safe_path_deepcopy except Exception: pass import matplotlib.pyplot as plt import matplotlib.colors as mcolors import matplotlib.patches as mpatches from src.data.agent_adoption import agent_survey_data from src.utils.styling import ( get_theme, EXPORT_DPI, AGENT_GROWTH, GRAY_DARK, BLACK, WHITE, GRAY_LIGHT, ) def _shade(base_hex: str, factor: float) -> str: """Lighten or darken a hex color by a given factor (0–1).""" r, g, b = mcolors.to_rgb(base_hex) # Blend toward white to lighten r2 = r + (1.0 - r) * factor g2 = g + (1.0 - g) * factor b2 = b + (1.0 - b) * factor return mcolors.to_hex((r2, g2, b2)) def plot_agent_adoption() -> str: """Generate grouped horizontal bar chart of survey comparisons.""" plt.rcParams.update(get_theme()) fig, ax = plt.subplots(figsize=(14, 8)) # ------------------------------------------------------------------ # Data # ------------------------------------------------------------------ lc = agent_survey_data["langchain_2025"] mc = agent_survey_data["mckinsey_2025"] pc = agent_survey_data["pwc_2025"] # Each row is a comparable category; values are [LangChain, McKinsey, PwC] # Where a survey has no direct comparable metric, we use None. categories = [ "Production\nDeployment", "Overall\nAI Adoption", "Budget\nIncrease", "Scaling\nAgentic AI", "Productivity\nValue", ] # Values mapped to closest comparable metrics values = [ # Production / Deployment [lc["production"], None, pc["ai_agents_already_adopted"]], # Overall AI Adoption / Maturity [lc["observability_implemented"], mc["overall_ai_adoption"], None], # Budget / Investment Intent [lc["multi_model_deployments"], None, pc["plan_increase_ai_budgets"]], # Scaling / Experimentation [None, mc["agentic_ai_scaling"], None], # Measurable Value / Productivity [None, None, pc["measurable_productivity_value"]], ] # Survey identifiers surveys = [ "LangChain\n(n=1,340)", "McKinsey\n(n=1,993)", "PwC\n(n=308)", ] # Colors: base AGENT_GROWTH with increasing lightness colors = [ AGENT_GROWTH, # LangChain — full purple _shade(AGENT_GROWTH, 0.25), # McKinsey — lighter _shade(AGENT_GROWTH, 0.50), # PwC — lightest ] # ------------------------------------------------------------------ # Plotting # ------------------------------------------------------------------ n_cats = len(categories) bar_height = 0.22 x_positions = [0, 1, 2] # offset within each group y_positions = [] for i in range(n_cats): base_y = i * 3 # three bars per category y_positions.append([base_y + off for off in [0.0, 0.22, 0.44]]) # Plot bars for row_idx, (cat, row_vals) in enumerate(zip(categories, values)): for col_idx, val in enumerate(row_vals): if val is None: continue y = y_positions[row_idx][col_idx] ax.barh(y, val, height=bar_height, color=colors[col_idx], edgecolor=WHITE, linewidth=0.8, label=surveys[col_idx] if row_idx == 0 else None) # Value label on bar ax.text(val + 1.0, y, f"{val:.1f}%", va="center", fontsize=9, color=GRAY_DARK, fontweight="bold") # Y-axis: category labels centered on each group group_centers = [i * 3 + 0.22 for i in range(n_cats)] ax.set_yticks(group_centers) ax.set_yticklabels(categories, fontsize=11, fontweight="bold") # Inset legend-like labels inside each group legend_y_offset = 0.55 for col_idx in range(3): ax.text(-0.5, group_centers[0] + legend_y_offset - col_idx * 0.22, surveys[col_idx], fontsize=8, color=colors[col_idx], ha="left", va="center", fontweight="bold") # Axis config ax.set_xlim(0, 105) ax.set_xlabel("Percentage (%)", fontsize=11, color=GRAY_DARK) ax.set_xticks(range(0, 106, 10)) ax.tick_params(axis="x", labelsize=9) # Grid ax.xaxis.grid(True, alpha=0.3, color=GRAY_LIGHT) ax.yaxis.grid(False) # Spine cleanup ax.spines["top"].set_visible(False) ax.spines["right"].set_visible(False) ax.spines["left"].set_color("#cccccc") ax.spines["bottom"].set_color("#cccccc") # Title ax.set_title( "Enterprise Agent Adoption — Survey Comparison", fontsize=18, fontweight="bold", pad=16, color=BLACK, ) ax.text( 0.5, -0.18, "LangChain (n=1,340) | McKinsey (n=1,993) | PwC (n=308)", transform=ax.transAxes, fontsize=11, color=GRAY_DARK, ha="center", ) # Legend handles = [] for col_idx in range(3): handles.append( mpatches.Rectangle((0, 0), 1, 1, color=colors[col_idx], alpha=1) ) ax.legend(handles, surveys, loc="lower right", fontsize=9, frameon=True, edgecolor="#cccccc") # Adjust layout fig.subplots_adjust(left=0.28, right=0.95, top=0.85, bottom=0.10) # Save out_path = "output/charts/10_agent_adoption.png" fig.savefig(out_path, dpi=EXPORT_DPI, facecolor=fig.get_facecolor(), edgecolor="none") plt.close(fig) return out_path def main(): path = plot_agent_adoption() print(f"Chart saved: {path}") if __name__ == "__main__": main()