🗺️ t-SNE Visualiser
Watch a real small-scale t-SNE run in your browser: high-D Gaussian affinities, Student-t low-D affinities, and gradient descent on KL divergence projecting clusters to 2D.
About this simulation
This is a genuine small-scale t-SNE implementation running live in your browser: for each point it binary-searches a per-point Gaussian bandwidth β so that the conditional distribution p_j|i matches your chosen Perplexity, symmetrises those into joint probabilities P, and compares them against a heavy-tailed Student-t distribution q_ij ∝ 1/(1+‖yᵢ−yⱼ‖²) in the 2D embedding. Momentum-based gradient descent minimises the KL divergence KL(P‖Q), with an early "exaggeration" phase (first 100 iterations) that inflates P to force tight, well-separated clusters to form before fine-tuning relative distances.
🔬 What it shows
How a high-dimensional dataset (5 to 8 dimensions here) can be compressed into a 2D scatter plot that preserves local neighbourhood structure — points that were close together in the original space end up close together in the embedding, even though the exact distances are not preserved.
🎮 How to use
Choose a Dataset (Blobs, Two moons, Concentric, Random), then tune Perplexity (effective neighbourhood size), Learning rate, and Points count; watch the 2D embedding and the live KL divergence curve evolve, use Pause/Resume to freeze the optimisation, and Reset/Re-init to restart from a fresh random embedding with the same data.
💡 Did you know?
t-SNE deliberately uses a heavy-tailed Student-t distribution (rather than a Gaussian) for the low-dimensional similarities specifically to solve the "crowding problem" — it gives moderately distant points more room to spread apart in 2D than a Gaussian would allow, which is why t-SNE plots tend to show cleanly separated, well-rounded clusters.
Frequently asked questions
What does the Perplexity parameter actually control?
Perplexity is roughly the effective number of nearest neighbours each point considers when its Gaussian bandwidth is tuned; low values emphasise very local structure while high values emphasise more global structure, and the algorithm binary-searches a per-point bandwidth to hit the target for every point.
Why does the embedding start compressed and gradually spread out?
During the "exaggeration" phase (roughly the first 100 iterations) the high-dimensional probabilities P are artificially multiplied up, which pulls similar points into unusually tight, well-separated clumps first, making it easier for distinct clusters to find separate regions before the algorithm relaxes to fine-tune actual relative distances.
What does the KL divergence curve tell you?
It measures how well the 2D embedding's similarity distribution Q matches the original high-dimensional similarity distribution P; a steadily decreasing KL divergence means the embedding is progressively better preserving the original neighbourhood structure, and it should flatten out as the optimisation converges.
Can you compare distances between clusters in a t-SNE plot?
No — t-SNE is designed to preserve local neighbourhoods, not global distances or densities, so the size of clusters and the gaps between them in the 2D plot don't reliably reflect how far apart or how dense those groups actually are in the original high-dimensional space.
Why does t-SNE use a Student-t distribution instead of a Gaussian in 2D?
The heavy tails of the Student-t distribution let moderately dissimilar points end up farther apart in the low-dimensional map than a Gaussian would permit, which counteracts the "crowding problem" where many points competing for limited low-dimensional space would otherwise get squeezed unnaturally close together.
t-SNE projects high-dimensional clusters to 2D via gradient descent on KL divergence. Tune perplexity and learning rate and watch clusters separate.
3D · Three.js / WebGL renderer · 60 FPS target · runs fully client-side, no install