{"spec_id":"roc-curve","library":"seaborn","language":"python","code":"\"\"\" anyplot.ai\nroc-curve: ROC Curve with AUC\nLibrary: seaborn 0.13.2 | Python 3.13.13\nQuality: 90/100 | Updated: 2026-05-09\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# Okabe-Ito palette - first series ALWAYS #009E73\nIMPRINT = [\"#009E73\", \"#C475FD\", \"#4467A3\"]\n\n# Set random seed for reproducibility\nnp.random.seed(42)\n\n# Generate synthetic classification data for three models with different performance levels\nn_samples = 1000\n\n# True labels (binary)\ny_true = np.concatenate([np.zeros(500), np.ones(500)])\n\n# Model 1: Good classifier (AUC ~0.92)\ny_scores_model1 = np.concatenate(\n    [\n        np.random.beta(2, 5, 500),  # Low scores for class 0\n        np.random.beta(5, 2, 500),  # High scores for class 1\n    ]\n)\n\n# Model 2: Moderate classifier (AUC ~0.78)\ny_scores_model2 = np.concatenate([np.random.beta(2, 3, 500), np.random.beta(3, 2, 500)])\n\n# Model 3: Weak classifier (AUC ~0.65)\ny_scores_model3 = np.concatenate([np.random.beta(2, 2.5, 500), np.random.beta(2.5, 2, 500)])\n\n# Compute ROC curves manually at various thresholds\nn_thresholds = 200\nthresholds = np.linspace(0, 1, n_thresholds)\n\n# Model 1 ROC\ntpr1, fpr1 = [], []\nfor thresh in thresholds:\n    y_pred = (y_scores_model1 >= thresh).astype(int)\n    tp = np.sum((y_pred == 1) & (y_true == 1))\n    fp = np.sum((y_pred == 1) & (y_true == 0))\n    fn = np.sum((y_pred == 0) & (y_true == 1))\n    tn = np.sum((y_pred == 0) & (y_true == 0))\n    tpr1.append(tp / (tp + fn) if (tp + fn) > 0 else 0)\n    fpr1.append(fp / (fp + tn) if (fp + tn) > 0 else 0)\nfpr1, tpr1 = np.array(fpr1), np.array(tpr1)\n\n# Model 2 ROC\ntpr2, fpr2 = [], []\nfor thresh in thresholds:\n    y_pred = (y_scores_model2 >= thresh).astype(int)\n    tp = np.sum((y_pred == 1) & (y_true == 1))\n    fp = np.sum((y_pred == 1) & (y_true == 0))\n    fn = np.sum((y_pred == 0) & (y_true == 1))\n    tn = np.sum((y_pred == 0) & (y_true == 0))\n    tpr2.append(tp / (tp + fn) if (tp + fn) > 0 else 0)\n    fpr2.append(fp / (fp + tn) if (fp + tn) > 0 else 0)\nfpr2, tpr2 = np.array(fpr2), np.array(tpr2)\n\n# Model 3 ROC\ntpr3, fpr3 = [], []\nfor thresh in thresholds:\n    y_pred = (y_scores_model3 >= thresh).astype(int)\n    tp = np.sum((y_pred == 1) & (y_true == 1))\n    fp = np.sum((y_pred == 1) & (y_true == 0))\n    fn = np.sum((y_pred == 0) & (y_true == 1))\n    tn = np.sum((y_pred == 0) & (y_true == 0))\n    tpr3.append(tp / (tp + fn) if (tp + fn) > 0 else 0)\n    fpr3.append(fp / (fp + tn) if (fp + tn) > 0 else 0)\nfpr3, tpr3 = np.array(fpr3), np.array(tpr3)\n\n# Calculate AUC scores using trapezoidal rule\nidx1 = np.argsort(fpr1)\nauc1 = np.trapezoid(tpr1[idx1], fpr1[idx1])\nidx2 = np.argsort(fpr2)\nauc2 = np.trapezoid(tpr2[idx2], fpr2[idx2])\nidx3 = np.argsort(fpr3)\nauc3 = np.trapezoid(tpr3[idx3], fpr3[idx3])\n\n# Configure seaborn with theme-adaptive colors and settings\nsns.set_theme(\n    style=\"whitegrid\",\n    palette=IMPRINT,\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.1,\n        \"grid.linewidth\": 0.8,\n        \"legend.facecolor\": ELEVATED_BG,\n        \"legend.edgecolor\": INK_SOFT,\n        \"legend.framealpha\": 0.95,\n    },\n)\n\n# Create figure with theme-aware background\nfig, ax = plt.subplots(figsize=(16, 9), facecolor=PAGE_BG)\n\n# Grid should be drawn before data to appear behind lines\nax.set_axisbelow(True)\n\n# Plot ROC curves using seaborn lineplot with theme-aware palette\nsns.lineplot(\n    x=fpr1, y=tpr1, ax=ax, linewidth=3.5, color=IMPRINT[0], label=f\"Support Vector Machine (AUC = {auc1:.3f})\"\n)\nsns.lineplot(x=fpr2, y=tpr2, ax=ax, linewidth=3.5, color=IMPRINT[1], label=f\"Random Forest (AUC = {auc2:.3f})\")\nsns.lineplot(x=fpr3, y=tpr3, ax=ax, linewidth=3.5, color=IMPRINT[2], label=f\"Logistic Regression (AUC = {auc3:.3f})\")\n\n# Diagonal reference line (random classifier) - use neutral theme-aware color\nax.plot([0, 1], [0, 1], linestyle=\"--\", linewidth=2.5, color=INK_SOFT, label=\"Random Classifier (AUC = 0.500)\")\n\n# Styling\nax.set_xlabel(\"False Positive Rate (FPR)\", fontsize=20, color=INK)\nax.set_ylabel(\"True Positive Rate (TPR)\", fontsize=20, color=INK)\nax.set_title(\"roc-curve · seaborn · anyplot.ai\", fontsize=24, fontweight=\"medium\", color=INK)\nax.tick_params(axis=\"both\", labelsize=16, colors=INK_SOFT)\n\n# Set axis limits and aspect\nax.set_xlim([-0.02, 1.02])\nax.set_ylim([-0.02, 1.02])\nax.set_aspect(\"equal\", adjustable=\"box\")\n\n# Spines\nax.spines[\"top\"].set_visible(False)\nax.spines[\"right\"].set_visible(False)\nfor spine in [\"left\", \"bottom\"]:\n    ax.spines[spine].set_color(INK_SOFT)\n\n# Legend\nax.legend(loc=\"lower right\", fontsize=16, framealpha=0.95, fancybox=False)\n\nplt.tight_layout()\nplt.savefig(f\"plot-{THEME}.png\", dpi=300, bbox_inches=\"tight\", facecolor=PAGE_BG)\n"}