Skip to main content

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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

citall-0.2.4.tar.gz (19.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

citall-0.2.4-py3-none-any.whl (17.6 kB view details)

Uploaded Python 3

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

Hashes for citall-0.2.4.tar.gz
Algorithm Hash digest
SHA256 61f3cc88398edd2878aecc1c239f682535130256233091a8fde085cf59160918
MD5 9eda23537de6cf72da7727dd041f9f99
BLAKE2b-256 8009893f326ead06ddea6734d2ccf7811f82064e74e0f22a4418a9a377a4bf97

See more details on using hashes here.

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

Hashes for citall-0.2.4-py3-none-any.whl
Algorithm Hash digest
SHA256 2ee875b3ba7efc5a1d5f0675780840218b203809d14b5f2239664515daf0ee18
MD5 37bfa89e83816e236e0ab2d0be0e0702
BLAKE2b-256 95ccedb65c137449a2942e829e6f4152d38ac4e90b40853498b8f1f88b71bfcf

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page