{"spec_id":"roc-curve","library":"pygal","language":"python","code":"\"\"\" anyplot.ai\nroc-curve: ROC Curve with AUC\nLibrary: pygal 3.1.0 | Python 3.13.13\nQuality: 90/100 | Updated: 2026-05-09\n\"\"\"\n\nimport os\n\nimport numpy as np\nimport pygal\nfrom pygal.style import Style\n\n\n# Theme tokens\nTHEME = os.getenv(\"ANYPLOT_THEME\", \"light\")\nPAGE_BG = \"#FAF8F1\" if THEME == \"light\" else \"#1A1A17\"\nINK = \"#1A1A17\" if THEME == \"light\" else \"#F0EFE8\"\nINK_MUTED = \"#6B6A63\" if THEME == \"light\" else \"#A8A79F\"\n\nIMPRINT = (\"#009E73\", \"#C475FD\", \"#4467A3\", \"#BD8233\", \"#AE3030\", \"#2ABCCD\", \"#954477\")\n\n# Data - Simulate ROC curves for three classifiers with different AUC scores\nnp.random.seed(42)\n\n# Generate predictions for an excellent model (AUC ~0.95)\ny_true = np.array([0] * 100 + [1] * 100)\ny_scores_excellent = np.concatenate(\n    [\n        np.random.beta(1.5, 6, 100),  # Negatives - lower scores\n        np.random.beta(6, 1.5, 100),  # Positives - higher scores\n    ]\n)\n\n# Generate predictions for a moderate model (AUC ~0.70)\ny_scores_moderate = np.concatenate(\n    [\n        np.random.beta(2.5, 2.5, 100),  # Negatives\n        np.random.beta(2.8, 2.2, 100),  # Positives\n    ]\n)\n\n# Generate predictions for a poor model (AUC ~0.60)\ny_scores_poor = np.concatenate(\n    [\n        np.random.beta(2.5, 2.0, 100),  # Negatives\n        np.random.beta(2.2, 2.5, 100),  # Positives\n    ]\n)\n\n# Compute ROC points for excellent model\nthresholds = np.linspace(1, 0, 100)\ntpr_excellent = []\nfpr_excellent = []\nfor thresh in thresholds:\n    y_pred = (y_scores_excellent >= 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    tpr_excellent.append(tp / (tp + fn) if (tp + fn) > 0 else 0)\n    fpr_excellent.append(fp / (fp + tn) if (fp + tn) > 0 else 0)\nfpr_excellent = np.array(fpr_excellent)\ntpr_excellent = np.array(tpr_excellent)\n\n# Compute ROC points for moderate model\ntpr_moderate = []\nfpr_moderate = []\nfor thresh in thresholds:\n    y_pred = (y_scores_moderate >= 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    tpr_moderate.append(tp / (tp + fn) if (tp + fn) > 0 else 0)\n    fpr_moderate.append(fp / (fp + tn) if (fp + tn) > 0 else 0)\nfpr_moderate = np.array(fpr_moderate)\ntpr_moderate = np.array(tpr_moderate)\n\n# Compute ROC points for poor model\ntpr_poor = []\nfpr_poor = []\nfor thresh in thresholds:\n    y_pred = (y_scores_poor >= 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    tpr_poor.append(tp / (tp + fn) if (tp + fn) > 0 else 0)\n    fpr_poor.append(fp / (fp + tn) if (fp + tn) > 0 else 0)\nfpr_poor = np.array(fpr_poor)\ntpr_poor = np.array(tpr_poor)\n\n# Compute AUC using trapezoidal rule\nsorted_idx_excellent = np.argsort(fpr_excellent)\nauc_excellent = np.trapezoid(tpr_excellent[sorted_idx_excellent], fpr_excellent[sorted_idx_excellent])\n\nsorted_idx_moderate = np.argsort(fpr_moderate)\nauc_moderate = np.trapezoid(tpr_moderate[sorted_idx_moderate], fpr_moderate[sorted_idx_moderate])\n\nsorted_idx_poor = np.argsort(fpr_poor)\nauc_poor = np.trapezoid(tpr_poor[sorted_idx_poor], fpr_poor[sorted_idx_poor])\n\n# Create custom style for anyplot.ai (scaled for 4800x2700 canvas)\ncustom_style = Style(\n    background=PAGE_BG,\n    plot_background=PAGE_BG,\n    foreground=INK,\n    foreground_strong=INK,\n    foreground_subtle=INK_MUTED,\n    colors=IMPRINT,\n    title_font_size=28,\n    label_font_size=22,\n    major_label_font_size=18,\n    legend_font_size=16,\n    value_font_size=14,\n    stroke_width=3,\n)\n\n# Create XY chart for ROC curve\nchart = pygal.XY(\n    width=4800,\n    height=2700,\n    style=custom_style,\n    title=\"roc-curve · pygal · anyplot.ai\",\n    x_title=\"False Positive Rate\",\n    y_title=\"True Positive Rate\",\n    show_dots=False,\n    stroke_style={\"width\": 5},\n    range=(0, 1),\n    xrange=(0, 1),\n    show_x_guides=True,\n    show_y_guides=True,\n    legend_at_bottom=False,\n    legend_box_size=32,\n    truncate_legend=-1,\n    dots_size=0,\n    fill=False,\n    interpolate=None,\n)\n\n# Prepare data points for pygal XY chart\npoints_excellent = list(zip(fpr_excellent.tolist(), tpr_excellent.tolist(), strict=True))\nchart.add(f\"Excellent (AUC = {auc_excellent:.2f})\", points_excellent)\n\npoints_moderate = list(zip(fpr_moderate.tolist(), tpr_moderate.tolist(), strict=True))\nchart.add(f\"Moderate (AUC = {auc_moderate:.2f})\", points_moderate)\n\npoints_poor = list(zip(fpr_poor.tolist(), tpr_poor.tolist(), strict=True))\nchart.add(f\"Poor (AUC = {auc_poor:.2f})\", points_poor)\n\n# Random classifier reference line (diagonal)\ndiagonal = [(0, 0), (1, 1)]\nchart.add(\"Random (AUC = 0.50)\", diagonal, stroke_dasharray=\"10,5\")\n\n# Save outputs\nchart.render_to_file(f\"plot-{THEME}.html\")\nchart.render_to_png(f\"plot-{THEME}.png\")\n"}