An interactive, browser-based playground for classical machine learning. Click on a 2D plane to place your own data points (or generate a dataset), pick an algorithm, and watch it train — one real step at a time, with the decision boundary, the fitted curve and the error metrics updating as it goes.
Every frame of every animation is a genuine intermediate state of the algorithm: an epoch of gradient descent, one Lloyd iteration of k-means, one more level of tree depth, one more tree in the forest. Nothing is faked for the sake of the visuals.
Everything runs on a laptop CPU. The heaviest configuration — a two-layer neural network of 100 neurons each over 1000 points — trains and renders every frame in about a second.
./run.sh # then open http://127.0.0.1:8000
| Algorithm | Task | What the animation steps through |
|---|---|---|
| Linear regression | Regression | Epochs of gradient descent, walking towards the closed-form least-squares line (drawn dashed for comparison) |
| Polynomial regression | Regression | Degree 1 → d, with training and validation error side by side so the overfitting U-curve appears |
| Logistic regression | Classification | Epochs of SGD on the log loss, with the confidence band around the boundary narrowing |
| k-nearest neighbours | Classification | k = 1 upwards: the Voronoi partition smoothing out as neighbours are added |
| Gaussian naive Bayes | Classification | Data fed in chunks via partial_fit, with each class's fitted 2σ ellipse drawn |
| Support vector machine | Classification | The solver's own iterations, with support vectors circled and the ±1 margins drawn for a linear kernel |
| Decision tree | Classification | One more level of depth per frame, plus a rendered tree diagram and the split lines on the plot |
| Random forest | Classification | One more tree per frame, with an optional overlay of the newest single tree to compare against the ensemble |
| Neural network (MLP) | Classification | Epochs of backpropagation, with a weight-shaded network diagram |
| k-means | Clustering | Assign and update shown as separate frames, with centroid movement trails |
| Gaussian mixture | Clustering | EM iterations, with covariance ellipses that tilt and points faded by how strongly they belong |
| DBSCAN | Clustering | The flood fill itself, with the eps radius drawn on the expanding point and core / border / noise points drawn differently |
| Hierarchical | Clustering | The cut sliding down a dendrogram, merging two clusters per frame, with selectable linkage |
Synthetic datasets: Gaussian blobs, stretched blobs, two moons, concentric circles, spirals, XOR quadrants, uniform noise, and four regression shapes (noisy line, sine wave, cubic, step). All have adjustable sample count and noise. Shuffle draws a new dataset and Resample split redraws the holdout without touching the data; no seed is ever shown.
The Noise dial means something slightly different per dataset — cluster spread for the blob sets, positional jitter for the shaped ones, residual spread for regression — so each dataset explains its own in the control's help text. Noise 0 is genuinely zero everywhere except the three generators built from Gaussian clusters (blobs, stretched blobs, XOR), where zero width would collapse each cluster to a single point; those keep a documented floor.
- Click the plot to add a point. In classification mode the coloured chips above the plot pick which class you are placing; press + class for a third, fourth, … class.
- Drag a point to move it and watch the model follow in real time.
- Shift-click or right-click a point to delete it.
- Space plays/pauses; ← and → step through frames.
- Auto-run re-fits on every change. Turn it off and changes are staged until you press Generate for data or Train for the model.
- Validation split holds back 0–50% of the points, scored separately, so training and validation metrics can be compared. Held-out points are ringed on the plot.
- Pressing Train or Generate rewinds and plays the animation; tweaking a slider re-fits in place so you can compare two settings at the same frame.
The only requirements are Python 3.10 or newer and a shell — Bash on macOS and Linux, PowerShell
on Windows. No editor, IDE or Node toolchain is needed: the frontend is plain ES modules served
straight from disk, with no build step. Working in a virtual environment is recommended, and both
run scripts pick .venv up automatically if it exists.
macOS / Linux
python3 -m venv .venv && source .venv/bin/activate
python3 -m pip install -r requirements.txt
./run.sh./run.sh --dev # auto-reload while editing
PORT=9000 ./run.sh # pick a portWindows (PowerShell)
py -m venv .venv
.\.venv\Scripts\Activate.ps1
python -m pip install -r requirements.txt
.\run.ps1.\run.ps1 -Dev # auto-reload while editing
.\run.ps1 -Port 9000 # pick a portThen open http://127.0.0.1:8000.
Or drive uvicorn yourself, on any platform:
python -m uvicorn backend.app.main:app --port 8000python -m pytest194 tests cover every algorithm endpoint, every dataset generator, the grid encoding, parameter coercion and clamping, and the error paths (unlabelled data, a single class, too few points, degenerate input).
backend/
app/
main.py FastAPI app: JSON API + serves the frontend
registry.py algorithm id -> spec + fit function
schemas.py request validation
datasets.py synthetic data generators
grid.py decision-surface sampling and byte encoding
algorithms/
base.py Step / FitResult / AlgorithmSpec, data preparation, shared helpers
*.py one module per algorithm
tests/
frontend/
index.html
css/style.css
js/
main.js app wiring: catalogue -> controls -> fit -> playback -> insights
plot.js the interactive canvas: surfaces, points, curves, drag-to-edit
chart.js per-step metric chart
diagrams.js SVG tree and neural-network diagrams
controls.js builds controls from the parameter specs the API returns
api.js, palette.js
The models are scikit-learn. Nothing is reimplemented by hand — the animations come from asking scikit-learn for genuine intermediate states:
partial_fitfor SGD regressors/classifiers and naive Bayes (one epoch or one chunk per frame)warm_startfor the random forest (one more tree per frame), the MLP (one epoch per frame) and the Gaussian mixture (one EM iteration per frame)SVC(max_iter=n)to cap the libsvm solver part-way through- refitting at each depth / k / degree for trees, k-NN and polynomials
- an explicit Lloyd loop over
kmeans_plusplus+pairwise_distances_argminfor k-means, so the assign and update halves can be shown as separate frames - an explicit flood fill over
NearestNeighborsradius queries for DBSCAN, for the same reason - one
scipylinkage tree for hierarchical clustering, re-cut withfclusterat each frame
DBSCAN and hierarchical clustering are transductive: they label the points they were given and
have no predict() for anywhere else. Their shaded regions are therefore an extrapolation — nearest
core point within eps, and nearest labelled point respectively — and each run says so in its notes.
Three endpoints, all JSON:
GET /api/algorithms— the catalogue. Each algorithm ships its own parameter specs, prose description and "things to try" list; the frontend builds its entire control panel from this, so adding a hyperparameter needs no frontend change.POST /api/generate—{generator, n_samples, noise, seed, classes}→ points.POST /api/fit—{algorithm, params, points, viewport, grid_resolution, validation_split, validation_seed}→ onestepper animation frame, each with metrics, a decision surface and any algorithm-specific extras.
Decision surfaces are the bulky part of the payload, so each frame's grid is sent as a base64
uint8 array — one byte of class index per cell, plus an optional confidence byte that the
frontend turns into per-pixel alpha. Responses are gzipped; a 48-frame animation is a few
hundred kilobytes.
- Drop a module in
backend/app/algorithms/exposingSPEC(anAlgorithmSpec) andfit(points, params, grid) -> FitResult. - Add it to
MODULESinbackend/app/algorithms/__init__.py.
That is all — the sidebar entry, the hyperparameter sliders, the explanation card, the metric chart and the playback bar are all driven by the spec and the returned steps.