Embedding explorer
Load embeddings (CSV, TSV, JSON, GloVe text, the TensorFlow Projector's vectors.tsv + metadata.tsv) or embed sentences in the browser with all-MiniLM-L6-v2, then project them with PCA, t-SNE or UMAP in 2-D or 3-D, colour and search them, list nearest neighbours by cosine or Euclidean distance, cluster with k-means or DBSCAN, score how faithful the map is, and try word analogies.
Added
How to use it
Four tabs: Explore (the map), Clusters, Analogies and Data. Everything runs in this page: projections and clustering in a background Web Worker, and nothing you load is uploaded. Every setting can be put in a link, with presets — see Linking to an example.
Loading data
Choose a built-in set (no download needed) or bring your own:
-
Word vectors (constructed) — 112 words in 32 dimensions: people, animals, countries and capitals, verbs and adjectives. They are made for teaching, not trained: each word is a sum of meaning directions (king = PERSON + ROYAL + MALE, plus its own random part and noise), which is exactly why king − man + woman lands on queen. Real word2vec and GloVe vectors behave like this only approximately.
-
Gaussian blobs — six clusters in 40 dimensions (centres uniform in ±10, like scikit-learn’s
make_blobs). -
Swiss roll and S-curve — 2-D sheets rolled up in 3-D (scikit-learn’s formulas), coloured by position along the sheet: PCA squashes the layers together, t-SNE and UMAP unroll them.
-
Digits — 500 8 × 8 images of 0–9 drawn from a pixel font with random scale, slant, shift, stroke weight and noise: like scikit-learn’s digits, generated here.
Your vectors: drop or open a file, or paste text.
-
CSV / TSV, with or without a header: numeric columns form the vector, text columns become metadata (a column called
label,word,text,name… labels the points). A column of bracketed arrays ("[0.12, -0.4, …]", as pandas writes them) is read as the vector. -
GloVe / word2vec text (
word 0.418 0.249 …, acount dimsfirst line is skipped). -
JSON:
[[…], …],[{"label": "…", "vector": […], "topic": "…"}, …](alsoembedding,values), or{"vectors": […], "labels": […], "metadata": {"col": […]}}. -
The TensorFlow Embedding Projector's pair — open
vectors.tsvandmetadata.tsvtogether. As in the Projector, a one-column metadata file has no header and a file with several columns does. Download vectors.tsv + metadata.tsv writes any loaded set back out in that format.
L2-normalise scales every vector to length 1, the usual step for text embeddings: Euclidean distance then ranks neighbours exactly as cosine similarity does.
Embed sentences in the browser: type one sentence per line (optionally group | sentence) and
press Embed. The page loads all-MiniLM-L6-v2
(384 dimensions, the 8-bit ONNX export, about 23 MB) with
transformers.js from the Hugging Face hub the first
time — the browser caches it — and embeds the lines with mean pooling and unit length, as
sentence-transformers does. Sample sentences gives sixteen lines on cooking, cycling, search and
the weather; they fall into four groups.
Exploring the map
Pick a projection and 2-D or 3-D. Changing a setting re-runs it; t-SNE and UMAP animate as they optimise, and Stop halts them.
-
PCA — the 2 or 3 directions of greatest variance. The panel shows the share of variance each component explains (as scikit-learn’s
explained_variance_ratio_). Linear and honest about distances, but it flattens whatever lies outside those components. -
t-SNE (van der Maaten & Hinton 2008), exact: each point’s Gaussian is tuned so its neighbour distribution has the chosen perplexity (about the number of neighbours it "listens to"), and the map is moved by gradient descent on the KL divergence with scikit-learn’s optimiser: early exaggeration (default 12) for the first quarter of the iterations, up to 250, momentum 0.5 then 0.8, adaptive gains, and learning rate "auto" = max(n / exaggeration / 4, 50). Start from PCA (stable) or random; the seed makes runs repeatable. Data with more than 50 dimensions are first reduced to 50 by PCA. At most 3,000 points.
-
UMAP (McInnes, Healy & Melville 2018) with umap-js (loaded from jsDelivr on first use): neighbours trades local detail for global shape, min distance sets how tightly points may pack, epochs how long it optimises, and the distance is cosine or Euclidean. umap-js starts from random positions; here the default start is spectral, as in the Python implementation — a Laplacian eigenmap of UMAP’s neighbour graph, computed by subspace iteration — which unrolls the Swiss roll that a random start often leaves folded.
Colour by any metadata column (categories get a palette, numbers a colour ramp) or by the clusters from the Clusters tab. Search highlights labels containing the text (or metadata equal to it); Enter selects the first match. Labels shows names on the map (auto: for small sets).
Tap or click a point to list its k nearest neighbours in the original space by cosine similarity or Euclidean distance, with both numbers, and whether each is also among its k nearest on the map. Click a row to hop to that point.
In 3-D, drag to rotate (two fingers pinch to zoom on a phone, arrow keys on a keyboard) or press ⟳ to spin. ⌘/Ctrl + wheel zooms, + and − zoom, Fit resets, and a mouse drag pans a 2-D map.
How faithful is the map? — two scores, measured against the original vectors:
trustworthiness (Venna & Kaski 2001, as sklearn.manifold.trustworthiness, k = 10; 1 means none
of a point’s map neighbours are strangers in the original space) and the share of each point’s 10
nearest neighbours that are still among its 10 nearest on the map. Above 1,500 points they are
measured on a sample.
t-SNE and UMAP keep who is next to whom, not how far. Cluster sizes, the gaps
between clusters and positions across the map are largely artefacts of the method and its
settings (compare blobs-tsne with blobs-perplexity-2). Check distances in the neighbour table,
which uses the original vectors.
|
⛶ Full screen (or F) gives the whole window to the tool — the browser’s full screen where it is allowed, otherwise a full-window layer (iPhone). The map fills the space and redraws at the screen’s resolution; Panel ◨ hides or shows the side panel (on a phone it slides up from the bottom). Tabs keep working; Esc (or ✕ Exit full screen) leaves.
Clusters
Clustering runs on the full-dimensional vectors, not on the picture.
-
k-means: Lloyd’s algorithm from k-means++ starts (Arthur & Vassilvitskii 2007), the best of four by inertia (an empty cluster takes the point farthest from its centre, as in scikit-learn). The chart shows inertia (the elbow) and the silhouette for k = 1 … 12; click it to choose k.
-
DBSCAN (Ester et al. 1996) as scikit-learn runs it: a core point has at least minPts points, itself included, within eps; clusters grow from core points; the rest is noise (grey). The k-distance plot (each point’s distance to its (minPts − 1)-th neighbour, sorted) shows where to put eps — at the knee; click the plot to set it. The distance is the Explore tab’s neighbour metric (cosine distance is 1 − cos).
The result gives the number of clusters, the noise, inertia, the mean silhouette (Rousseeuw 1987, Euclidean; noise left out) and, against a metadata column chosen in Compare with, the adjusted Rand index (1 the same grouping, about 0 chance) and a cross-table. Colour the Explore map by cluster carries the colours over.
Analogies
a − b + c, ranked by cosine with q = â − b̂ + ĉ (each vector scaled to length 1 first) and with
a, b and c left out of the answers — exactly gensim’s most_similar(positive=[a, c],
negative=[b]). Leaving the inputs out matters: q is very often closest to a itself, which is
part of why published analogy accuracies flatter embeddings. The picture projects the five vectors
onto their own two principal components: when the analogy holds, b → a and c → answer are
parallel. Works on any dataset with labels — your own GloVe file or embedded sentences too.
Limits
-
t-SNE is the exact O(n²) algorithm (no Barnes–Hut): up to 3,000 points, about a minute for 2,000 points and 1,000 iterations. UMAP and PCA take up to 20,000 points; DBSCAN, the silhouette and the quality scores are O(n²) too.
-
UMAP and the sentence model need a network connection the first time (jsDelivr and the Hugging Face hub). PCA, t-SNE, clustering and analogies work offline.
-
Your own data stays in the page and is gone after a reload; links never contain it (a link made while it is loaded opens the word set with the same settings).
-
The word vectors are constructed, so their analogies work far better than trained ones; the digits are generated, not scanned handwriting.
-
PCA signs are arbitrary (here, each component’s largest entry is positive), so a map may come out mirrored compared with another program.
Tested against scikit-learn 1.9.1 on the same data: PCA explained-variance ratios (to 10⁻¹⁰, all
three code paths), k-means inertia and labels from fixed starts (KMeans(algorithm="elkan")),
DBSCAN labels point for point, silhouette_score, adjusted_rand_score and
trustworthiness; t-SNE’s per-point entropies equal log(perplexity).
Related: Eigenvectors at work (PCA by hand, the SVD and latent semantic indexing), The maths of machine learning (TF-IDF, BM25, cosine similarity, softmax and attention), Neural network designer, Statistics, Model evaluation workbench and Classic ML, step by step.
Sources: L. van der Maaten and G. Hinton, “Visualizing Data using t-SNE”, JMLR 9 (2008); L. McInnes, J. Healy, J. Melville, “UMAP: Uniform Manifold Approximation and Projection”, arXiv:1802.03426; M. Wattenberg, F. Viégas, I. Johnson, “How to Use t-SNE Effectively”, Distill (2016); J. Venna and S. Kaski, “Neighborhood preservation in nonlinear projection methods” (ICANN 2001); M. Ester et al., “A density-based algorithm for discovering clusters” (KDD 1996); T. Mikolov et al., “Linguistic Regularities in Continuous Space Word Representations” (NAACL 2013); N. Reimers and I. Gurevych, “Sentence-BERT” (EMNLP 2019).
Linking to an example
A link opens the tool with the given settings: /tools/embedding-explorer/?<parameters>#<tab>,
where the tab is explore, cluster, analogy or data. Share link (top right) builds one
from what is on screen. Links carry settings and built-in dataset names — never your own vectors.
| Parameter | Meaning | Example |
|---|---|---|
|
a preset (list below); other parameters in the same link override it |
|
|
|
|
|
L2-normalise the vectors ( |
|
|
|
|
|
2 or 3 |
|
|
t-SNE perplexity |
|
|
t-SNE learning rate (0 = auto) |
|
|
t-SNE iterations |
|
|
t-SNE early exaggeration |
|
|
t-SNE start: |
|
|
t-SNE / UMAP seed |
|
|
UMAP neighbours |
|
|
UMAP minimum distance |
|
|
UMAP epochs |
|
|
UMAP start: |
|
|
metadata column to colour by, or |
|
|
|
|
|
neighbour (and UMAP, DBSCAN) distance: |
|
|
neighbours listed |
|
|
search text |
|
|
selected point’s label (or |
|
|
|
|
|
k for k-means |
|
|
DBSCAN radius |
|
|
DBSCAN minPts |
|
|
k-means seed |
|
|
metadata column to compare clusters with |
|
|
analogy words: a − b + c |
|
|
analogy answers listed |
|
|
sentences to embed, one per line ( |
Presets for example=:
| Name | Tab | Shows |
|---|---|---|
|
explore |
The constructed words by PCA, coloured by category; neighbours of “king” |
|
explore |
The same words by t-SNE (perplexity 10): the groups pull apart |
|
explore |
The words in 3-D — drag to rotate |
|
explore |
PCA cannot unroll the Swiss roll: the layers overlap |
|
explore |
t-SNE unrolls it, but tears it into pieces |
|
explore |
UMAP with 30 neighbours and a spectral start unrolls the sheet |
|
explore |
Six 40-D blobs by t-SNE: sizes and gaps are not to scale |
|
explore |
Perplexity 2: spurious little clumps inside each blob |
|
explore |
Digits by PCA: the classes overlap |
|
explore |
Digits by t-SNE: ten islands |
|
explore |
Digits by UMAP |
|
cluster |
k-means, k = 6, on the blobs: adjusted Rand index 1 against the true blobs |
|
cluster |
k-means, k = 10, on the digits against the true digit |
|
cluster |
DBSCAN on the S-curve at eps 0.3: one connected cluster |
|
cluster |
DBSCAN at eps 12, minPts 5: six clusters and 13 noise points |
|
analogy |
king − man + woman ≈ queen |
|
analogy |
paris − france + italy ≈ rome |
|
analogy |
walked − walk + swim ≈ swam |
|
analogy |
puppy − dog + cat ≈ kitten |
|
data |
Sixteen sentences on four topics, ready to embed |
For example, https://geekychris.github.io/tools/embedding-explorer/?example=swissroll-umap opens the unrolled Swiss roll, and https://geekychris.github.io/tools/embedding-explorer/?data=words&method=pca&dim=3&color=continent#explore the word vectors in 3-D coloured by continent.
Feedback is a gift. Something to improve, a feature to add, or a bug? Tell me.
Runs entirely in your browser; nothing you type leaves this page.