{"spec_id":"calibration-curve","library":"seaborn","language":"python","code":"\"\"\" anyplot.ai\ncalibration-curve: Calibration Curve\nLibrary: seaborn 0.13.2 | Python 3.13.13\nQuality: 87/100 | Updated: 2026-05-10\n\"\"\"\n\nimport matplotlib.pyplot as plt\nimport numpy as np\nimport seaborn as sns\n\n\n# Set seaborn style\nsns.set_theme(style=\"whitegrid\")\n\n# Generate synthetic binary classification data\nnp.random.seed(42)\nn_samples = 2000\n\n# True labels - imbalanced for realism (35% positive class)\ny_true = np.random.binomial(1, 0.35, n_samples)\n\n# Simulate a well-calibrated classifier (predictions close to diagonal)\nbase_probs = y_true * 0.7 + (1 - y_true) * 0.3 + np.random.normal(0, 0.2, n_samples)\ny_prob_calibrated = np.clip(base_probs, 0.01, 0.99)\n\n# Simulate an overconfident classifier (S-shaped: below diagonal on left, above on right)\ny_prob_overconfident = 1 / (1 + np.exp(-5 * (y_prob_calibrated - 0.5)))\ny_prob_overconfident = np.clip(y_prob_overconfident, 0.01, 0.99)\n\n# Simulate an underconfident classifier (inverted S: above diagonal on left, below on right)\ny_prob_underconfident = 0.5 + (y_prob_calibrated - 0.5) * 0.35\ny_prob_underconfident = np.clip(y_prob_underconfident, 0.01, 0.99)\n\n# Compute calibration curves (bin predictions, compute fraction of positives)\nn_bins = 10\nbin_edges = np.linspace(0, 1, n_bins + 1)\n\n# Well-calibrated model calibration curve\nbin_indices_calib = np.digitize(y_prob_calibrated, bin_edges[1:-1])\nprob_true_calib = [np.mean(y_true[bin_indices_calib == i]) for i in range(n_bins) if np.sum(bin_indices_calib == i) > 0]\nprob_pred_calib = [\n    np.mean(y_prob_calibrated[bin_indices_calib == i]) for i in range(n_bins) if np.sum(bin_indices_calib == i) > 0\n]\n\n# Overconfident model calibration curve\nbin_indices_over = np.digitize(y_prob_overconfident, bin_edges[1:-1])\nprob_true_over = [np.mean(y_true[bin_indices_over == i]) for i in range(n_bins) if np.sum(bin_indices_over == i) > 0]\nprob_pred_over = [\n    np.mean(y_prob_overconfident[bin_indices_over == i]) for i in range(n_bins) if np.sum(bin_indices_over == i) > 0\n]\n\n# Underconfident model calibration curve\nbin_indices_under = np.digitize(y_prob_underconfident, bin_edges[1:-1])\nprob_true_under = [np.mean(y_true[bin_indices_under == i]) for i in range(n_bins) if np.sum(bin_indices_under == i) > 0]\nprob_pred_under = [\n    np.mean(y_prob_underconfident[bin_indices_under == i]) for i in range(n_bins) if np.sum(bin_indices_under == i) > 0\n]\n\n# Calculate Brier scores (mean squared error of probability predictions)\nbrier_calib = 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# Create figure with two subplots\nfig, (ax1, ax2) = plt.subplots(1, 2, figsize=(16, 9), gridspec_kw={\"width_ratios\": [2, 1]})\n\n# Colors: Python Blue, Python Yellow, and a third colorblind-safe color\ncolors = [\"#306998\", \"#FFD43B\", \"#8B4513\"]\n\n# Plot calibration curves using seaborn lineplot\nsns.lineplot(\n    x=prob_pred_calib,\n    y=prob_true_calib,\n    ax=ax1,\n    marker=\"o\",\n    markersize=14,\n    linewidth=3,\n    color=colors[0],\n    label=f\"Well-Calibrated (Brier: {brier_calib:.3f})\",\n)\nsns.lineplot(\n    x=prob_pred_over,\n    y=prob_true_over,\n    ax=ax1,\n    marker=\"s\",\n    markersize=12,\n    linewidth=3,\n    color=colors[1],\n    label=f\"Overconfident (Brier: {brier_over:.3f})\",\n)\nsns.lineplot(\n    x=prob_pred_under,\n    y=prob_true_under,\n    ax=ax1,\n    marker=\"^\",\n    markersize=12,\n    linewidth=3,\n    color=colors[2],\n    label=f\"Underconfident (Brier: {brier_under:.3f})\",\n)\n\n# Diagonal reference line for perfect calibration\nax1.plot([0, 1], [0, 1], \"k--\", linewidth=2, alpha=0.7, label=\"Perfectly Calibrated\")\n\n# Styling for calibration plot\nax1.set_xlabel(\"Mean Predicted Probability\", fontsize=20)\nax1.set_ylabel(\"Fraction of Positives\", fontsize=20)\nax1.set_title(\"calibration-curve · seaborn · pyplots.ai\", fontsize=24, pad=15)\nax1.tick_params(axis=\"both\", labelsize=16)\nax1.set_xlim(-0.02, 1.02)\nax1.set_ylim(-0.02, 1.02)\nax1.legend(fontsize=14, loc=\"lower right\")\nax1.grid(True, alpha=0.3, linestyle=\"--\")\nax1.set_aspect(\"equal\")\n\n# Histogram of predicted probabilities using seaborn\nsns.histplot(\n    y_prob_calibrated,\n    ax=ax2,\n    bins=20,\n    color=colors[0],\n    alpha=0.5,\n    label=\"Well-Calibrated\",\n    edgecolor=\"white\",\n    linewidth=0.5,\n)\nsns.histplot(\n    y_prob_overconfident,\n    ax=ax2,\n    bins=20,\n    color=colors[1],\n    alpha=0.5,\n    label=\"Overconfident\",\n    edgecolor=\"white\",\n    linewidth=0.5,\n)\nsns.histplot(\n    y_prob_underconfident,\n    ax=ax2,\n    bins=20,\n    color=colors[2],\n    alpha=0.5,\n    label=\"Underconfident\",\n    edgecolor=\"white\",\n    linewidth=0.5,\n)\n\n# Styling for histogram\nax2.set_xlabel(\"Predicted Probability\", fontsize=20)\nax2.set_ylabel(\"Count\", fontsize=20)\nax2.set_title(\"Prediction Distribution\", fontsize=22, pad=15)\nax2.tick_params(axis=\"both\", labelsize=16)\nax2.legend(fontsize=12, loc=\"upper right\")\nax2.grid(True, alpha=0.3, linestyle=\"--\")\n\nplt.tight_layout()\nplt.savefig(\"plot.png\", dpi=300, bbox_inches=\"tight\")\n"}