Skip to content

Commit 0430626

Browse files
feat(plotly): implement contour-decision-boundary (#6886)
## Implementation: `contour-decision-boundary` - python/plotly Implements the **python/plotly** version of `contour-decision-boundary`. **File:** `plots/contour-decision-boundary/implementations/python/plotly.py` **Parent Issue:** #2921 --- :robot: *[impl-generate workflow](https://github.com/MarkusNeusinger/anyplot/actions/runs/25955652261)* --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: Markus Neusinger <2921697+MarkusNeusinger@users.noreply.github.com>
1 parent 0d9d391 commit 0430626

2 files changed

Lines changed: 216 additions & 165 deletions

File tree

Lines changed: 55 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,27 @@
1-
""" pyplots.ai
1+
""" anyplot.ai
22
contour-decision-boundary: Decision Boundary Classifier Visualization
3-
Library: plotly 6.5.0 | Python 3.13.11
4-
Quality: 92/100 | Created: 2025-12-31
3+
Library: plotly 6.7.0 | Python 3.13.13
4+
Quality: 95/100 | Updated: 2026-05-16
55
"""
66

7+
import os
8+
79
import numpy as np
810
import plotly.graph_objects as go
911
from sklearn.datasets import make_moons
1012
from sklearn.neighbors import KNeighborsClassifier
1113
from sklearn.preprocessing import StandardScaler
1214

1315

16+
THEME = os.getenv("ANYPLOT_THEME", "light")
17+
PAGE_BG = "#FAF8F1" if THEME == "light" else "#1A1A17"
18+
ELEVATED_BG = "#FFFDF6" if THEME == "light" else "#242420"
19+
INK = "#1A1A17" if THEME == "light" else "#F0EFE8"
20+
INK_SOFT = "#4A4A44" if THEME == "light" else "#B8B7B0"
21+
GRID = "rgba(26,26,23,0.10)" if THEME == "light" else "rgba(240,239,232,0.10)"
22+
23+
OKABE_ITO = ["#009E73", "#D55E00", "#0072B2", "#CC79A7"]
24+
1425
# Data - Generate moon-shaped classification data
1526
np.random.seed(42)
1627
X, y = make_moons(n_samples=200, noise=0.25, random_state=42)
@@ -28,11 +39,7 @@
2839
y_min, y_max = X[:, 1].min() - 0.5, X[:, 1].max() + 0.5
2940
xx, yy = np.meshgrid(np.linspace(x_min, x_max, 150), np.linspace(y_min, y_max, 150))
3041

31-
# Get predictions for mesh grid
32-
Z = clf.predict(np.c_[xx.ravel(), yy.ravel()])
33-
Z = Z.reshape(xx.shape)
34-
35-
# Get prediction probabilities for smoother contours
42+
# Get prediction probabilities for smooth contours
3643
Z_prob = clf.predict_proba(np.c_[xx.ravel(), yy.ravel()])[:, 1]
3744
Z_prob = Z_prob.reshape(xx.shape)
3845

@@ -45,14 +52,18 @@
4552
x=np.linspace(x_min, x_max, 150),
4653
y=np.linspace(y_min, y_max, 150),
4754
z=Z_prob,
48-
colorscale=[[0, "#306998"], [1, "#FFD43B"]],
49-
opacity=0.6,
55+
colorscale=[[0, OKABE_ITO[0]], [1, OKABE_ITO[1]]],
56+
opacity=0.4,
5057
showscale=True,
5158
colorbar=dict(
52-
title=dict(text="Class Probability", font=dict(size=18)), tickfont=dict(size=16), len=0.7, thickness=25
59+
title=dict(text="Class Probability", font=dict(size=18)),
60+
tickfont=dict(size=16),
61+
len=0.7,
62+
thickness=25,
63+
bordercolor=INK_SOFT,
5364
),
5465
contours=dict(showlines=False),
55-
hoverinfo="skip",
66+
hovertemplate="Feature 1: %{x:.2f}<br>Feature 2: %{y:.2f}<br>Probability: %{z:.2f}<extra></extra>",
5667
)
5768
)
5869

@@ -64,7 +75,7 @@
6475
z=Z_prob,
6576
showscale=False,
6677
contours=dict(start=0.5, end=0.5, size=0.1, coloring="lines", showlabels=False),
67-
line=dict(color="white", width=3, dash="dash"),
78+
line=dict(color=INK_SOFT, width=3, dash="dash"),
6879
hoverinfo="skip",
6980
)
7081
)
@@ -79,9 +90,9 @@
7990
x=X_class0[:, 0],
8091
y=X_class0[:, 1],
8192
mode="markers",
82-
marker=dict(size=14, color="#306998", line=dict(color="white", width=2), symbol="circle"),
93+
marker=dict(size=14, color=OKABE_ITO[0], line=dict(color=PAGE_BG, width=2), symbol="circle"),
8394
name="Class 0",
84-
hovertemplate="Feature 1: %{x:.2f}<br>Feature 2: %{y:.2f}<extra>Class 0</extra>",
95+
hovertemplate="Feature 1: %{x:.2f}<br>Feature 2: %{y:.2f}<br>Class: 0<extra></extra>",
8596
)
8697
)
8798

@@ -91,47 +102,56 @@
91102
x=X_class1[:, 0],
92103
y=X_class1[:, 1],
93104
mode="markers",
94-
marker=dict(size=14, color="#FFD43B", line=dict(color="black", width=2), symbol="diamond"),
105+
marker=dict(size=14, color=OKABE_ITO[1], line=dict(color=PAGE_BG, width=2), symbol="diamond"),
95106
name="Class 1",
96-
hovertemplate="Feature 1: %{x:.2f}<br>Feature 2: %{y:.2f}<extra>Class 1</extra>",
107+
hovertemplate="Feature 1: %{x:.2f}<br>Feature 2: %{y:.2f}<br>Class: 1<extra></extra>",
97108
)
98109
)
99110

100-
# Update layout
111+
# Update layout with theme-adaptive colors
101112
fig.update_layout(
102-
title=dict(text="contour-decision-boundary · plotly · pyplots.ai", font=dict(size=28), x=0.5, xanchor="center"),
113+
title=dict(
114+
text="contour-decision-boundary · plotly · anyplot.ai", font=dict(size=28, color=INK), x=0.5, xanchor="center"
115+
),
103116
xaxis=dict(
104-
title=dict(text="Feature 1 (Standardized)", font=dict(size=22)),
105-
tickfont=dict(size=18),
117+
title=dict(text="Feature 1 (Standardized)", font=dict(size=22, color=INK)),
118+
tickfont=dict(size=18, color=INK_SOFT),
106119
showgrid=True,
107120
gridwidth=1,
108-
gridcolor="rgba(128, 128, 128, 0.3)",
121+
gridcolor=GRID,
109122
zeroline=False,
123+
linecolor=INK_SOFT,
124+
linewidth=2,
110125
),
111126
yaxis=dict(
112-
title=dict(text="Feature 2 (Standardized)", font=dict(size=22)),
113-
tickfont=dict(size=18),
127+
title=dict(text="Feature 2 (Standardized)", font=dict(size=22, color=INK)),
128+
tickfont=dict(size=18, color=INK_SOFT),
114129
showgrid=True,
115130
gridwidth=1,
116-
gridcolor="rgba(128, 128, 128, 0.3)",
131+
gridcolor=GRID,
117132
zeroline=False,
133+
linecolor=INK_SOFT,
134+
linewidth=2,
118135
scaleanchor="x",
119136
scaleratio=1,
120137
),
121-
template="plotly_white",
138+
paper_bgcolor=PAGE_BG,
139+
plot_bgcolor=PAGE_BG,
140+
font=dict(color=INK),
122141
legend=dict(
123-
font=dict(size=18),
124-
x=0.02,
125-
y=0.98,
126-
xanchor="left",
127-
yanchor="top",
128-
bgcolor="rgba(255, 255, 255, 0.8)",
129-
bordercolor="rgba(0, 0, 0, 0.3)",
142+
font=dict(size=18, color=INK_SOFT),
143+
x=0.98,
144+
y=0.02,
145+
xanchor="right",
146+
yanchor="bottom",
147+
bgcolor=ELEVATED_BG,
148+
bordercolor=INK_SOFT,
130149
borderwidth=1,
131150
),
132151
margin=dict(l=80, r=100, t=100, b=80),
152+
hovermode="closest",
133153
)
134154

135155
# Save as PNG and HTML
136-
fig.write_image("plot.png", width=1600, height=900, scale=3)
137-
fig.write_html("plot.html", include_plotlyjs="cdn")
156+
fig.write_image(f"plot-{THEME}.png", width=1600, height=900, scale=3)
157+
fig.write_html(f"plot-{THEME}.html", include_plotlyjs="cdn")

0 commit comments

Comments
 (0)