{"spec_id":"calibration-curve","library":"matplotlib","language":"python","code":"\"\"\" anyplot.ai\ncalibration-curve: Calibration Curve\nLibrary: matplotlib 3.10.9 | Python 3.13.13\nQuality: 93/100 | Updated: 2026-05-10\n\"\"\"\n\nimport os\n\nimport matplotlib.pyplot as plt\nimport numpy as np\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\"\n\n# Okabe-Ito palette - canonical order\nIMPRINT = [\"#009E73\", \"#C475FD\", \"#4467A3\", \"#BD8233\"]\nBRAND = IMPRINT[0]  # #009E73\n\n# Data\nnp.random.seed(42)\nn_samples = 2000\nn_bins = 10\n\ny_true = np.random.binomial(1, 0.35, n_samples)\n\nlogits_calibrated = 1.2 * (y_true * 2 - 1) + np.random.normal(0, 1.0, n_samples)\ny_prob_calibrated = 1 / (1 + np.exp(-logits_calibrated))\n\nlogits_over = 2.0 * (y_true * 2 - 1) + np.random.normal(0, 0.5, n_samples)\ny_prob_overconfident = 1 / (1 + np.exp(-logits_over))\n\nlogits_under = 0.5 * (y_true * 2 - 1) + np.random.normal(0, 0.8, n_samples)\ny_prob_underconfident = 1 / (1 + np.exp(-logits_under))\n\nbin_edges = np.linspace(0, 1, n_bins + 1)\n\n# Calculate calibration curves - well-calibrated\nbin_idx_cal = np.digitize(y_prob_calibrated, bin_edges[1:-1])\nprob_true_cal = np.array([np.mean(y_true[bin_idx_cal == i]) for i in range(n_bins) if np.sum(bin_idx_cal == i) > 0])\nprob_pred_cal = np.array(\n    [np.mean(y_prob_calibrated[bin_idx_cal == i]) for i in range(n_bins) if np.sum(bin_idx_cal == i) > 0]\n)\nprob_std_cal = np.array(\n    [\n        np.std(y_true[bin_idx_cal == i]) / np.sqrt(np.sum(bin_idx_cal == i))\n        for i in range(n_bins)\n        if np.sum(bin_idx_cal == i) > 0\n    ]\n)\n\n# Calculate calibration curves - overconfident\nbin_idx_over = np.digitize(y_prob_overconfident, bin_edges[1:-1])\nprob_true_over = np.array([np.mean(y_true[bin_idx_over == i]) for i in range(n_bins) if np.sum(bin_idx_over == i) > 0])\nprob_pred_over = np.array(\n    [np.mean(y_prob_overconfident[bin_idx_over == i]) for i in range(n_bins) if np.sum(bin_idx_over == i) > 0]\n)\nprob_std_over = np.array(\n    [\n        np.std(y_true[bin_idx_over == i]) / np.sqrt(np.sum(bin_idx_over == i))\n        for i in range(n_bins)\n        if np.sum(bin_idx_over == i) > 0\n    ]\n)\n\n# Calculate calibration curves - underconfident\nbin_idx_under = np.digitize(y_prob_underconfident, bin_edges[1:-1])\nprob_true_under = np.array(\n    [np.mean(y_true[bin_idx_under == i]) for i in range(n_bins) if np.sum(bin_idx_under == i) > 0]\n)\nprob_pred_under = np.array(\n    [np.mean(y_prob_underconfident[bin_idx_under == i]) for i in range(n_bins) if np.sum(bin_idx_under == i) > 0]\n)\nprob_std_under = np.array(\n    [\n        np.std(y_true[bin_idx_under == i]) / np.sqrt(np.sum(bin_idx_under == i))\n        for i in range(n_bins)\n        if np.sum(bin_idx_under == i) > 0\n    ]\n)\n\nbrier_cal = np.mean((y_prob_calibrated - y_true) ** 2)\nbrier_over = np.mean((y_prob_overconfident - y_true) ** 2)\nbrier_under = np.mean((y_prob_underconfident - y_true) ** 2)\n\n# Plot\nfig, (ax1, ax2) = plt.subplots(2, 1, figsize=(16, 9), gridspec_kw={\"height_ratios\": [3, 1]}, facecolor=PAGE_BG)\nax1.set_facecolor(PAGE_BG)\nax2.set_facecolor(PAGE_BG)\n\n# Calibration curves with confidence bands\nax1.plot([0, 1], [0, 1], \"--\", linewidth=2, color=INK_SOFT, label=\"Perfect Calibration\", alpha=0.6)\n\n# Well-calibrated\nax1.fill_between(\n    prob_pred_cal, prob_true_cal - prob_std_cal, prob_true_cal + prob_std_cal, alpha=0.2, color=IMPRINT[0]\n)\nax1.plot(\n    prob_pred_cal,\n    prob_true_cal,\n    \"o-\",\n    color=IMPRINT[0],\n    linewidth=3,\n    markersize=10,\n    label=f\"Well-Calibrated (Brier: {brier_cal:.3f})\",\n)\n\n# Overconfident\nax1.fill_between(\n    prob_pred_over, prob_true_over - prob_std_over, prob_true_over + prob_std_over, alpha=0.2, color=IMPRINT[1]\n)\nax1.plot(\n    prob_pred_over,\n    prob_true_over,\n    \"s-\",\n    color=IMPRINT[1],\n    linewidth=3,\n    markersize=10,\n    label=f\"Overconfident (Brier: {brier_over:.3f})\",\n)\n\n# Underconfident\nax1.fill_between(\n    prob_pred_under, prob_true_under - prob_std_under, prob_true_under + prob_std_under, alpha=0.2, color=IMPRINT[2]\n)\nax1.plot(\n    prob_pred_under,\n    prob_true_under,\n    \"^-\",\n    color=IMPRINT[2],\n    linewidth=3,\n    markersize=10,\n    label=f\"Underconfident (Brier: {brier_under:.3f})\",\n)\n\nax1.set_xlabel(\"Mean Predicted Probability (0 to 1)\", fontsize=20, color=INK)\nax1.set_ylabel(\"Fraction of Positives (0 to 1)\", fontsize=20, color=INK)\nax1.set_title(\"calibration-curve · matplotlib · anyplot.ai\", fontsize=24, fontweight=\"medium\", color=INK)\nax1.tick_params(axis=\"both\", labelsize=16, colors=INK_SOFT)\nax1.set_xlim(0, 1)\nax1.set_ylim(0, 1)\n\nleg1 = ax1.legend(fontsize=16, loc=\"lower right\")\nleg1.get_frame().set_facecolor(ELEVATED_BG)\nleg1.get_frame().set_edgecolor(INK_SOFT)\nleg1.get_frame().set_linewidth(0.5)\nfor text in leg1.get_texts():\n    text.set_color(INK_SOFT)\n\nax1.yaxis.grid(True, alpha=0.1, linewidth=0.8, color=INK)\nax1.spines[\"top\"].set_visible(False)\nax1.spines[\"right\"].set_visible(False)\nfor s in (\"left\", \"bottom\"):\n    ax1.spines[s].set_color(INK_SOFT)\n\n# Histogram\nax2.hist(\n    y_prob_calibrated, bins=20, alpha=0.6, color=IMPRINT[0], label=\"Well-Calibrated\", edgecolor=PAGE_BG, linewidth=0.5\n)\nax2.hist(\n    y_prob_overconfident,\n    bins=20,\n    alpha=0.6,\n    color=IMPRINT[1],\n    label=\"Overconfident\",\n    edgecolor=PAGE_BG,\n    linewidth=0.5,\n)\nax2.hist(\n    y_prob_underconfident,\n    bins=20,\n    alpha=0.6,\n    color=IMPRINT[2],\n    label=\"Underconfident\",\n    edgecolor=PAGE_BG,\n    linewidth=0.5,\n)\n\nax2.set_xlabel(\"Predicted Probability (0 to 1)\", fontsize=20, color=INK)\nax2.set_ylabel(\"Count (Sample Frequency)\", fontsize=20, color=INK)\nax2.tick_params(axis=\"both\", labelsize=16, colors=INK_SOFT)\n\nleg2 = ax2.legend(fontsize=16, loc=\"upper right\")\nleg2.get_frame().set_facecolor(ELEVATED_BG)\nleg2.get_frame().set_edgecolor(INK_SOFT)\nleg2.get_frame().set_linewidth(0.5)\nfor text in leg2.get_texts():\n    text.set_color(INK_SOFT)\n\nax2.yaxis.grid(True, alpha=0.1, linewidth=0.8, color=INK)\nax2.spines[\"top\"].set_visible(False)\nax2.spines[\"right\"].set_visible(False)\nfor s in (\"left\", \"bottom\"):\n    ax2.spines[s].set_color(INK_SOFT)\n\nplt.tight_layout()\nplt.savefig(f\"plot-{THEME}.png\", dpi=300, bbox_inches=\"tight\", facecolor=PAGE_BG)\n"}