Skip to content

Commit 7ea467c

Browse files
feat(bokeh): implement roc-curve (#2313)
## Implementation: `roc-curve` - bokeh Implements the **bokeh** version of `roc-curve`. **File:** `plots/roc-curve/implementations/bokeh.py` --- :robot: *[impl-generate workflow](https://github.com/MarkusNeusinger/pyplots/actions/runs/20526594112)* --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
1 parent 3abe7f2 commit 7ea467c

2 files changed

Lines changed: 146 additions & 0 deletions

File tree

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
""" pyplots.ai
2+
roc-curve: ROC Curve with AUC
3+
Library: bokeh 3.8.1 | Python 3.13.11
4+
Quality: 91/100 | Created: 2025-12-26
5+
"""
6+
7+
import numpy as np
8+
from bokeh.io import export_png, save
9+
from bokeh.models import ColumnDataSource, Legend
10+
from bokeh.plotting import figure
11+
from bokeh.resources import CDN
12+
13+
14+
# Data - Simulated ROC curves for three classifiers with different performance levels
15+
np.random.seed(42)
16+
17+
# Generate ROC curve points using sklearn-like simulation
18+
# Using the parametric approach: FPR = t, TPR = t^(1/k) where k controls curve shape
19+
n_points = 200
20+
t = np.linspace(0, 1, n_points)
21+
22+
# Model 1: Strong classifier (AUC ~0.95) - curve bows far towards top-left
23+
k1 = 0.15
24+
fpr_1 = t
25+
tpr_1 = np.power(t, k1)
26+
auc_1 = np.trapezoid(tpr_1, fpr_1)
27+
28+
# Model 2: Medium classifier (AUC ~0.82) - moderate curve
29+
k2 = 0.35
30+
fpr_2 = t
31+
tpr_2 = np.power(t, k2)
32+
auc_2 = np.trapezoid(tpr_2, fpr_2)
33+
34+
# Model 3: Weak classifier (AUC ~0.68) - closer to diagonal
35+
k3 = 0.6
36+
fpr_3 = t
37+
tpr_3 = np.power(t, k3)
38+
auc_3 = np.trapezoid(tpr_3, fpr_3)
39+
40+
# Random classifier reference line
41+
fpr_random = np.array([0, 1])
42+
tpr_random = np.array([0, 1])
43+
44+
# Create ColumnDataSources
45+
source_1 = ColumnDataSource(data={"fpr": fpr_1, "tpr": tpr_1})
46+
source_2 = ColumnDataSource(data={"fpr": fpr_2, "tpr": tpr_2})
47+
source_3 = ColumnDataSource(data={"fpr": fpr_3, "tpr": tpr_3})
48+
source_random = ColumnDataSource(data={"fpr": fpr_random, "tpr": tpr_random})
49+
50+
# Create figure - Square format preferred for equal aspect ratio
51+
p = figure(
52+
width=3600,
53+
height=3600,
54+
title="roc-curve · bokeh · pyplots.ai",
55+
x_axis_label="False Positive Rate",
56+
y_axis_label="True Positive Rate",
57+
x_range=(-0.02, 1.02),
58+
y_range=(-0.02, 1.02),
59+
tools="",
60+
toolbar_location=None,
61+
)
62+
63+
# Plot random classifier reference line (diagonal)
64+
random_line = p.line(
65+
x="fpr", y="tpr", source=source_random, line_width=3, line_dash="dashed", line_color="#888888", alpha=0.8
66+
)
67+
68+
# Plot ROC curves with distinct colors
69+
# Using Python Blue (#306998) for best model, then complementary colors
70+
line_1 = p.line(x="fpr", y="tpr", source=source_1, line_width=5, line_color="#306998", alpha=0.9)
71+
line_2 = p.line(x="fpr", y="tpr", source=source_2, line_width=5, line_color="#FFD43B", alpha=0.9)
72+
line_3 = p.line(x="fpr", y="tpr", source=source_3, line_width=5, line_color="#E74C3C", alpha=0.9)
73+
74+
# Create legend with AUC scores
75+
legend = Legend(
76+
items=[
77+
(f"Random Forest (AUC = {auc_1:.2f})", [line_1]),
78+
(f"Logistic Regression (AUC = {auc_2:.2f})", [line_2]),
79+
(f"Decision Tree (AUC = {auc_3:.2f})", [line_3]),
80+
("Random Classifier", [random_line]),
81+
],
82+
location="bottom_right",
83+
)
84+
85+
p.add_layout(legend)
86+
legend.label_text_font_size = "20pt"
87+
legend.glyph_height = 30
88+
legend.glyph_width = 30
89+
legend.spacing = 15
90+
legend.padding = 20
91+
legend.background_fill_alpha = 0.8
92+
legend.border_line_alpha = 0
93+
94+
# Style the plot
95+
p.title.text_font_size = "32pt"
96+
p.title.align = "center"
97+
p.xaxis.axis_label_text_font_size = "24pt"
98+
p.yaxis.axis_label_text_font_size = "24pt"
99+
p.xaxis.major_label_text_font_size = "18pt"
100+
p.yaxis.major_label_text_font_size = "18pt"
101+
102+
# Grid styling - subtle
103+
p.grid.grid_line_alpha = 0.3
104+
p.grid.grid_line_dash = [6, 4]
105+
106+
# Background and border
107+
p.background_fill_color = "#FAFAFA"
108+
p.border_fill_color = "white"
109+
p.outline_line_color = "#CCCCCC"
110+
111+
# Axis styling
112+
p.xaxis.axis_line_width = 2
113+
p.yaxis.axis_line_width = 2
114+
p.xaxis.major_tick_line_width = 2
115+
p.yaxis.major_tick_line_width = 2
116+
117+
# Save as PNG and HTML
118+
export_png(p, filename="plot.png")
119+
save(p, filename="plot.html", resources=CDN, title="ROC Curve with AUC")
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
library: bokeh
2+
specification_id: roc-curve
3+
created: '2025-12-26T17:39:45Z'
4+
updated: '2025-12-26T17:50:15Z'
5+
generated_by: claude-opus-4-5-20251101
6+
workflow_run: 20526594112
7+
issue: 0
8+
python_version: 3.13.11
9+
library_version: 3.8.1
10+
preview_url: https://storage.googleapis.com/pyplots-images/plots/roc-curve/bokeh/plot.png
11+
preview_thumb: https://storage.googleapis.com/pyplots-images/plots/roc-curve/bokeh/plot_thumb.png
12+
preview_html: https://storage.googleapis.com/pyplots-images/plots/roc-curve/bokeh/plot.html
13+
quality_score: 91
14+
review:
15+
strengths:
16+
- Excellent visual clarity with appropriate line widths and font sizes for the 3600x3600
17+
canvas
18+
- Correct implementation of ROC curve mathematics using parametric approach
19+
- Clean, well-organized code following KISS principles
20+
- Proper use of ColumnDataSource for data management
21+
- Good color choices that distinguish the three classifiers
22+
- Produces both PNG and HTML output showcasing Bokeh's dual output capability
23+
weaknesses:
24+
- Legend positioned in extreme bottom-right corner; could be better placed inside
25+
the plot area or with more padding
26+
- Does not utilize Bokeh's interactive features like HoverTool to show threshold
27+
values on hover

0 commit comments

Comments
 (0)