Skip to main content

anywidget-vector

Interactive 3D vector visualization for Python notebooks.

Works with Marimo, Jupyter, VS Code, Colab, anywhere anywidget runs.

anywidget-vector demo

Features

  • Universal: One widget, every notebook environment
  • 6D Visualization: X, Y, Z position + Color, Shape, Size encoding
  • Backend-agnostic: NumPy, pandas, Qdrant, Chroma, Pinecone, Weaviate, LanceDB, or raw dicts
  • Interactive: Orbit, pan, zoom, click, hover, box select
  • Customizable: Color scales, shapes, sizes, themes
  • Performant: Instanced rendering for large point clouds

Installation

uv add anywidget-vector

Quick Start

from anywidget_vector import VectorSpace

widget = VectorSpace(points=[
    {"id": "a", "x": 0.5, "y": 0.3, "z": 0.8, "label": "Point A", "cluster": 0},
    {"id": "b", "x": -0.2, "y": 0.7, "z": 0.1, "label": "Point B", "cluster": 1},
    {"id": "c", "x": 0.1, "y": -0.4, "z": 0.6, "label": "Point C", "cluster": 0},
])

widget

Data Sources

Dictionary

widget = VectorSpace.from_dict({
    "points": [
        {"id": "a", "x": 0, "y": 0, "z": 0},
        {"id": "b", "x": 1, "y": 1, "z": 1},
    ]
})

NumPy Arrays

import numpy as np

positions = np.random.randn(100, 3)
widget = VectorSpace.from_numpy(positions)

pandas DataFrame

import pandas as pd

df = pd.DataFrame({
    "x": [0.1, 0.5, 0.9],
    "y": [0.2, 0.6, 0.3],
    "z": [0.3, 0.1, 0.7],
    "cluster": ["A", "B", "A"],
    "size": [0.5, 1.0, 0.8],
})

widget = VectorSpace.from_dataframe(
    df,
    color_col="cluster",
    size_col="size",
)

UMAP / t-SNE / PCA

import umap

embedding = umap.UMAP(n_components=3).fit_transform(high_dim_data)
widget = VectorSpace.from_umap(embedding, labels=labels)

Qdrant

from qdrant_client import QdrantClient

client = QdrantClient("localhost", port=6333)
widget = VectorSpace.from_qdrant(client, "my_collection", limit=5000)

ChromaDB

import chromadb

client = chromadb.Client()
collection = client.get_collection("embeddings")
widget = VectorSpace.from_chroma(collection)

Pinecone

from pinecone import Pinecone

pc = Pinecone(api_key="...")
index = pc.Index("my-index")
widget = VectorSpace.from_pinecone(index, limit=5000)

Weaviate

import weaviate

client = weaviate.Client("http://localhost:8080")
widget = VectorSpace.from_weaviate(client, "Article", limit=5000)

LanceDB

import lancedb

db = lancedb.connect("~/.lancedb")
table = db.open_table("vectors")
widget = VectorSpace.from_lancedb(table, limit=5000)

Visual Encoding

6 Dimensions

Dimension Visual Channel Example
X Horizontal position x coordinate
Y Vertical position y coordinate
Z Depth position z coordinate
Color Hue/gradient Cluster, score
Shape Geometry Category, type
Size Scale Importance, count

Color Scales

widget = VectorSpace(
    points=data,
    color_field="score",           # Field to map
    color_scale="viridis",         # Scale: viridis, plasma, inferno, magma, cividis, turbo
    color_domain=[0, 100],         # Optional: explicit range
)

Shapes

widget = VectorSpace(
    points=data,
    shape_field="category",
    shape_map={
        "type_a": "sphere",        # Available: sphere, cube, cone,
        "type_b": "cube",          #            tetrahedron, octahedron, cylinder
        "type_c": "cone",
    }
)

Size

widget = VectorSpace(
    points=data,
    size_field="importance",
    size_range=[0.02, 0.15],       # Min/max point size
)

Interactivity

Events

widget = VectorSpace(points=data)

@widget.on_click
def handle_click(point_id, point_data):
    print(f"Clicked: {point_id}")

@widget.on_hover
def handle_hover(point_id, point_data):
    if point_id:
        print(f"Hovering: {point_id}")

@widget.on_selection
def handle_selection(point_ids, points_data):
    print(f"Selected {len(point_ids)} points")

Selection

