{"spec_id":"curve-bias-variance-tradeoff","library":"seaborn","language":"python","code":"\"\"\" anyplot.ai\ncurve-bias-variance-tradeoff: Bias-Variance Tradeoff Curve\nLibrary: seaborn 0.13.2 | Python 3.13.13\nQuality: 90/100 | Updated: 2026-05-28\n\"\"\"\n\nimport os\n\nimport matplotlib.pyplot as plt\nimport numpy as np\nimport seaborn as sns\n\n\n# Theme tokens\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\n# Imprint palette — semantic assignments for bias-variance curves\nC_BIAS = \"#009E73\"  # position 1 brand green — decreasing / improving direction\nC_VAR = \"#C475FD\"  # position 2 lavender — increasing / overfitting direction\nC_TOTAL = \"#AE3030\"  # position 5 matte red — semantic: error / loss\nC_IRRED = INK_MUTED  # adaptive muted — baseline / noise floor\n\n# Data — theoretical curves\ncomplexity = np.linspace(0.5, 10, 100)\nbias_squared = 2.5 / (1 + 0.5 * complexity)\nvariance = 0.05 * complexity**1.5\nirreducible_error = np.full_like(complexity, 0.3)\ntotal_error = bias_squared + variance + irreducible_error\n\noptimal_idx = np.argmin(total_error)\noptimal_complexity = complexity[optimal_idx]\noptimal_error = total_error[optimal_idx]\n\n# Seaborn theme\nsns.set_theme(\n    style=\"ticks\",\n    rc={\n        \"figure.facecolor\": PAGE_BG,\n        \"axes.facecolor\": PAGE_BG,\n        \"axes.edgecolor\": INK_SOFT,\n        \"axes.labelcolor\": INK,\n        \"text.color\": INK,\n        \"xtick.color\": INK_SOFT,\n        \"ytick.color\": INK_SOFT,\n        \"grid.color\": INK,\n        \"grid.alpha\": 0.15,\n        \"legend.facecolor\": ELEVATED_BG,\n        \"legend.edgecolor\": INK_SOFT,\n    },\n)\n\n# Plot\nfig, ax = plt.subplots(figsize=(8, 4.5), dpi=400)\nfig.set_facecolor(PAGE_BG)\nax.set_facecolor(PAGE_BG)\n\n# Shaded underfitting / overfitting zones (behind curves)\nax.axvspan(0.5, optimal_complexity, alpha=0.07, color=C_BIAS, zorder=0)\nax.axvspan(optimal_complexity, 10, alpha=0.07, color=C_VAR, zorder=0)\n\n# Main curves via seaborn lineplot\nsns.lineplot(x=complexity, y=bias_squared, color=C_BIAS, linewidth=2.5, label=\"Bias²\", ax=ax)\nsns.lineplot(x=complexity, y=variance, color=C_VAR, linewidth=2.5, label=\"Variance\", ax=ax)\nsns.lineplot(\n    x=complexity, y=irreducible_error, color=C_IRRED, linewidth=2.0, linestyle=\"--\", label=\"Irreducible Error\", ax=ax\n)\nsns.lineplot(x=complexity, y=total_error, color=C_TOTAL, linewidth=3.5, label=\"Total Error\", ax=ax)\n\n# Optimal complexity marker\nax.axvline(x=optimal_complexity, color=C_BIAS, linestyle=\":\", linewidth=1.8, alpha=0.7, zorder=2)\nax.scatter([optimal_complexity], [optimal_error], s=80, color=C_BIAS, zorder=6, edgecolor=PAGE_BG, linewidth=1.5)\n\n# Direct curve annotations\nax.annotate(\"Bias²\", xy=(1.4, bias_squared[9] + 0.13), fontsize=8, color=C_BIAS, fontweight=\"bold\")\nax.annotate(\"Variance\", xy=(8.2, variance[80] + 0.13), fontsize=8, color=C_VAR, fontweight=\"bold\")\nax.annotate(\"Total Error\", xy=(7.3, total_error[70] + 0.18), fontsize=8, color=C_TOTAL, fontweight=\"bold\")\nax.annotate(\"Irreducible\\nError\", xy=(1.8, 0.40), fontsize=7, color=C_IRRED, fontweight=\"bold\")\n\n# Zone labels\nax.text(2.1, 2.75, \"Underfitting\\n(High Bias)\", fontsize=7, ha=\"center\", color=C_BIAS, alpha=0.8, fontweight=\"bold\")\nax.text(7.8, 2.75, \"Overfitting\\n(High Variance)\", fontsize=7, ha=\"center\", color=C_VAR, alpha=0.8, fontweight=\"bold\")\n\n# Optimal complexity annotation\nax.annotate(\n    \"Optimal\\nComplexity\",\n    xy=(optimal_complexity, optimal_error),\n    xytext=(optimal_complexity + 1.0, optimal_error + 0.5),\n    fontsize=7,\n    ha=\"left\",\n    color=C_BIAS,\n    fontweight=\"bold\",\n    arrowprops={\"arrowstyle\": \"->\", \"color\": C_BIAS, \"lw\": 1.5},\n)\n\n# Formula box — bottom-right to avoid legend overlap\nax.text(\n    0.99,\n    0.03,\n    r\"Total Error = Bias² + Variance + $\\epsilon$\",\n    transform=ax.transAxes,\n    fontsize=7,\n    verticalalignment=\"bottom\",\n    horizontalalignment=\"right\",\n    bbox={\"boxstyle\": \"round,pad=0.4\", \"facecolor\": ELEVATED_BG, \"edgecolor\": INK_SOFT, \"alpha\": 0.9},\n    color=INK,\n)\n\n# Title and axis labels\ntitle = \"curve-bias-variance-tradeoff · python · seaborn · anyplot.ai\"\nn = len(title)\nratio = 67 / n if n > 67 else 1.0\ntitle_fontsize = max(8, round(12 * ratio))\n\nax.set_title(title, fontsize=title_fontsize, fontweight=\"medium\", color=INK)\nax.set_xlabel(\"Model Complexity\", fontsize=10, color=INK)\nax.set_ylabel(\"Prediction Error\", fontsize=10, color=INK)\nax.tick_params(axis=\"both\", labelsize=8, colors=INK_SOFT)\n\nax.set_xlim(0.5, 10)\nax.set_ylim(0, 3.8)\nax.set_xticks([1, 3, 5, 7, 9])\nax.set_xticklabels([\"Low\", \"\", \"Medium\", \"\", \"High\"])\n\n# Subtle y-axis grid\nax.yaxis.grid(True, alpha=0.15, linewidth=0.8, color=INK)\n\n# Spines — L-shaped frame\nax.spines[\"top\"].set_visible(False)\nax.spines[\"right\"].set_visible(False)\nfor sp in (\"left\", \"bottom\"):\n    ax.spines[sp].set_color(INK_SOFT)\n\n# Legend — top center, 4 columns\nax.legend(loc=\"upper center\", fontsize=8, ncol=4, framealpha=0.9, bbox_to_anchor=(0.5, 0.99))\n\nplt.savefig(f\"plot-{THEME}.png\", dpi=400, facecolor=PAGE_BG)\n"}