{"spec_id":"precision-recall","library":"seaborn","language":"python","code":"\"\"\" anyplot.ai\nprecision-recall: Precision-Recall Curve\nLibrary: seaborn 0.13.2 | Python 3.13.13\nQuality: 92/100 | Updated: 2026-05-10\n\"\"\"\n\nimport os\nimport sys\n\nimport matplotlib.pyplot as plt\nimport numpy as np\n\n\n# Remove local directory from path to avoid shadowing library imports\nsys.path = [p for p in sys.path if not p.endswith(\"/python\")]\n\nimport seaborn as sns\nfrom sklearn.metrics import average_precision_score, precision_recall_curve\n\n\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\nIMPRINT = [\"#009E73\", \"#C475FD\", \"#4467A3\", \"#BD8233\", \"#AE3030\", \"#2ABCCD\"]\n\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.10,\n        \"legend.facecolor\": ELEVATED_BG,\n        \"legend.edgecolor\": INK_SOFT,\n    },\n)\n\n# Data - Simulate binary classification with imbalanced classes (fraud detection scenario)\nnp.random.seed(42)\nn_samples = 1000\nn_positive = 100  # 10% positive class (imbalanced)\n\n# Ground truth labels\ny_true = np.zeros(n_samples)\ny_true[:n_positive] = 1\nnp.random.shuffle(y_true)\n\n# Simulate classifier scores - better separation for positives\ny_scores_good = np.where(\n    y_true == 1,\n    np.random.beta(5, 2, n_samples),  # Positives: higher scores\n    np.random.beta(2, 5, n_samples),  # Negatives: lower scores\n)\n\ny_scores_moderate = np.where(\n    y_true == 1,\n    np.random.beta(3, 2, n_samples),  # Positives: moderately higher\n    np.random.beta(2, 3, n_samples),  # Negatives: moderately lower\n)\n\ny_scores_poor = np.where(\n    y_true == 1,\n    np.random.beta(2, 2, n_samples),  # Positives: similar to negatives\n    np.random.beta(2, 2, n_samples),  # Negatives: similar to positives\n)\n\n# Calculate precision-recall curves\nprecision_good, recall_good, _ = precision_recall_curve(y_true, y_scores_good)\nprecision_moderate, recall_moderate, _ = precision_recall_curve(y_true, y_scores_moderate)\nprecision_poor, recall_poor, _ = precision_recall_curve(y_true, y_scores_poor)\n\n# Average precision scores\nap_good = average_precision_score(y_true, y_scores_good)\nap_moderate = average_precision_score(y_true, y_scores_moderate)\nap_poor = average_precision_score(y_true, y_scores_poor)\n\n# Baseline (random classifier)\nbaseline = n_positive / n_samples\n\n# Create plot\nfig, ax = plt.subplots(figsize=(16, 9))\n\n# Plot PR curves using seaborn's lineplot style with step interpolation\n# Good classifier\nax.step(\n    recall_good, precision_good, where=\"post\", linewidth=3, color=IMPRINT[0], label=f\"Model A (AP = {ap_good:.2f})\"\n)\nax.fill_between(recall_good, precision_good, step=\"post\", alpha=0.2, color=IMPRINT[0])\n\n# Moderate classifier\nax.step(\n    recall_moderate,\n    precision_moderate,\n    where=\"post\",\n    linewidth=3,\n    color=IMPRINT[1],\n    label=f\"Model B (AP = {ap_moderate:.2f})\",\n)\nax.fill_between(recall_moderate, precision_moderate, step=\"post\", alpha=0.2, color=IMPRINT[1])\n\n# Poor classifier\nax.step(\n    recall_poor, precision_poor, where=\"post\", linewidth=3, color=IMPRINT[2], label=f\"Model C (AP = {ap_poor:.2f})\"\n)\nax.fill_between(recall_poor, precision_poor, step=\"post\", alpha=0.2, color=IMPRINT[2])\n\n# Baseline reference line\nax.axhline(y=baseline, linestyle=\"--\", linewidth=2, color=INK_SOFT, label=f\"Random Classifier (P = {baseline:.2f})\")\n\n# Styling with seaborn aesthetics\nax.set_xlabel(\"Recall (Sensitivity)\", fontsize=20)\nax.set_ylabel(\"Precision (Positive Predictive Value)\", fontsize=20)\nax.set_title(\"precision-recall · seaborn · anyplot.ai\", fontsize=24)\nax.tick_params(axis=\"both\", labelsize=16)\n\n# Set axis limits\nax.set_xlim([0.0, 1.0])\nax.set_ylim([0.0, 1.05])\n\n# Legend\nax.legend(loc=\"upper right\", fontsize=16, frameon=True, fancybox=True, framealpha=0.9)\n\n# Grid styling\nax.yaxis.grid(True, alpha=0.2, linewidth=0.8)\nax.spines[\"top\"].set_visible(False)\nax.spines[\"right\"].set_visible(False)\n\nplt.tight_layout()\nplt.savefig(f\"plot-{THEME}.png\", dpi=300, bbox_inches=\"tight\", facecolor=PAGE_BG)\n"}