anywidget-vector 0.2.3__tar.gz → 0.2.5__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {anywidget_vector-0.2.3 → anywidget_vector-0.2.5}/PKG-INFO +86 -59
- {anywidget_vector-0.2.3 → anywidget_vector-0.2.5}/README.md +78 -51
- {anywidget_vector-0.2.3 → anywidget_vector-0.2.5}/pyproject.toml +9 -9
- {anywidget_vector-0.2.3 → anywidget_vector-0.2.5}/src/anywidget_vector/__init__.py +1 -1
- {anywidget_vector-0.2.3 → anywidget_vector-0.2.5}/src/anywidget_vector/static/icons.js +5 -0
- {anywidget_vector-0.2.3 → anywidget_vector-0.2.5}/src/anywidget_vector/ui/canvas.js +205 -2
- {anywidget_vector-0.2.3 → anywidget_vector-0.2.5}/src/anywidget_vector/ui/styles.css +69 -0
- {anywidget_vector-0.2.3 → anywidget_vector-0.2.5}/src/anywidget_vector/ui/toolbar.js +11 -0
- {anywidget_vector-0.2.3 → anywidget_vector-0.2.5}/src/anywidget_vector/widget.py +425 -1
- {anywidget_vector-0.2.3 → anywidget_vector-0.2.5}/tests/test_widget.py +141 -0
- {anywidget_vector-0.2.3 → anywidget_vector-0.2.5}/uv.lock +145 -67
- anywidget_vector-0.2.3/src/anywidget_vector/traitlets.py +0 -84
- {anywidget_vector-0.2.3 → anywidget_vector-0.2.5}/.github/workflows/ci.yml +0 -0
- {anywidget_vector-0.2.3 → anywidget_vector-0.2.5}/.github/workflows/pypi.yml +0 -0
- {anywidget_vector-0.2.3 → anywidget_vector-0.2.5}/.gitignore +0 -0
- {anywidget_vector-0.2.3 → anywidget_vector-0.2.5}/.python-version +0 -0
- {anywidget_vector-0.2.3 → anywidget_vector-0.2.5}/LICENSE +0 -0
- {anywidget_vector-0.2.3 → anywidget_vector-0.2.5}/examples/demo.py +0 -0
- {anywidget_vector-0.2.3 → anywidget_vector-0.2.5}/src/anywidget_vector/backends/__init__.py +0 -0
- {anywidget_vector-0.2.3 → anywidget_vector-0.2.5}/src/anywidget_vector/backends/chroma/__init__.py +0 -0
- {anywidget_vector-0.2.3 → anywidget_vector-0.2.5}/src/anywidget_vector/backends/chroma/client.py +0 -0
- {anywidget_vector-0.2.3 → anywidget_vector-0.2.5}/src/anywidget_vector/backends/chroma/converter.py +0 -0
- {anywidget_vector-0.2.3 → anywidget_vector-0.2.5}/src/anywidget_vector/backends/grafeo/__init__.py +0 -0
- {anywidget_vector-0.2.3 → anywidget_vector-0.2.5}/src/anywidget_vector/backends/grafeo/browser.js +0 -0
- {anywidget_vector-0.2.3 → anywidget_vector-0.2.5}/src/anywidget_vector/backends/grafeo/client.py +0 -0
- {anywidget_vector-0.2.3 → anywidget_vector-0.2.5}/src/anywidget_vector/backends/grafeo/converter.py +0 -0
- {anywidget_vector-0.2.3 → anywidget_vector-0.2.5}/src/anywidget_vector/backends/grafeo/embed.js +0 -0
- {anywidget_vector-0.2.3 → anywidget_vector-0.2.5}/src/anywidget_vector/backends/lancedb/__init__.py +0 -0
- {anywidget_vector-0.2.3 → anywidget_vector-0.2.5}/src/anywidget_vector/backends/lancedb/client.py +0 -0
- {anywidget_vector-0.2.3 → anywidget_vector-0.2.5}/src/anywidget_vector/backends/lancedb/converter.py +0 -0
- {anywidget_vector-0.2.3 → anywidget_vector-0.2.5}/src/anywidget_vector/backends/pinecone/__init__.py +0 -0
- {anywidget_vector-0.2.3 → anywidget_vector-0.2.5}/src/anywidget_vector/backends/pinecone/client.js +0 -0
- {anywidget_vector-0.2.3 → anywidget_vector-0.2.5}/src/anywidget_vector/backends/pinecone/converter.py +0 -0
- {anywidget_vector-0.2.3 → anywidget_vector-0.2.5}/src/anywidget_vector/backends/qdrant/__init__.py +0 -0
- {anywidget_vector-0.2.3 → anywidget_vector-0.2.5}/src/anywidget_vector/backends/qdrant/client.js +0 -0
- {anywidget_vector-0.2.3 → anywidget_vector-0.2.5}/src/anywidget_vector/backends/qdrant/converter.py +0 -0
- {anywidget_vector-0.2.3 → anywidget_vector-0.2.5}/src/anywidget_vector/backends/weaviate/__init__.py +0 -0
- {anywidget_vector-0.2.3 → anywidget_vector-0.2.5}/src/anywidget_vector/backends/weaviate/client.js +0 -0
- {anywidget_vector-0.2.3 → anywidget_vector-0.2.5}/src/anywidget_vector/backends/weaviate/converter.py +0 -0
- {anywidget_vector-0.2.3 → anywidget_vector-0.2.5}/src/anywidget_vector/demo.py +0 -0
- {anywidget_vector-0.2.3 → anywidget_vector-0.2.5}/src/anywidget_vector/py.typed +0 -0
- {anywidget_vector-0.2.3 → anywidget_vector-0.2.5}/src/anywidget_vector/ui/__init__.py +0 -0
- {anywidget_vector-0.2.3 → anywidget_vector-0.2.5}/src/anywidget_vector/ui/constants.js +0 -0
- {anywidget_vector-0.2.3 → anywidget_vector-0.2.5}/src/anywidget_vector/ui/properties.js +0 -0
- {anywidget_vector-0.2.3 → anywidget_vector-0.2.5}/src/anywidget_vector/ui/settings.js +0 -0
- {anywidget_vector-0.2.3 → anywidget_vector-0.2.5}/src/anywidget_vector/ui/sidebar.js +0 -0
- {anywidget_vector-0.2.3 → anywidget_vector-0.2.5}/tests/__init__.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: anywidget-vector
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.5
|
|
4
4
|
Summary: Interactive 3D vector visualization with query UI for vector databases
|
|
5
5
|
Project-URL: Homepage, https://grafeo.dev/
|
|
6
6
|
Project-URL: Repository, https://github.com/GrafeoDB/anywidget-vector
|
|
@@ -24,22 +24,22 @@ Provides-Extra: all
|
|
|
24
24
|
Requires-Dist: chromadb>=1.5; extra == 'all'
|
|
25
25
|
Requires-Dist: lancedb>=0.29.2; extra == 'all'
|
|
26
26
|
Requires-Dist: numpy>=2.4; extra == 'all'
|
|
27
|
-
Requires-Dist: pandas>=3
|
|
27
|
+
Requires-Dist: pandas>=3; extra == 'all'
|
|
28
28
|
Requires-Dist: pinecone-client>=6.0; extra == 'all'
|
|
29
|
-
Requires-Dist: qdrant-client>=1
|
|
30
|
-
Requires-Dist: weaviate-client>=4.
|
|
29
|
+
Requires-Dist: qdrant-client>=1; extra == 'all'
|
|
30
|
+
Requires-Dist: weaviate-client>=4.20; extra == 'all'
|
|
31
31
|
Provides-Extra: chroma
|
|
32
32
|
Requires-Dist: chromadb>=0.4; extra == 'chroma'
|
|
33
33
|
Provides-Extra: demo
|
|
34
34
|
Provides-Extra: dev
|
|
35
|
-
Requires-Dist: marimo>=0.
|
|
35
|
+
Requires-Dist: marimo>=0.20; extra == 'dev'
|
|
36
36
|
Requires-Dist: prek>=0.3.2; extra == 'dev'
|
|
37
37
|
Requires-Dist: pytest>=9.0.2; extra == 'dev'
|
|
38
|
-
Requires-Dist: ruff>=0.15
|
|
39
|
-
Requires-Dist: ty>=0.0.
|
|
38
|
+
Requires-Dist: ruff>=0.15; extra == 'dev'
|
|
39
|
+
Requires-Dist: ty>=0.0.20; extra == 'dev'
|
|
40
40
|
Provides-Extra: embed
|
|
41
41
|
Provides-Extra: grafeo
|
|
42
|
-
Requires-Dist: grafeo>=0.5
|
|
42
|
+
Requires-Dist: grafeo>=0.5; extra == 'grafeo'
|
|
43
43
|
Provides-Extra: lancedb
|
|
44
44
|
Requires-Dist: lancedb>=0.1; extra == 'lancedb'
|
|
45
45
|
Provides-Extra: numpy
|
|
@@ -64,8 +64,8 @@ Works with Marimo, Jupyter, VS Code, Colab, anywhere [anywidget](https://anywidg
|
|
|
64
64
|
|
|
65
65
|
- **Universal**: One widget, every notebook environment
|
|
66
66
|
- **6D Visualization**: X, Y, Z position + Color, Shape, Size encoding
|
|
67
|
-
- **Backend-agnostic**: NumPy, pandas, Qdrant, Chroma, or raw dicts
|
|
68
|
-
- **Interactive**: Orbit, pan, zoom, click, hover, select
|
|
67
|
+
- **Backend-agnostic**: NumPy, pandas, Qdrant, Chroma, Pinecone, Weaviate, LanceDB, or raw dicts
|
|
68
|
+
- **Interactive**: Orbit, pan, zoom, click, hover, box select
|
|
69
69
|
- **Customizable**: Color scales, shapes, sizes, themes
|
|
70
70
|
- **Performant**: Instanced rendering for large point clouds
|
|
71
71
|
|
|
@@ -94,8 +94,6 @@ widget
|
|
|
94
94
|
### Dictionary
|
|
95
95
|
|
|
96
96
|
```python
|
|
97
|
-
from anywidget_vector import VectorSpace
|
|
98
|
-
|
|
99
97
|
widget = VectorSpace.from_dict({
|
|
100
98
|
"points": [
|
|
101
99
|
{"id": "a", "x": 0, "y": 0, "z": 0},
|
|
@@ -108,7 +106,6 @@ widget = VectorSpace.from_dict({
|
|
|
108
106
|
|
|
109
107
|
```python
|
|
110
108
|
import numpy as np
|
|
111
|
-
from anywidget_vector import VectorSpace
|
|
112
109
|
|
|
113
110
|
positions = np.random.randn(100, 3)
|
|
114
111
|
widget = VectorSpace.from_numpy(positions)
|
|
@@ -118,7 +115,6 @@ widget = VectorSpace.from_numpy(positions)
|
|
|
118
115
|
|
|
119
116
|
```python
|
|
120
117
|
import pandas as pd
|
|
121
|
-
from anywidget_vector import VectorSpace
|
|
122
118
|
|
|
123
119
|
df = pd.DataFrame({
|
|
124
120
|
"x": [0.1, 0.5, 0.9],
|
|
@@ -139,9 +135,7 @@ widget = VectorSpace.from_dataframe(
|
|
|
139
135
|
|
|
140
136
|
```python
|
|
141
137
|
import umap
|
|
142
|
-
from anywidget_vector import VectorSpace
|
|
143
138
|
|
|
144
|
-
# Reduce high-dimensional data to 3D
|
|
145
139
|
embedding = umap.UMAP(n_components=3).fit_transform(high_dim_data)
|
|
146
140
|
widget = VectorSpace.from_umap(embedding, labels=labels)
|
|
147
141
|
```
|
|
@@ -150,7 +144,6 @@ widget = VectorSpace.from_umap(embedding, labels=labels)
|
|
|
150
144
|
|
|
151
145
|
```python
|
|
152
146
|
from qdrant_client import QdrantClient
|
|
153
|
-
from anywidget_vector import VectorSpace
|
|
154
147
|
|
|
155
148
|
client = QdrantClient("localhost", port=6333)
|
|
156
149
|
widget = VectorSpace.from_qdrant(client, "my_collection", limit=5000)
|
|
@@ -160,13 +153,41 @@ widget = VectorSpace.from_qdrant(client, "my_collection", limit=5000)
|
|
|
160
153
|
|
|
161
154
|
```python
|
|
162
155
|
import chromadb
|
|
163
|
-
from anywidget_vector import VectorSpace
|
|
164
156
|
|
|
165
157
|
client = chromadb.Client()
|
|
166
158
|
collection = client.get_collection("embeddings")
|
|
167
159
|
widget = VectorSpace.from_chroma(collection)
|
|
168
160
|
```
|
|
169
161
|
|
|
162
|
+
### Pinecone
|
|
163
|
+
|
|
164
|
+
```python
|
|
165
|
+
from pinecone import Pinecone
|
|
166
|
+
|
|
167
|
+
pc = Pinecone(api_key="...")
|
|
168
|
+
index = pc.Index("my-index")
|
|
169
|
+
widget = VectorSpace.from_pinecone(index, limit=5000)
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### Weaviate
|
|
173
|
+
|
|
174
|
+
```python
|
|
175
|
+
import weaviate
|
|
176
|
+
|
|
177
|
+
client = weaviate.Client("http://localhost:8080")
|
|
178
|
+
widget = VectorSpace.from_weaviate(client, "Article", limit=5000)
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
### LanceDB
|
|
182
|
+
|
|
183
|
+
```python
|
|
184
|
+
import lancedb
|
|
185
|
+
|
|
186
|
+
db = lancedb.connect("~/.lancedb")
|
|
187
|
+
table = db.open_table("vectors")
|
|
188
|
+
widget = VectorSpace.from_lancedb(table, limit=5000)
|
|
189
|
+
```
|
|
190
|
+
|
|
170
191
|
## Visual Encoding
|
|
171
192
|
|
|
172
193
|
### 6 Dimensions
|
|
@@ -225,7 +246,6 @@ widget = VectorSpace(points=data)
|
|
|
225
246
|
@widget.on_click
|
|
226
247
|
def handle_click(point_id, point_data):
|
|
227
248
|
print(f"Clicked: {point_id}")
|
|
228
|
-
print(f"Data: {point_data}")
|
|
229
249
|
|
|
230
250
|
@widget.on_hover
|
|
231
251
|
def handle_hover(point_id, point_data):
|
|
@@ -240,36 +260,19 @@ def handle_selection(point_ids, points_data):
|
|
|
240
260
|
### Selection
|
|
241
261
|
|
|
242
262
|
```python
|
|
243
|
-
widget.selected_points
|
|
244
|
-
widget.select(["a", "b"])
|
|
245
|
-
widget.clear_selection()
|
|
263
|
+
widget.selected_points # Current selection
|
|
264
|
+
widget.select(["a", "b"]) # Select points
|
|
265
|
+
widget.clear_selection() # Clear
|
|
266
|
+
widget.selection_mode = "box" # Switch to box-select mode
|
|
246
267
|
```
|
|
247
268
|
|
|
248
269
|
### Camera
|
|
249
270
|
|
|
250
271
|
```python
|
|
251
|
-
widget.camera_position
|
|
252
|
-
widget.camera_target
|
|
253
|
-
widget.reset_camera()
|
|
254
|
-
widget.focus_on(["a", "b"])
|
|
255
|
-
```
|
|
256
|
-
|
|
257
|
-
## Options
|
|
258
|
-
|
|
259
|
-
```python
|
|
260
|
-
widget = VectorSpace(
|
|
261
|
-
points=data,
|
|
262
|
-
width=1000,
|
|
263
|
-
height=700,
|
|
264
|
-
background="#1a1a2e", # Dark theme default
|
|
265
|
-
show_axes=True,
|
|
266
|
-
show_grid=True,
|
|
267
|
-
axis_labels={"x": "PC1", "y": "PC2", "z": "PC3"},
|
|
268
|
-
show_tooltip=True,
|
|
269
|
-
tooltip_fields=["label", "x", "y", "z", "cluster"],
|
|
270
|
-
selection_mode="click", # "click" or "multi"
|
|
271
|
-
use_instancing=True, # Performance: instanced rendering
|
|
272
|
-
)
|
|
272
|
+
widget.camera_position # Get position [x, y, z]
|
|
273
|
+
widget.camera_target # Get target [x, y, z]
|
|
274
|
+
widget.reset_camera() # Reset to default
|
|
275
|
+
widget.focus_on(["a", "b"]) # Focus on specific points
|
|
273
276
|
```
|
|
274
277
|
|
|
275
278
|
## Distance Metrics
|
|
@@ -288,7 +291,6 @@ Compute distances and visualize similarity relationships between points.
|
|
|
288
291
|
### Color by Distance
|
|
289
292
|
|
|
290
293
|
```python
|
|
291
|
-
# Color points by distance from a reference
|
|
292
294
|
widget.color_by_distance("point_a")
|
|
293
295
|
widget.color_by_distance("point_a", metric="cosine")
|
|
294
296
|
```
|
|
@@ -296,21 +298,16 @@ widget.color_by_distance("point_a", metric="cosine")
|
|
|
296
298
|
### Find Neighbors
|
|
297
299
|
|
|
298
300
|
```python
|
|
299
|
-
# Find k nearest neighbors
|
|
300
301
|
neighbors = widget.find_neighbors("point_a", k=5)
|
|
301
302
|
# Returns: [("point_b", 0.1), ("point_c", 0.2), ...]
|
|
302
303
|
|
|
303
|
-
# Find neighbors within distance threshold
|
|
304
304
|
neighbors = widget.find_neighbors("point_a", threshold=0.5)
|
|
305
305
|
```
|
|
306
306
|
|
|
307
307
|
### Show Connections
|
|
308
308
|
|
|
309
309
|
```python
|
|
310
|
-
# Draw lines to k-nearest neighbors
|
|
311
310
|
widget.show_neighbors("point_a", k=5)
|
|
312
|
-
|
|
313
|
-
# Draw lines to all points within threshold
|
|
314
311
|
widget.show_neighbors("point_a", threshold=0.3)
|
|
315
312
|
|
|
316
313
|
# Manual connection settings
|
|
@@ -327,7 +324,6 @@ widget = VectorSpace(
|
|
|
327
324
|
### Compute Distances
|
|
328
325
|
|
|
329
326
|
```python
|
|
330
|
-
# Get distances from reference to all points
|
|
331
327
|
distances = widget.compute_distances("point_a")
|
|
332
328
|
# Returns: {"point_b": 0.1, "point_c": 0.5, ...}
|
|
333
329
|
|
|
@@ -335,26 +331,57 @@ distances = widget.compute_distances("point_a")
|
|
|
335
331
|
distances = widget.compute_distances(
|
|
336
332
|
"point_a",
|
|
337
333
|
metric="cosine",
|
|
338
|
-
vector_field="embedding"
|
|
334
|
+
vector_field="embedding"
|
|
339
335
|
)
|
|
340
336
|
```
|
|
341
337
|
|
|
338
|
+
## Options
|
|
339
|
+
|
|
340
|
+
```python
|
|
341
|
+
widget = VectorSpace(
|
|
342
|
+
points=data,
|
|
343
|
+
width=1000,
|
|
344
|
+
height=700,
|
|
345
|
+
background="#1a1a2e", # Dark theme default
|
|
346
|
+
show_axes=True,
|
|
347
|
+
show_grid=True,
|
|
348
|
+
axis_labels={"x": "PC1", "y": "PC2", "z": "PC3"},
|
|
349
|
+
show_tooltip=True,
|
|
350
|
+
tooltip_fields=["label", "x", "y", "z", "cluster"],
|
|
351
|
+
selection_mode="click", # "click", "multi", or "box"
|
|
352
|
+
use_instancing=True, # Performance: instanced rendering
|
|
353
|
+
)
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
## Backends
|
|
357
|
+
|
|
358
|
+
Configure a backend for interactive querying:
|
|
359
|
+
|
|
360
|
+
```python
|
|
361
|
+
widget.set_backend("chroma", client=collection)
|
|
362
|
+
widget.set_backend("lancedb", client=table)
|
|
363
|
+
widget.set_backend("grafeo", client=db)
|
|
364
|
+
```
|
|
365
|
+
|
|
342
366
|
## Export
|
|
343
367
|
|
|
344
368
|
```python
|
|
345
|
-
widget.to_json()
|
|
369
|
+
widget.to_json() # Points as JSON string
|
|
370
|
+
widget.to_html() # Self-contained HTML string
|
|
371
|
+
widget.to_html(title="My Vectors") # Custom title
|
|
372
|
+
widget.save_html("vectors.html") # Write HTML to file
|
|
346
373
|
```
|
|
347
374
|
|
|
348
375
|
## Environment Support
|
|
349
376
|
|
|
350
377
|
| Environment | Supported |
|
|
351
378
|
|-------------|-----------|
|
|
352
|
-
| Marimo |
|
|
353
|
-
| JupyterLab |
|
|
354
|
-
| Jupyter Notebook |
|
|
355
|
-
| VS Code |
|
|
356
|
-
| Google Colab |
|
|
357
|
-
| Databricks |
|
|
379
|
+
| Marimo | Yes |
|
|
380
|
+
| JupyterLab | Yes |
|
|
381
|
+
| Jupyter Notebook | Yes |
|
|
382
|
+
| VS Code | Yes |
|
|
383
|
+
| Google Colab | Yes |
|
|
384
|
+
| Databricks | Yes |
|
|
358
385
|
|
|
359
386
|
## Related
|
|
360
387
|
|
|
@@ -8,8 +8,8 @@ Works with Marimo, Jupyter, VS Code, Colab, anywhere [anywidget](https://anywidg
|
|
|
8
8
|
|
|
9
9
|
- **Universal**: One widget, every notebook environment
|
|
10
10
|
- **6D Visualization**: X, Y, Z position + Color, Shape, Size encoding
|
|
11
|
-
- **Backend-agnostic**: NumPy, pandas, Qdrant, Chroma, or raw dicts
|
|
12
|
-
- **Interactive**: Orbit, pan, zoom, click, hover, select
|
|
11
|
+
- **Backend-agnostic**: NumPy, pandas, Qdrant, Chroma, Pinecone, Weaviate, LanceDB, or raw dicts
|
|
12
|
+
- **Interactive**: Orbit, pan, zoom, click, hover, box select
|
|
13
13
|
- **Customizable**: Color scales, shapes, sizes, themes
|
|
14
14
|
- **Performant**: Instanced rendering for large point clouds
|
|
15
15
|
|
|
@@ -38,8 +38,6 @@ widget
|
|
|
38
38
|
### Dictionary
|
|
39
39
|
|
|
40
40
|
```python
|
|
41
|
-
from anywidget_vector import VectorSpace
|
|
42
|
-
|
|
43
41
|
widget = VectorSpace.from_dict({
|
|
44
42
|
"points": [
|
|
45
43
|
{"id": "a", "x": 0, "y": 0, "z": 0},
|
|
@@ -52,7 +50,6 @@ widget = VectorSpace.from_dict({
|
|
|
52
50
|
|
|
53
51
|
```python
|
|
54
52
|
import numpy as np
|
|
55
|
-
from anywidget_vector import VectorSpace
|
|
56
53
|
|
|
57
54
|
positions = np.random.randn(100, 3)
|
|
58
55
|
widget = VectorSpace.from_numpy(positions)
|
|
@@ -62,7 +59,6 @@ widget = VectorSpace.from_numpy(positions)
|
|
|
62
59
|
|
|
63
60
|
```python
|
|
64
61
|
import pandas as pd
|
|
65
|
-
from anywidget_vector import VectorSpace
|
|
66
62
|
|
|
67
63
|
df = pd.DataFrame({
|
|
68
64
|
"x": [0.1, 0.5, 0.9],
|
|
@@ -83,9 +79,7 @@ widget = VectorSpace.from_dataframe(
|
|
|
83
79
|
|
|
84
80
|
```python
|
|
85
81
|
import umap
|
|
86
|
-
from anywidget_vector import VectorSpace
|
|
87
82
|
|
|
88
|
-
# Reduce high-dimensional data to 3D
|
|
89
83
|
embedding = umap.UMAP(n_components=3).fit_transform(high_dim_data)
|
|
90
84
|
widget = VectorSpace.from_umap(embedding, labels=labels)
|
|
91
85
|
```
|
|
@@ -94,7 +88,6 @@ widget = VectorSpace.from_umap(embedding, labels=labels)
|
|
|
94
88
|
|
|
95
89
|
```python
|
|
96
90
|
from qdrant_client import QdrantClient
|
|
97
|
-
from anywidget_vector import VectorSpace
|
|
98
91
|
|
|
99
92
|
client = QdrantClient("localhost", port=6333)
|
|
100
93
|
widget = VectorSpace.from_qdrant(client, "my_collection", limit=5000)
|
|
@@ -104,13 +97,41 @@ widget = VectorSpace.from_qdrant(client, "my_collection", limit=5000)
|
|
|
104
97
|
|
|
105
98
|
```python
|
|
106
99
|
import chromadb
|
|
107
|
-
from anywidget_vector import VectorSpace
|
|
108
100
|
|
|
109
101
|
client = chromadb.Client()
|
|
110
102
|
collection = client.get_collection("embeddings")
|
|
111
103
|
widget = VectorSpace.from_chroma(collection)
|
|
112
104
|
```
|
|
113
105
|
|
|
106
|
+
### Pinecone
|
|
107
|
+
|
|
108
|
+
```python
|
|
109
|
+
from pinecone import Pinecone
|
|
110
|
+
|
|
111
|
+
pc = Pinecone(api_key="...")
|
|
112
|
+
index = pc.Index("my-index")
|
|
113
|
+
widget = VectorSpace.from_pinecone(index, limit=5000)
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### Weaviate
|
|
117
|
+
|
|
118
|
+
```python
|
|
119
|
+
import weaviate
|
|
120
|
+
|
|
121
|
+
client = weaviate.Client("http://localhost:8080")
|
|
122
|
+
widget = VectorSpace.from_weaviate(client, "Article", limit=5000)
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### LanceDB
|
|
126
|
+
|
|
127
|
+
```python
|
|
128
|
+
import lancedb
|
|
129
|
+
|
|
130
|
+
db = lancedb.connect("~/.lancedb")
|
|
131
|
+
table = db.open_table("vectors")
|
|
132
|
+
widget = VectorSpace.from_lancedb(table, limit=5000)
|
|
133
|
+
```
|
|
134
|
+
|
|
114
135
|
## Visual Encoding
|
|
115
136
|
|
|
116
137
|
### 6 Dimensions
|
|
@@ -169,7 +190,6 @@ widget = VectorSpace(points=data)
|
|
|
169
190
|
@widget.on_click
|
|
170
191
|
def handle_click(point_id, point_data):
|
|
171
192
|
print(f"Clicked: {point_id}")
|
|
172
|
-
print(f"Data: {point_data}")
|
|
173
193
|
|
|
174
194
|
@widget.on_hover
|
|
175
195
|
def handle_hover(point_id, point_data):
|
|
@@ -184,36 +204,19 @@ def handle_selection(point_ids, points_data):
|
|
|
184
204
|
### Selection
|
|
185
205
|
|
|
186
206
|
```python
|
|
187
|
-
widget.selected_points
|
|
188
|
-
widget.select(["a", "b"])
|
|
189
|
-
widget.clear_selection()
|
|
207
|
+
widget.selected_points # Current selection
|
|
208
|
+
widget.select(["a", "b"]) # Select points
|
|
209
|
+
widget.clear_selection() # Clear
|
|
210
|
+
widget.selection_mode = "box" # Switch to box-select mode
|
|
190
211
|
```
|
|
191
212
|
|
|
192
213
|
### Camera
|
|
193
214
|
|
|
194
215
|
```python
|
|
195
|
-
widget.camera_position
|
|
196
|
-
widget.camera_target
|
|
197
|
-
widget.reset_camera()
|
|
198
|
-
widget.focus_on(["a", "b"])
|
|
199
|
-
```
|
|
200
|
-
|
|
201
|
-
## Options
|
|
202
|
-
|
|
203
|
-
```python
|
|
204
|
-
widget = VectorSpace(
|
|
205
|
-
points=data,
|
|
206
|
-
width=1000,
|
|
207
|
-
height=700,
|
|
208
|
-
background="#1a1a2e", # Dark theme default
|
|
209
|
-
show_axes=True,
|
|
210
|
-
show_grid=True,
|
|
211
|
-
axis_labels={"x": "PC1", "y": "PC2", "z": "PC3"},
|
|
212
|
-
show_tooltip=True,
|
|
213
|
-
tooltip_fields=["label", "x", "y", "z", "cluster"],
|
|
214
|
-
selection_mode="click", # "click" or "multi"
|
|
215
|
-
use_instancing=True, # Performance: instanced rendering
|
|
216
|
-
)
|
|
216
|
+
widget.camera_position # Get position [x, y, z]
|
|
217
|
+
widget.camera_target # Get target [x, y, z]
|
|
218
|
+
widget.reset_camera() # Reset to default
|
|
219
|
+
widget.focus_on(["a", "b"]) # Focus on specific points
|
|
217
220
|
```
|
|
218
221
|
|
|
219
222
|
## Distance Metrics
|
|
@@ -232,7 +235,6 @@ Compute distances and visualize similarity relationships between points.
|
|
|
232
235
|
### Color by Distance
|
|
233
236
|
|
|
234
237
|
```python
|
|
235
|
-
# Color points by distance from a reference
|
|
236
238
|
widget.color_by_distance("point_a")
|
|
237
239
|
widget.color_by_distance("point_a", metric="cosine")
|
|
238
240
|
```
|
|
@@ -240,21 +242,16 @@ widget.color_by_distance("point_a", metric="cosine")
|
|
|
240
242
|
### Find Neighbors
|
|
241
243
|
|
|
242
244
|
```python
|
|
243
|
-
# Find k nearest neighbors
|
|
244
245
|
neighbors = widget.find_neighbors("point_a", k=5)
|
|
245
246
|
# Returns: [("point_b", 0.1), ("point_c", 0.2), ...]
|
|
246
247
|
|
|
247
|
-
# Find neighbors within distance threshold
|
|
248
248
|
neighbors = widget.find_neighbors("point_a", threshold=0.5)
|
|
249
249
|
```
|
|
250
250
|
|
|
251
251
|
### Show Connections
|
|
252
252
|
|
|
253
253
|
```python
|
|
254
|
-
# Draw lines to k-nearest neighbors
|
|
255
254
|
widget.show_neighbors("point_a", k=5)
|
|
256
|
-
|
|
257
|
-
# Draw lines to all points within threshold
|
|
258
255
|
widget.show_neighbors("point_a", threshold=0.3)
|
|
259
256
|
|
|
260
257
|
# Manual connection settings
|
|
@@ -271,7 +268,6 @@ widget = VectorSpace(
|
|
|
271
268
|
### Compute Distances
|
|
272
269
|
|
|
273
270
|
```python
|
|
274
|
-
# Get distances from reference to all points
|
|
275
271
|
distances = widget.compute_distances("point_a")
|
|
276
272
|
# Returns: {"point_b": 0.1, "point_c": 0.5, ...}
|
|
277
273
|
|
|
@@ -279,26 +275,57 @@ distances = widget.compute_distances("point_a")
|
|
|
279
275
|
distances = widget.compute_distances(
|
|
280
276
|
"point_a",
|
|
281
277
|
metric="cosine",
|
|
282
|
-
vector_field="embedding"
|
|
278
|
+
vector_field="embedding"
|
|
283
279
|
)
|
|
284
280
|
```
|
|
285
281
|
|
|
282
|
+
## Options
|
|
283
|
+
|
|
284
|
+
```python
|
|
285
|
+
widget = VectorSpace(
|
|
286
|
+
points=data,
|
|
287
|
+
width=1000,
|
|
288
|
+
height=700,
|
|
289
|
+
background="#1a1a2e", # Dark theme default
|
|
290
|
+
show_axes=True,
|
|
291
|
+
show_grid=True,
|
|
292
|
+
axis_labels={"x": "PC1", "y": "PC2", "z": "PC3"},
|
|
293
|
+
show_tooltip=True,
|
|
294
|
+
tooltip_fields=["label", "x", "y", "z", "cluster"],
|
|
295
|
+
selection_mode="click", # "click", "multi", or "box"
|
|
296
|
+
use_instancing=True, # Performance: instanced rendering
|
|
297
|
+
)
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
## Backends
|
|
301
|
+
|
|
302
|
+
Configure a backend for interactive querying:
|
|
303
|
+
|
|
304
|
+
```python
|
|
305
|
+
widget.set_backend("chroma", client=collection)
|
|
306
|
+
widget.set_backend("lancedb", client=table)
|
|
307
|
+
widget.set_backend("grafeo", client=db)
|
|
308
|
+
```
|
|
309
|
+
|
|
286
310
|
## Export
|
|
287
311
|
|
|
288
312
|
```python
|
|
289
|
-
widget.to_json()
|
|
313
|
+
widget.to_json() # Points as JSON string
|
|
314
|
+
widget.to_html() # Self-contained HTML string
|
|
315
|
+
widget.to_html(title="My Vectors") # Custom title
|
|
316
|
+
widget.save_html("vectors.html") # Write HTML to file
|
|
290
317
|
```
|
|
291
318
|
|
|
292
319
|
## Environment Support
|
|
293
320
|
|
|
294
321
|
| Environment | Supported |
|
|
295
322
|
|-------------|-----------|
|
|
296
|
-
| Marimo |
|
|
297
|
-
| JupyterLab |
|
|
298
|
-
| Jupyter Notebook |
|
|
299
|
-
| VS Code |
|
|
300
|
-
| Google Colab |
|
|
301
|
-
| Databricks |
|
|
323
|
+
| Marimo | Yes |
|
|
324
|
+
| JupyterLab | Yes |
|
|
325
|
+
| Jupyter Notebook | Yes |
|
|
326
|
+
| VS Code | Yes |
|
|
327
|
+
| Google Colab | Yes |
|
|
328
|
+
| Databricks | Yes |
|
|
302
329
|
|
|
303
330
|
## Related
|
|
304
331
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "anywidget-vector"
|
|
3
|
-
version = "0.2.
|
|
3
|
+
version = "0.2.5"
|
|
4
4
|
description = "Interactive 3D vector visualization with query UI for vector databases"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
license = "Apache-2.0"
|
|
@@ -28,9 +28,9 @@ dependencies = [
|
|
|
28
28
|
dev = [
|
|
29
29
|
"prek>=0.3.2",
|
|
30
30
|
"pytest>=9.0.2",
|
|
31
|
-
"ruff>=0.15
|
|
32
|
-
"ty>=0.0.
|
|
33
|
-
"marimo>=0.
|
|
31
|
+
"ruff>=0.15",
|
|
32
|
+
"ty>=0.0.20",
|
|
33
|
+
"marimo>=0.20",
|
|
34
34
|
]
|
|
35
35
|
pandas = ["pandas>=2.0"]
|
|
36
36
|
numpy = ["numpy>=1.24"]
|
|
@@ -39,16 +39,16 @@ chroma = ["chromadb>=0.4"]
|
|
|
39
39
|
pinecone = ["pinecone-client>=3.0"]
|
|
40
40
|
weaviate = ["weaviate-client>=4.0"]
|
|
41
41
|
lancedb = ["lancedb>=0.1"]
|
|
42
|
-
grafeo = ["grafeo>=0.5
|
|
42
|
+
grafeo = ["grafeo>=0.5"]
|
|
43
43
|
embed = [] # Marker extra — WASM loads from CDN on demand
|
|
44
44
|
demo = [] # Marker extra — enables demo mode with pre-populated dataset
|
|
45
45
|
all = [
|
|
46
|
-
"pandas>=3
|
|
46
|
+
"pandas>=3",
|
|
47
47
|
"numpy>=2.4",
|
|
48
|
-
"qdrant-client>=1
|
|
48
|
+
"qdrant-client>=1",
|
|
49
49
|
"chromadb>=1.5",
|
|
50
50
|
"pinecone-client>=6.0",
|
|
51
|
-
"weaviate-client>=4.
|
|
51
|
+
"weaviate-client>=4.20",
|
|
52
52
|
"lancedb>=0.29.2",
|
|
53
53
|
]
|
|
54
54
|
|
|
@@ -93,5 +93,5 @@ repos = [
|
|
|
93
93
|
[tool.uv]
|
|
94
94
|
dev-dependencies = [
|
|
95
95
|
"pytest>=9.0.2",
|
|
96
|
-
"ruff>=0.
|
|
96
|
+
"ruff>=0.15",
|
|
97
97
|
]
|
|
@@ -11,4 +11,9 @@ export const ICONS = {
|
|
|
11
11
|
loader: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10" stroke-dasharray="31.4" stroke-dashoffset="10"/></svg>',
|
|
12
12
|
cube: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z"/><polyline points="3.27,6.96 12,12.01 20.73,6.96"/><line x1="12" y1="22.08" x2="12" y2="12"/></svg>',
|
|
13
13
|
reset: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8"/><path d="M3 3v5h5"/></svg>',
|
|
14
|
+
zoomIn: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/><line x1="11" y1="8" x2="11" y2="14"/><line x1="8" y1="11" x2="14" y2="11"/></svg>',
|
|
15
|
+
zoomOut: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/><line x1="8" y1="11" x2="14" y2="11"/></svg>',
|
|
16
|
+
zoomFit: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M15 3h6v6M9 21H3v-6M21 3l-7 7M3 21l7-7"/></svg>',
|
|
17
|
+
cursor: '<svg viewBox="0 0 24 24" fill="currentColor" stroke="none"><path d="M4 2l12 14h-5l-2.3 5.5L6 20.3 8.3 15H4V2z"/></svg>',
|
|
18
|
+
boxSelect: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-dasharray="3 2"><rect x="3" y="3" width="18" height="18" rx="1"/></svg>',
|
|
14
19
|
};
|