|
1 | | -""" pyplots.ai |
| 1 | +""" anyplot.ai |
2 | 2 | contour-decision-boundary: Decision Boundary Classifier Visualization |
3 | | -Library: altair 6.0.0 | Python 3.13.11 |
4 | | -Quality: 91/100 | Created: 2025-12-31 |
| 3 | +Library: altair 6.1.0 | Python 3.13.13 |
| 4 | +Quality: 92/100 | Updated: 2026-05-16 |
5 | 5 | """ |
6 | 6 |
|
| 7 | +import os |
| 8 | + |
7 | 9 | import altair as alt |
8 | 10 | import numpy as np |
9 | 11 | import pandas as pd |
10 | 12 | from sklearn.datasets import make_moons |
11 | 13 | from sklearn.neighbors import KNeighborsClassifier |
12 | 14 |
|
13 | 15 |
|
| 16 | +# Theme tokens |
| 17 | +THEME = os.getenv("ANYPLOT_THEME", "light") |
| 18 | +PAGE_BG = "#FAF8F1" if THEME == "light" else "#1A1A17" |
| 19 | +ELEVATED_BG = "#FFFDF6" if THEME == "light" else "#242420" |
| 20 | +INK = "#1A1A17" if THEME == "light" else "#F0EFE8" |
| 21 | +INK_SOFT = "#4A4A44" if THEME == "light" else "#B8B7B0" |
| 22 | + |
| 23 | +# Okabe-Ito palette |
| 24 | +OKABE_ITO = ["#009E73", "#D55E00", "#0072B2", "#CC79A7", "#E69F00", "#56B4E9", "#F0E442"] |
| 25 | + |
14 | 26 | # Data - generate two-moon classification dataset |
15 | 27 | np.random.seed(42) |
16 | 28 | X, y = make_moons(n_samples=150, noise=0.25, random_state=42) |
|
51 | 63 | y=alt.Y("X2:Q", bin=alt.Bin(maxbins=150), title="Feature X2"), |
52 | 64 | color=alt.Color( |
53 | 65 | "Class:N", |
54 | | - scale=alt.Scale(domain=["Class A", "Class B"], range=["#306998", "#FFD43B"]), |
55 | | - legend=alt.Legend(title="Class", titleFontSize=18, labelFontSize=16, orient="right"), |
| 66 | + scale=alt.Scale(domain=["Class A", "Class B"], range=[OKABE_ITO[0], OKABE_ITO[1]]), |
| 67 | + legend=alt.Legend(title="Decision Region", titleFontSize=18, labelFontSize=16, orient="right"), |
56 | 68 | ), |
57 | 69 | ) |
58 | 70 | ) |
|
65 | 77 | x=alt.X("X1:Q"), |
66 | 78 | y=alt.Y("X2:Q"), |
67 | 79 | fill=alt.Color( |
68 | | - "Class:N", scale=alt.Scale(domain=["Class A", "Class B"], range=["#306998", "#FFD43B"]), legend=None |
| 80 | + "Class:N", scale=alt.Scale(domain=["Class A", "Class B"], range=[OKABE_ITO[0], OKABE_ITO[1]]), legend=None |
69 | 81 | ), |
70 | | - stroke=alt.value("#333333"), |
| 82 | + stroke=alt.value(INK_SOFT), |
71 | 83 | tooltip=["X1:Q", "X2:Q", "Class:N", "Classification:N"], |
72 | 84 | ) |
73 | 85 | ) |
74 | 86 |
|
75 | | -# Incorrectly classified points (triangles with red stroke) |
| 87 | +# Incorrectly classified points (triangles with orange stroke) |
76 | 88 | incorrect_points = ( |
77 | 89 | alt.Chart(train_df[train_df["Classification"] == "Incorrect"]) |
78 | 90 | .mark_point(shape="triangle", size=350, strokeWidth=3, filled=True) |
79 | 91 | .encode( |
80 | 92 | x=alt.X("X1:Q"), |
81 | 93 | y=alt.Y("X2:Q"), |
82 | 94 | fill=alt.Color( |
83 | | - "Class:N", scale=alt.Scale(domain=["Class A", "Class B"], range=["#306998", "#FFD43B"]), legend=None |
| 95 | + "Class:N", scale=alt.Scale(domain=["Class A", "Class B"], range=[OKABE_ITO[0], OKABE_ITO[1]]), legend=None |
84 | 96 | ), |
85 | | - stroke=alt.value("#E63946"), |
| 97 | + stroke=alt.value(OKABE_ITO[1]), |
86 | 98 | tooltip=["X1:Q", "X2:Q", "Class:N", "Classification:N"], |
87 | 99 | ) |
88 | 100 | ) |
|
109 | 121 | .properties( |
110 | 122 | width=1600, |
111 | 123 | height=900, |
112 | | - title=alt.Title("contour-decision-boundary \u00b7 altair \u00b7 pyplots.ai", fontSize=28, anchor="middle"), |
| 124 | + background=PAGE_BG, |
| 125 | + title=alt.Title("contour-decision-boundary · altair · anyplot.ai", fontSize=28, anchor="middle", color=INK), |
| 126 | + ) |
| 127 | + .configure_view(fill=PAGE_BG, stroke=INK_SOFT, strokeWidth=0) |
| 128 | + .configure_axis( |
| 129 | + domainColor=INK_SOFT, |
| 130 | + tickColor=INK_SOFT, |
| 131 | + gridColor=INK, |
| 132 | + gridOpacity=0.10, |
| 133 | + labelColor=INK_SOFT, |
| 134 | + titleColor=INK, |
| 135 | + labelFontSize=18, |
| 136 | + titleFontSize=22, |
| 137 | + ) |
| 138 | + .configure_legend( |
| 139 | + fillColor=ELEVATED_BG, |
| 140 | + strokeColor=INK_SOFT, |
| 141 | + labelColor=INK_SOFT, |
| 142 | + titleColor=INK, |
| 143 | + labelFontSize=16, |
| 144 | + titleFontSize=18, |
113 | 145 | ) |
114 | | - .configure_axis(labelFontSize=18, titleFontSize=22, gridOpacity=0.3) |
115 | | - .configure_view(strokeWidth=0) |
116 | 146 | ) |
117 | 147 |
|
118 | 148 | # Save outputs |
119 | | -chart.save("plot.png", scale_factor=3.0) |
120 | | -chart.save("plot.html") |
| 149 | +chart.save(f"plot-{THEME}.png", scale_factor=3.0) |
| 150 | +chart.save(f"plot-{THEME}.html") |
0 commit comments