|
1 | | -""" pyplots.ai |
| 1 | +""" anyplot.ai |
2 | 2 | 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 |
5 | 5 | """ |
6 | 6 |
|
| 7 | +import os |
| 8 | + |
7 | 9 | import numpy as np |
8 | 10 | import plotly.graph_objects as go |
9 | 11 | from sklearn.datasets import make_moons |
10 | 12 | from sklearn.neighbors import KNeighborsClassifier |
11 | 13 | from sklearn.preprocessing import StandardScaler |
12 | 14 |
|
13 | 15 |
|
| 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 | + |
14 | 25 | # Data - Generate moon-shaped classification data |
15 | 26 | np.random.seed(42) |
16 | 27 | X, y = make_moons(n_samples=200, noise=0.25, random_state=42) |
|
28 | 39 | y_min, y_max = X[:, 1].min() - 0.5, X[:, 1].max() + 0.5 |
29 | 40 | xx, yy = np.meshgrid(np.linspace(x_min, x_max, 150), np.linspace(y_min, y_max, 150)) |
30 | 41 |
|
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 |
36 | 43 | Z_prob = clf.predict_proba(np.c_[xx.ravel(), yy.ravel()])[:, 1] |
37 | 44 | Z_prob = Z_prob.reshape(xx.shape) |
38 | 45 |
|
|
45 | 52 | x=np.linspace(x_min, x_max, 150), |
46 | 53 | y=np.linspace(y_min, y_max, 150), |
47 | 54 | 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, |
50 | 57 | showscale=True, |
51 | 58 | 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, |
53 | 64 | ), |
54 | 65 | contours=dict(showlines=False), |
55 | | - hoverinfo="skip", |
| 66 | + hovertemplate="Feature 1: %{x:.2f}<br>Feature 2: %{y:.2f}<br>Probability: %{z:.2f}<extra></extra>", |
56 | 67 | ) |
57 | 68 | ) |
58 | 69 |
|
|
64 | 75 | z=Z_prob, |
65 | 76 | showscale=False, |
66 | 77 | 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"), |
68 | 79 | hoverinfo="skip", |
69 | 80 | ) |
70 | 81 | ) |
|
79 | 90 | x=X_class0[:, 0], |
80 | 91 | y=X_class0[:, 1], |
81 | 92 | 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"), |
83 | 94 | 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>", |
85 | 96 | ) |
86 | 97 | ) |
87 | 98 |
|
|
91 | 102 | x=X_class1[:, 0], |
92 | 103 | y=X_class1[:, 1], |
93 | 104 | 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"), |
95 | 106 | 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>", |
97 | 108 | ) |
98 | 109 | ) |
99 | 110 |
|
100 | | -# Update layout |
| 111 | +# Update layout with theme-adaptive colors |
101 | 112 | 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 | + ), |
103 | 116 | 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), |
106 | 119 | showgrid=True, |
107 | 120 | gridwidth=1, |
108 | | - gridcolor="rgba(128, 128, 128, 0.3)", |
| 121 | + gridcolor=GRID, |
109 | 122 | zeroline=False, |
| 123 | + linecolor=INK_SOFT, |
| 124 | + linewidth=2, |
110 | 125 | ), |
111 | 126 | 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), |
114 | 129 | showgrid=True, |
115 | 130 | gridwidth=1, |
116 | | - gridcolor="rgba(128, 128, 128, 0.3)", |
| 131 | + gridcolor=GRID, |
117 | 132 | zeroline=False, |
| 133 | + linecolor=INK_SOFT, |
| 134 | + linewidth=2, |
118 | 135 | scaleanchor="x", |
119 | 136 | scaleratio=1, |
120 | 137 | ), |
121 | | - template="plotly_white", |
| 138 | + paper_bgcolor=PAGE_BG, |
| 139 | + plot_bgcolor=PAGE_BG, |
| 140 | + font=dict(color=INK), |
122 | 141 | 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, |
130 | 149 | borderwidth=1, |
131 | 150 | ), |
132 | 151 | margin=dict(l=80, r=100, t=100, b=80), |
| 152 | + hovermode="closest", |
133 | 153 | ) |
134 | 154 |
|
135 | 155 | # 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