{"spec_id":"curve-bias-variance-tradeoff","library":"plotnine","language":"python","code":"\"\"\" anyplot.ai\ncurve-bias-variance-tradeoff: Bias-Variance Tradeoff Curve\nLibrary: plotnine 0.15.4 | Python 3.13.13\nQuality: 88/100 | Created: 2026-05-28\n\"\"\"\n\nimport os\n\nimport numpy as np\nimport pandas as pd\nfrom plotnine import (\n    aes,\n    element_blank,\n    element_line,\n    element_rect,\n    element_text,\n    geom_line,\n    geom_rect,\n    geom_text,\n    geom_vline,\n    ggplot,\n    labs,\n    scale_color_manual,\n    scale_linetype_manual,\n    scale_size_manual,\n    scale_x_continuous,\n    scale_y_continuous,\n    theme,\n)\n\n\nTHEME = os.getenv(\"ANYPLOT_THEME\", \"light\")\nPAGE_BG = \"#FAF8F1\" if THEME == \"light\" else \"#1A1A17\"\nELEVATED_BG = \"#FFFDF6\" if THEME == \"light\" else \"#242420\"\nINK = \"#1A1A17\" if THEME == \"light\" else \"#F0EFE8\"\nINK_SOFT = \"#4A4A44\" if THEME == \"light\" else \"#B8B7B0\"\nINK_MUTED = \"#6B6A63\" if THEME == \"light\" else \"#A8A79F\"\n\nIMPRINT_PALETTE = [\"#009E73\", \"#C475FD\", \"#4467A3\", \"#BD8233\"]\n\n# Data\ncomplexity = np.linspace(0.1, 10, 100)\nn = len(complexity)\nirreducible = 0.20\nbias_sq = 1.0 / (1.0 + complexity * 0.4) ** 0.9\nvariance = 0.018 * complexity**1.6\ntotal_error = bias_sq + variance + irreducible\n\nopt_idx = int(np.argmin(total_error))\nopt_x = float(complexity[opt_idx])\nopt_y = float(total_error[opt_idx])\ny_max = float(np.max(total_error))\n\nseries_order = [\"Bias²\", \"Variance\", \"Irreducible Error\", \"Total Error\"]\n\ndf = pd.DataFrame(\n    {\n        \"complexity\": np.tile(complexity, 4),\n        \"error\": np.concatenate([bias_sq, variance, np.full(n, irreducible), total_error]),\n        \"component\": pd.Categorical(\n            [\"Bias²\"] * n + [\"Variance\"] * n + [\"Irreducible Error\"] * n + [\"Total Error\"] * n, categories=series_order\n        ),\n    }\n)\n\ncolors = dict(zip(series_order, IMPRINT_PALETTE, strict=False))\nlinetypes = {\"Bias²\": \"dashed\", \"Variance\": \"dashed\", \"Irreducible Error\": \"dotted\", \"Total Error\": \"solid\"}\nline_sizes = {\"Bias²\": 0.9, \"Variance\": 0.9, \"Irreducible Error\": 0.7, \"Total Error\": 1.3}\n\n\ndef y_at(arr, x_val):\n    idx = min(int(np.searchsorted(complexity, x_val)), n - 1)\n    return float(arr[idx])\n\n\n# Shaded underfitting (left) / overfitting (right) zones\nzone_df = pd.DataFrame(\n    {\"xmin\": [0.1, opt_x], \"xmax\": [opt_x, 11.5], \"ymin\": [0.0, 0.0], \"ymax\": [y_max * 1.05, y_max * 1.05]}\n)\n\n# Direct curve labels at well-separated positions\ncurve_label_df = pd.DataFrame(\n    {\n        \"x\": [2.2, 8.0, 6.5, 5.8],\n        \"y\": [y_at(bias_sq, 2.2) + 0.06, y_at(variance, 8.0) + 0.05, irreducible - 0.06, y_at(total_error, 5.8) + 0.06],\n        \"label\": [\"Bias²\", \"Variance\", \"Irreducible Error\", \"Total Error\"],\n        \"component\": pd.Categorical([\"Bias²\", \"Variance\", \"Irreducible Error\", \"Total Error\"], categories=series_order),\n    }\n)\n\nopt_label_df = pd.DataFrame({\"x\": [opt_x + 0.25], \"y\": [opt_y - 0.07], \"label\": [\"Optimal\\nComplexity\"]})\n\nformula_df = pd.DataFrame(\n    {\"x\": [5.5], \"y\": [y_max * 0.93], \"label\": [\"Total Error = Bias² + Variance + Irreducible Error\"]}\n)\n\ntitle = \"curve-bias-variance-tradeoff · python · plotnine · anyplot.ai\"\n\nanyplot_theme = theme(\n    figure_size=(8, 4.5),\n    plot_background=element_rect(fill=PAGE_BG, color=PAGE_BG),\n    panel_background=element_rect(fill=PAGE_BG),\n    panel_grid_major_y=element_line(color=INK_MUTED, size=0.3),\n    panel_grid_major_x=element_blank(),\n    panel_grid_minor=element_blank(),\n    panel_border=element_blank(),\n    axis_line=element_line(color=INK_SOFT, size=0.5),\n    axis_ticks=element_line(color=INK_SOFT, size=0.3),\n    axis_title=element_text(color=INK, size=10),\n    axis_text=element_text(color=INK_SOFT, size=8),\n    plot_title=element_text(color=INK, size=12),\n    legend_position=\"none\",\n)\n\n# Plot\nplot = (\n    ggplot(df, aes(x=\"complexity\", y=\"error\", color=\"component\", linetype=\"component\", size=\"component\"))\n    + geom_rect(\n        data=zone_df,\n        mapping=aes(xmin=\"xmin\", xmax=\"xmax\", ymin=\"ymin\", ymax=\"ymax\"),\n        fill=INK_MUTED,\n        alpha=0.07,\n        inherit_aes=False,\n    )\n    + geom_line()\n    + geom_vline(xintercept=opt_x, color=INK_MUTED, linetype=\"dashed\", size=0.5, inherit_aes=False)\n    + geom_text(\n        data=curve_label_df,\n        mapping=aes(x=\"x\", y=\"y\", label=\"label\", color=\"component\"),\n        size=3.5,\n        ha=\"left\",\n        inherit_aes=False,\n    )\n    + geom_text(\n        data=opt_label_df,\n        mapping=aes(x=\"x\", y=\"y\", label=\"label\"),\n        color=INK_MUTED,\n        size=3.2,\n        ha=\"left\",\n        inherit_aes=False,\n    )\n    + geom_text(\n        data=formula_df,\n        mapping=aes(x=\"x\", y=\"y\", label=\"label\"),\n        color=INK_SOFT,\n        size=3.2,\n        ha=\"center\",\n        inherit_aes=False,\n    )\n    + scale_color_manual(values=colors)\n    + scale_linetype_manual(values=linetypes)\n    + scale_size_manual(values=line_sizes)\n    + scale_x_continuous(\n        name=\"Model Complexity\", breaks=[0, 2, 4, 6, 8, 10], labels=[\"Low\", \"\", \"\", \"\", \"\", \"High\"], limits=(0.1, 11.5)\n    )\n    + scale_y_continuous(name=\"Prediction Error\", limits=(0.0, y_max * 1.05))\n    + labs(title=title)\n    + anyplot_theme\n)\n\n# Save\nplot.save(f\"plot-{THEME}.png\", dpi=400, width=8, height=4.5, units=\"in\")\n"}