Interactive 3D PCA visualization from PyTorch embeddings with Plotly
Project description
citall
Python library for turning PyTorch embedding tensors into interactive, shareable 3D PCA explorers — with hover metadata and image previews — in a single function call.
Install
pip install citall
# or with uv
uv add citall
Quick Start
from citall import pca3d_explorer
pca3d_explorer(
vectors_pt="embeddings.pt",
output_html="explorer.html",
open_browser=True,
)
That's it. Open explorer.html in any browser — no server required.
What It Produces
A self-contained HTML file with:
- A 3D scatter plot of your embeddings projected onto their first 3 principal components, with per-axis variance percentages in the labels.
- Hover tooltips showing metadata fields you choose.
- A click side-panel showing detailed metadata and image previews for whichever point you select.
- Color-by support: numeric fields get a continuous Viridis gradient; categorical fields get a discrete legend.
API Reference
pca3d_explorer
| Parameter | Type | Default | Description |
|---|---|---|---|
vectors_pt |
str | Path | dict |
required | Your embeddings. Accepts a path to a .pt file, or a Python dict. See Inputs for all supported shapes. |
metadata_path |
str | Path |
None |
Path to a .json or .jsonl file containing per-embedding metadata. Each record is matched to a vector via metadata_key + rows_key. |
metadata_key |
str | list[str] |
None |
The field (or list of fields) in the metadata file used as the join key. Required when metadata_path is provided. Supports pipe syntax: "object_id|uid". |
rows_key |
str | list[str] |
None |
The field (or list of fields) in the embedding rows used as the join key. Defaults to the vector id when omitted. |
images_dir |
str | Path |
None |
A directory of images. citall looks for <id>, <id>.png, <id>.jpg, <id>.jpeg, <id>.webp, or <id>.gif, and falls back to using the filename field from the row. If <id> is itself a subdirectory, all images inside it are collected (up to max_images_per_embedding). |
image_dir_key |
str |
None |
A field name in metadata/rows whose value is a path to a folder of images for that embedding. Relative paths are resolved against images_dir when set. Takes priority over images_dir fallback. |
max_images_per_embedding |
int |
6 |
Maximum number of images loaded and shown in the side panel per point. Set to None to load all. |
hover_fields |
list[str] |
None |
Metadata fields to show in the hover tooltip. When None, up to 6 fields are shown automatically. |
click_fields |
list[str] |
None |
Metadata fields to show in the click side panel. When None, all available metadata is shown. |
color_by |
str |
None |
A metadata field used to color the points. Numeric values produce a continuous Viridis gradient; string values produce discrete legend groups. Points missing the field appear in grey. |
output_html |
str | Path |
None |
Where to write the HTML file. Defaults to citall_plot.html in the current directory. When open_browser=True and this is None, a temporary file is used instead. |
open_browser |
bool |
False |
Automatically open the generated HTML in your default browser after saving. |
return_summary |
bool |
False |
When True, the function returns (Path, dict) instead of just Path. The dict contains diagnostic counts and PCA statistics — see Summary Dict below. |
from citall import pca3d_explorer
output_path = pca3d_explorer(
vectors_pt="embeddings.pt",
metadata_path="meta.jsonl",
metadata_key="id",
hover_fields=["label", "split"],
color_by="label",
output_html="explorer.html",
)
When return_summary=True, the return value is (Path, dict):
output_path, summary = pca3d_explorer(..., return_summary=True)
print(summary["num_points"])
print(summary["pca_explained_variance_ratio"])
CitallExplorer (class API)
For multi-step workflows or when you want to reuse the same dataset:
from citall import CitallExplorer
explorer = CitallExplorer.from_files(
vectors_pt=...,
metadata_path=...,
metadata_key=...,
rows_key=...,
images_dir=...,
image_dir_key=...,
max_images_per_embedding=6,
)
explorer.compute_pca() # runs PCA, stores result internally
explorer.save_html("out.html", hover_fields=["label"], color_by="label")
print(explorer.summary())
Inputs
Vectors (vectors_pt)
Accepts any of:
| What you pass | How it's interpreted |
|---|---|
Path to a .pt file containing a Tensor of shape (N, D) |
Ids become "0", "1", … |
Path to a .pt dict with vectors/embeddings/tensor/data key |
Ids from ids/keys/labels/names key, or auto-numbered |
Dict with an embeddings (or vectors) tensor + a rows list of dicts |
Ids from row["uid"] or row["id"], else index |
Any of the above passed as a Python dict directly (no file needed) |
Same as above |
Metadata (metadata_path)
.json or .jsonl file. Supported formats:
- JSONL — one object per line
- JSON list —
[{...}, {...}] - JSON map —
{"id1": {...}, "id2": {...}}(the key is injected as"id")
Metadata is joined to vectors by matching metadata_key against rows_key. If both your rows and metadata contain an object_id field, the join happens automatically with no extra config.
Images
Two ways to attach images to points:
| Parameter | What it does |
|---|---|
images_dir |
A flat folder or folder-per-id. citall looks for <id>, <id>.png, <id>.jpg, etc., and also checks the filename field as a fallback. |
image_dir_key |
A metadata/row field whose value is a path to a folder of images for that embedding. Combined with images_dir as a base when the path is relative. |
max_images_per_embedding caps how many images are loaded (and shown in the side panel) per point. Default is 6.
Coloring Points
pca3d_explorer(..., color_by="label")
- Numeric field → continuous Viridis gradient with a colorbar.
- Categorical field → discrete legend groups.
- Points missing the field → rendered in neutral grey, shown as a separate legend entry.
Summary Dict
When return_summary=True, you get back a dict with:
| Key | Description |
|---|---|
num_points |
Total points in the plot |
vector_shape |
Shape of the input tensor |
metadata_rows_matched |
Points that have at least one metadata row |
images_matched |
Points that have at least one resolved image |
matched_vectors |
Vectors successfully joined to metadata |
unmatched_vectors |
Vectors with no metadata match |
missing_images |
Points where image resolution failed |
pca_explained_variance_ratio |
[pc1%, pc2%, pc3%] as floats |
Examples
Minimal — tensor only
import torch
from citall import pca3d_explorer
vectors = torch.randn(500, 128)
pca3d_explorer(vectors_pt={"embeddings": vectors, "rows": []}, output_html="out.html")
With metadata and coloring
pca3d_explorer(
vectors_pt="embeddings.pt",
metadata_path="meta.jsonl",
metadata_key="id",
hover_fields=["label", "source"],
click_fields=["label", "filename", "score"],
color_by="label",
output_html="explorer.html",
open_browser=True,
)
Raw dict payload + images per embedding
pca3d_explorer(
vectors_pt={"embeddings": tensor, "rows": rows}, # rows is a list of dicts
images_dir="./data/images", # base folder — citall looks for ./data/images/<id>.jpg (or a folder named <id>)
image_dir_key="folder", # if a row has a "folder" field, citall loads images from that folder instead
max_images_per_embedding=4,
color_by="category",
output_html="explorer.html",
)
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file citall-0.2.4.tar.gz.
File metadata
- Download URL: citall-0.2.4.tar.gz
- Upload date:
- Size: 19.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.10.2 {"installer":{"name":"uv","version":"0.10.2","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
61f3cc88398edd2878aecc1c239f682535130256233091a8fde085cf59160918
|
|
| MD5 |
9eda23537de6cf72da7727dd041f9f99
|
|
| BLAKE2b-256 |
8009893f326ead06ddea6734d2ccf7811f82064e74e0f22a4418a9a377a4bf97
|
File details
Details for the file citall-0.2.4-py3-none-any.whl.
File metadata
- Download URL: citall-0.2.4-py3-none-any.whl
- Upload date:
- Size: 17.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.10.2 {"installer":{"name":"uv","version":"0.10.2","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2ee875b3ba7efc5a1d5f0675780840218b203809d14b5f2239664515daf0ee18
|
|
| MD5 |
37bfa89e83816e236e0ab2d0be0e0702
|
|
| BLAKE2b-256 |
95ccedb65c137449a2942e829e6f4152d38ac4e90b40853498b8f1f88b71bfcf
|