widget.selected_points              # Current selection
widget.select(["a", "b"])           # Select points
widget.clear_selection()            # Clear
widget.selection_mode = "box"       # Switch to box-select mode

Camera

widget.camera_position              # Get position [x, y, z]
widget.camera_target                # Get target [x, y, z]
widget.reset_camera()               # Reset to default
widget.focus_on(["a", "b"])         # Focus on specific points

Distance Metrics

Compute distances and visualize similarity relationships between points.

Supported Metrics

Metric Description
euclidean Straight-line distance (L2 norm)
cosine Angle-based distance (1 - cosine similarity)
manhattan Sum of absolute differences (L1 norm)
dot_product Negative dot product (higher = closer)

Color by Distance

widget.color_by_distance("point_a")
widget.color_by_distance("point_a", metric="cosine")

Find Neighbors

neighbors = widget.find_neighbors("point_a", k=5)
# Returns: [("point_b", 0.1), ("point_c", 0.2), ...]

neighbors = widget.find_neighbors("point_a", threshold=0.5)

Show Connections

widget.show_neighbors("point_a", k=5)
widget.show_neighbors("point_a", threshold=0.3)

# Manual connection settings
widget = VectorSpace(
    points=data,
    show_connections=True,
    k_neighbors=3,
    distance_metric="cosine",
    connection_color="#00ff00",
    connection_opacity=0.5,
)

Compute Distances

distances = widget.compute_distances("point_a")
# Returns: {"point_b": 0.1, "point_c": 0.5, ...}

# Use high-dimensional vectors (not just x,y,z)
distances = widget.compute_distances(
    "point_a",
    metric="cosine",
    vector_field="embedding"
)

Options

widget = VectorSpace(
    points=data,
    width=1000,
    height=700,
    background="#1a1a2e",         # Dark theme default
    show_axes=True,
    show_grid=True,
    axis_labels={"x": "PC1", "y": "PC2", "z": "PC3"},
    show_tooltip=True,
    tooltip_fields=["label", "x", "y", "z", "cluster"],
    selection_mode="click",       # "click", "multi", or "box"
    use_instancing=True,          # Performance: instanced rendering
)

Backends

Configure a backend for interactive querying:

widget.set_backend("chroma", client=collection)
widget.set_backend("lancedb", client=table)
widget.set_backend("grafeo", client=db)

Export

widget.to_json()                            # Points as JSON string
widget.to_html()                            # Self-contained HTML string
widget.to_html(title="My Vectors")          # Custom title
widget.save_html("vectors.html")            # Write HTML to file

Environment Support

Environment Supported
Marimo Yes
JupyterLab Yes
Jupyter Notebook Yes
VS Code Yes
Google Colab Yes
Databricks Yes

Related

License

Apache-2.0

Metadata

Release files for anywidget-vector 0.3.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for anywidget-vector 0.3.2
File Size Uploaded
anywidget_vector-0.3.2.tar.gz 381.6 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for anywidget-vector 0.3.2
File Interpreter ABI Platform
anywidget_vector-0.3.2-py3-none-any.whl Python 3 none any Details

Total release size: 448.9 kB

Release files / anywidget_vector-0.3.2.tar.gz

Download URL anywidget_vector-0.3.2.tar.gz
Size 381.6 kB
Tags Source
SHA-256 checksum
How to use checksums
990abf4691b4254a308b989799bd27ca89f839badd33e0eb4d16d3412cfbabf0
BLAKE2b-256 checksum
How to use checksums
e469366f6b04928cebb0cac7eabd472caf41f19d60341eca87faeed4589a635d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Mar 16, 2026.

Transparency log

Release files / anywidget_vector-0.3.2-py3-none-any.whl

Download URL anywidget_vector-0.3.2-py3-none-any.whl
Size 67.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
b1df7ec784424d75f4d83df5d518a79a68cc9b53b46ab3da4e7aea8e6fde02b0
BLAKE2b-256 checksum
How to use checksums
e77363cd79bf880b3cfaf4b5c1595e7918f458aaf5fde135f7fde6bbbb44a5d3
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Mar 16, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.3.2 This release

2 release files

0.3.1

2 release files

0.3.0

2 release files

0.2.8

2 release files

0.2.7

2 release files

0.2.6

2 release files

0.2.5

2 release files

0.2.4

2 release files

0.2.3

2 release files

0.2.2

2 release files

0.2.1

2 release files

0.2.0

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page