anywidget-vector 0.3.2__tar.gz → 0.4.0__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.4.0/.github/workflows/ci.yml +70 -0
- anywidget_vector-0.4.0/.github/workflows/grafeo-latest.yml +72 -0
- {anywidget_vector-0.3.2 → anywidget_vector-0.4.0}/.github/workflows/pypi.yml +20 -11
- anywidget_vector-0.4.0/CHANGELOG.md +191 -0
- {anywidget_vector-0.3.2 → anywidget_vector-0.4.0}/PKG-INFO +129 -13
- {anywidget_vector-0.3.2 → anywidget_vector-0.4.0}/README.md +114 -2
- {anywidget_vector-0.3.2 → anywidget_vector-0.4.0}/pyproject.toml +31 -16
- anywidget_vector-0.4.0/scripts/vendor/build.mjs +40 -0
- anywidget_vector-0.4.0/scripts/vendor/entry.mjs +70 -0
- anywidget_vector-0.4.0/scripts/vendor/package-lock.json +506 -0
- anywidget_vector-0.4.0/scripts/vendor/package.json +15 -0
- anywidget_vector-0.4.0/src/anywidget_vector/__init__.py +13 -0
- anywidget_vector-0.4.0/src/anywidget_vector/backends/grafeo/__init__.py +23 -0
- anywidget_vector-0.4.0/src/anywidget_vector/backends/grafeo/browser.js +64 -0
- anywidget_vector-0.4.0/src/anywidget_vector/backends/grafeo/client.py +53 -0
- anywidget_vector-0.4.0/src/anywidget_vector/backends/grafeo/converter.py +133 -0
- anywidget_vector-0.4.0/src/anywidget_vector/backends/grafeo/embed.js +114 -0
- anywidget_vector-0.4.0/src/anywidget_vector/backends/grafeo/points.js +117 -0
- {anywidget_vector-0.3.2 → anywidget_vector-0.4.0}/src/anywidget_vector/demo.py +1 -1
- {anywidget_vector-0.3.2 → anywidget_vector-0.4.0}/src/anywidget_vector/ui/__init__.py +113 -113
- {anywidget_vector-0.3.2 → anywidget_vector-0.4.0}/src/anywidget_vector/ui/canvas.js +21 -8
- {anywidget_vector-0.3.2 → anywidget_vector-0.4.0}/src/anywidget_vector/ui/properties.js +9 -4
- {anywidget_vector-0.3.2 → anywidget_vector-0.4.0}/src/anywidget_vector/ui/sidebar.js +9 -4
- {anywidget_vector-0.3.2 → anywidget_vector-0.4.0}/src/anywidget_vector/ui/styles.css +8 -2
- anywidget_vector-0.4.0/src/anywidget_vector/ui/theme.js +126 -0
- anywidget_vector-0.4.0/src/anywidget_vector/ui/vendor/three.LICENSES.txt +25 -0
- anywidget_vector-0.4.0/src/anywidget_vector/ui/vendor/three.min.js +4220 -0
- {anywidget_vector-0.3.2 → anywidget_vector-0.4.0}/src/anywidget_vector/widget.py +232 -49
- anywidget_vector-0.4.0/tests/conftest.py +20 -0
- anywidget_vector-0.4.0/tests/js/wasm_smoke.mjs +111 -0
- anywidget_vector-0.4.0/tests/support.py +31 -0
- anywidget_vector-0.4.0/tests/test_grafeo_backend.py +202 -0
- anywidget_vector-0.4.0/tests/test_grafeo_contract.py +383 -0
- anywidget_vector-0.4.0/tests/test_theme.py +328 -0
- anywidget_vector-0.4.0/tests/test_ui_bundle.py +459 -0
- {anywidget_vector-0.3.2 → anywidget_vector-0.4.0}/tests/test_widget.py +20 -2
- anywidget_vector-0.4.0/tests/test_widget_robustness.py +309 -0
- anywidget_vector-0.4.0/uv.lock +4226 -0
- anywidget_vector-0.3.2/.github/workflows/ci.yml +0 -71
- anywidget_vector-0.3.2/CHANGELOG.md +0 -145
- anywidget_vector-0.3.2/src/anywidget_vector/__init__.py +0 -6
- anywidget_vector-0.3.2/src/anywidget_vector/backends/grafeo/__init__.py +0 -20
- anywidget_vector-0.3.2/src/anywidget_vector/backends/grafeo/browser.js +0 -90
- anywidget_vector-0.3.2/src/anywidget_vector/backends/grafeo/client.py +0 -33
- anywidget_vector-0.3.2/src/anywidget_vector/backends/grafeo/converter.py +0 -46
- anywidget_vector-0.3.2/src/anywidget_vector/backends/grafeo/embed.js +0 -95
- anywidget_vector-0.3.2/uv.lock +0 -3122
- {anywidget_vector-0.3.2 → anywidget_vector-0.4.0}/.gitignore +0 -0
- {anywidget_vector-0.3.2 → anywidget_vector-0.4.0}/.python-version +0 -0
- {anywidget_vector-0.3.2 → anywidget_vector-0.4.0}/LICENSE +0 -0
- {anywidget_vector-0.3.2 → anywidget_vector-0.4.0}/assets/demo.png +0 -0
- {anywidget_vector-0.3.2 → anywidget_vector-0.4.0}/examples/demo.py +0 -0
- {anywidget_vector-0.3.2 → anywidget_vector-0.4.0}/examples/fashion-mnist-parallel-coords-6d.py +0 -0
- {anywidget_vector-0.3.2 → anywidget_vector-0.4.0}/examples/test_add_numpy.py +0 -0
- {anywidget_vector-0.3.2 → anywidget_vector-0.4.0}/examples/test_projection.py +0 -0
- {anywidget_vector-0.3.2 → anywidget_vector-0.4.0}/src/anywidget_vector/backends/__init__.py +0 -0
- {anywidget_vector-0.3.2 → anywidget_vector-0.4.0}/src/anywidget_vector/backends/chroma/__init__.py +0 -0
- {anywidget_vector-0.3.2 → anywidget_vector-0.4.0}/src/anywidget_vector/backends/chroma/client.py +0 -0
- {anywidget_vector-0.3.2 → anywidget_vector-0.4.0}/src/anywidget_vector/backends/chroma/converter.py +0 -0
- {anywidget_vector-0.3.2 → anywidget_vector-0.4.0}/src/anywidget_vector/backends/lancedb/__init__.py +0 -0
- {anywidget_vector-0.3.2 → anywidget_vector-0.4.0}/src/anywidget_vector/backends/lancedb/client.py +0 -0
- {anywidget_vector-0.3.2 → anywidget_vector-0.4.0}/src/anywidget_vector/backends/lancedb/converter.py +0 -0
- {anywidget_vector-0.3.2 → anywidget_vector-0.4.0}/src/anywidget_vector/backends/pinecone/__init__.py +0 -0
- {anywidget_vector-0.3.2 → anywidget_vector-0.4.0}/src/anywidget_vector/backends/pinecone/client.js +0 -0
- {anywidget_vector-0.3.2 → anywidget_vector-0.4.0}/src/anywidget_vector/backends/pinecone/converter.py +0 -0
- {anywidget_vector-0.3.2 → anywidget_vector-0.4.0}/src/anywidget_vector/backends/qdrant/__init__.py +0 -0
- {anywidget_vector-0.3.2 → anywidget_vector-0.4.0}/src/anywidget_vector/backends/qdrant/client.js +0 -0
- {anywidget_vector-0.3.2 → anywidget_vector-0.4.0}/src/anywidget_vector/backends/qdrant/converter.py +0 -0
- {anywidget_vector-0.3.2 → anywidget_vector-0.4.0}/src/anywidget_vector/backends/weaviate/__init__.py +0 -0
- {anywidget_vector-0.3.2 → anywidget_vector-0.4.0}/src/anywidget_vector/backends/weaviate/client.js +0 -0
- {anywidget_vector-0.3.2 → anywidget_vector-0.4.0}/src/anywidget_vector/backends/weaviate/converter.py +0 -0
- {anywidget_vector-0.3.2 → anywidget_vector-0.4.0}/src/anywidget_vector/py.typed +0 -0
- {anywidget_vector-0.3.2 → anywidget_vector-0.4.0}/src/anywidget_vector/static/icons.js +0 -0
- {anywidget_vector-0.3.2 → anywidget_vector-0.4.0}/src/anywidget_vector/ui/constants.js +0 -0
- {anywidget_vector-0.3.2 → anywidget_vector-0.4.0}/src/anywidget_vector/ui/settings.js +0 -0
- {anywidget_vector-0.3.2 → anywidget_vector-0.4.0}/src/anywidget_vector/ui/toolbar.js +0 -0
- {anywidget_vector-0.3.2 → anywidget_vector-0.4.0}/tests/__init__.py +0 -0
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main, "release/**", "support/**"]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
# The release workflow runs the full suite before it publishes
|
|
9
|
+
workflow_call:
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
lint:
|
|
13
|
+
name: Lint
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
steps:
|
|
16
|
+
- uses: actions/checkout@v7
|
|
17
|
+
|
|
18
|
+
- name: Install uv
|
|
19
|
+
uses: astral-sh/setup-uv@68559e99cc807c1eb7e9238fd43a15bba460eec2 # v10.3.3
|
|
20
|
+
|
|
21
|
+
- name: Check that uv.lock matches pyproject.toml
|
|
22
|
+
run: uv lock --check
|
|
23
|
+
|
|
24
|
+
- name: Run ruff check
|
|
25
|
+
run: uv run --locked --only-group dev ruff check .
|
|
26
|
+
|
|
27
|
+
- name: Run ruff format check
|
|
28
|
+
run: uv run --locked --only-group dev ruff format --check .
|
|
29
|
+
|
|
30
|
+
test:
|
|
31
|
+
name: Test (Python ${{ matrix.python-version }})
|
|
32
|
+
runs-on: ubuntu-latest
|
|
33
|
+
strategy:
|
|
34
|
+
matrix:
|
|
35
|
+
python-version: ["3.12", "3.13", "3.14", "3.15"]
|
|
36
|
+
steps:
|
|
37
|
+
- uses: actions/checkout@v7
|
|
38
|
+
|
|
39
|
+
# Sets UV_PYTHON, so uv uses this version instead of .python-version
|
|
40
|
+
- name: Install uv and Python ${{ matrix.python-version }}
|
|
41
|
+
uses: astral-sh/setup-uv@68559e99cc807c1eb7e9238fd43a15bba460eec2 # v10.3.3
|
|
42
|
+
with:
|
|
43
|
+
python-version: ${{ matrix.python-version }}
|
|
44
|
+
|
|
45
|
+
# The ESM bundle tests parse and run the widget's JavaScript with Node
|
|
46
|
+
- name: Set up Node.js
|
|
47
|
+
uses: actions/setup-node@v7
|
|
48
|
+
with:
|
|
49
|
+
node-version: "22"
|
|
50
|
+
|
|
51
|
+
- name: Install dependencies
|
|
52
|
+
run: uv sync --locked --extra dev
|
|
53
|
+
|
|
54
|
+
- name: Run tests
|
|
55
|
+
run: uv run --locked --extra dev pytest
|
|
56
|
+
|
|
57
|
+
build:
|
|
58
|
+
name: Build
|
|
59
|
+
runs-on: ubuntu-latest
|
|
60
|
+
steps:
|
|
61
|
+
- uses: actions/checkout@v7
|
|
62
|
+
|
|
63
|
+
- name: Install uv
|
|
64
|
+
uses: astral-sh/setup-uv@68559e99cc807c1eb7e9238fd43a15bba460eec2 # v10.3.3
|
|
65
|
+
|
|
66
|
+
- name: Build package
|
|
67
|
+
run: uv build
|
|
68
|
+
|
|
69
|
+
- name: Check package
|
|
70
|
+
run: uvx twine check dist/*
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
name: Grafeo Latest
|
|
2
|
+
|
|
3
|
+
# Early warning for engine changes: runs the suite against the newest grafeo on
|
|
4
|
+
# PyPI (pre-releases included, even outside the pinned range) and the browser
|
|
5
|
+
# backend against the pinned and the newest @grafeo-db/wasm on npm.
|
|
6
|
+
|
|
7
|
+
on:
|
|
8
|
+
schedule:
|
|
9
|
+
- cron: "0 6 * * 1" # Mondays 06:00 UTC
|
|
10
|
+
workflow_dispatch:
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
python:
|
|
14
|
+
name: Test with newest grafeo (Python ${{ matrix.python-version }})
|
|
15
|
+
runs-on: ubuntu-latest
|
|
16
|
+
strategy:
|
|
17
|
+
fail-fast: false
|
|
18
|
+
matrix:
|
|
19
|
+
python-version: ["3.12", "3.13", "3.14", "3.15"]
|
|
20
|
+
steps:
|
|
21
|
+
- uses: actions/checkout@v7
|
|
22
|
+
|
|
23
|
+
- name: Install uv and Python ${{ matrix.python-version }}
|
|
24
|
+
uses: astral-sh/setup-uv@68559e99cc807c1eb7e9238fd43a15bba460eec2 # v10.3.3
|
|
25
|
+
with:
|
|
26
|
+
python-version: ${{ matrix.python-version }}
|
|
27
|
+
|
|
28
|
+
- name: Install dependencies
|
|
29
|
+
run: |
|
|
30
|
+
uv sync --extra dev
|
|
31
|
+
uv pip install --upgrade --prerelease allow grafeo
|
|
32
|
+
|
|
33
|
+
- name: Show grafeo build
|
|
34
|
+
run: uv run --no-sync python -c "import grafeo; print(grafeo.__version__); print(grafeo.build_info())"
|
|
35
|
+
|
|
36
|
+
- name: Run tests
|
|
37
|
+
run: uv run --no-sync pytest
|
|
38
|
+
|
|
39
|
+
wasm:
|
|
40
|
+
name: WASM smoke test (${{ matrix.release }} @grafeo-db/wasm)
|
|
41
|
+
runs-on: ubuntu-latest
|
|
42
|
+
strategy:
|
|
43
|
+
fail-fast: false
|
|
44
|
+
matrix:
|
|
45
|
+
release: [pinned, newest]
|
|
46
|
+
steps:
|
|
47
|
+
- uses: actions/checkout@v7
|
|
48
|
+
|
|
49
|
+
- name: Set up Node.js
|
|
50
|
+
uses: actions/setup-node@v7
|
|
51
|
+
with:
|
|
52
|
+
node-version: "22"
|
|
53
|
+
|
|
54
|
+
- name: Resolve version
|
|
55
|
+
id: version
|
|
56
|
+
run: |
|
|
57
|
+
if [ "${{ matrix.release }}" = "pinned" ]; then
|
|
58
|
+
version=$(sed -n 's/^export const GRAFEO_WASM_VERSION = "\(.*\)";$/\1/p' src/anywidget_vector/backends/grafeo/embed.js)
|
|
59
|
+
else
|
|
60
|
+
version=$(npm view @grafeo-db/wasm versions --json | node -e 'const v = JSON.parse(require("fs").readFileSync(0, "utf8")); console.log([].concat(v).pop())')
|
|
61
|
+
fi
|
|
62
|
+
echo "version=$version" >> "$GITHUB_OUTPUT"
|
|
63
|
+
|
|
64
|
+
- name: Download @grafeo-db/wasm@${{ steps.version.outputs.version }}
|
|
65
|
+
run: |
|
|
66
|
+
mkdir -p "$RUNNER_TEMP/wasm"
|
|
67
|
+
cd "$RUNNER_TEMP/wasm"
|
|
68
|
+
npm pack "@grafeo-db/wasm@${{ steps.version.outputs.version }}"
|
|
69
|
+
tar -xzf grafeo-db-wasm-*.tgz
|
|
70
|
+
|
|
71
|
+
- name: Run smoke test
|
|
72
|
+
run: node tests/js/wasm_smoke.mjs "$RUNNER_TEMP/wasm/package"
|
|
@@ -15,25 +15,34 @@ on:
|
|
|
15
15
|
- pypi
|
|
16
16
|
|
|
17
17
|
jobs:
|
|
18
|
+
test:
|
|
19
|
+
name: Test
|
|
20
|
+
uses: ./.github/workflows/ci.yml
|
|
21
|
+
|
|
18
22
|
build:
|
|
19
23
|
name: Build distribution
|
|
24
|
+
needs: test
|
|
20
25
|
runs-on: ubuntu-latest
|
|
21
26
|
steps:
|
|
22
|
-
- uses: actions/checkout@
|
|
27
|
+
- uses: actions/checkout@v7
|
|
23
28
|
|
|
24
|
-
- name:
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
29
|
+
- name: Check the release tag matches the package version
|
|
30
|
+
if: github.event_name == 'release'
|
|
31
|
+
run: |
|
|
32
|
+
version=$(python3 -c "import tomllib; print(tomllib.load(open('pyproject.toml', 'rb'))['project']['version'])")
|
|
33
|
+
if [ "$GITHUB_REF_NAME" != "v$version" ]; then
|
|
34
|
+
echo "Release tag $GITHUB_REF_NAME does not match the package version $version"
|
|
35
|
+
exit 1
|
|
36
|
+
fi
|
|
28
37
|
|
|
29
|
-
- name: Install
|
|
30
|
-
|
|
38
|
+
- name: Install uv
|
|
39
|
+
uses: astral-sh/setup-uv@68559e99cc807c1eb7e9238fd43a15bba460eec2 # v10.3.3
|
|
31
40
|
|
|
32
41
|
- name: Build package
|
|
33
|
-
run:
|
|
42
|
+
run: uv build
|
|
34
43
|
|
|
35
44
|
- name: Upload distribution artifacts
|
|
36
|
-
uses: actions/upload-artifact@
|
|
45
|
+
uses: actions/upload-artifact@v7
|
|
37
46
|
with:
|
|
38
47
|
name: dist
|
|
39
48
|
path: dist/
|
|
@@ -48,7 +57,7 @@ jobs:
|
|
|
48
57
|
id-token: write
|
|
49
58
|
steps:
|
|
50
59
|
- name: Download distribution artifacts
|
|
51
|
-
uses: actions/download-artifact@
|
|
60
|
+
uses: actions/download-artifact@v8
|
|
52
61
|
with:
|
|
53
62
|
name: dist
|
|
54
63
|
path: dist/
|
|
@@ -68,7 +77,7 @@ jobs:
|
|
|
68
77
|
id-token: write
|
|
69
78
|
steps:
|
|
70
79
|
- name: Download distribution artifacts
|
|
71
|
-
uses: actions/download-artifact@
|
|
80
|
+
uses: actions/download-artifact@v8
|
|
72
81
|
with:
|
|
73
82
|
name: dist
|
|
74
83
|
path: dist/
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.4.0 (2026-10-28)
|
|
4
|
+
|
|
5
|
+
Requires Python 3.12 or later; the Grafeo backend requires grafeo 0.6. See "Upgrading to 0.4" in the README.
|
|
6
|
+
|
|
7
|
+
### Breaking
|
|
8
|
+
|
|
9
|
+
- **Grafeo 0.6**: The `grafeo` extra requires `grafeo>=0.6.0,<0.7`; grafeo 0.5.x is no longer supported. Grafeo 0.6 changes query results and files, and these reach the widget's Grafeo backend:
|
|
10
|
+
- Every database is a single file. The first read-write open of a 0.5.x database migrates it and keeps the old file as `<file>.pre-0.6`, which 0.5.x needs to go back; opening a directory that is not a 0.5.x database fails
|
|
11
|
+
- A GQL number with a point is an exact decimal, so `0.0/0.0` and `1/0` fail the query (division by zero) where they gave NaN or null, and so does integer overflow. Use exponent literals (`0.0e0/0.0e0`) for IEEE floats
|
|
12
|
+
- A `WHERE` right after `INSERT`, `CREATE`, `MERGE` or `DELETE` is an error, and an `INSERT` alone returns no rows, so running one from the toolbar clears the scene
|
|
13
|
+
- GQL `ORDER BY` puts nulls last in both directions
|
|
14
|
+
- **Theme follows the page until you choose**: `dark_mode` reports the theme in use. The widget follows the host page until a theme is chosen (`VectorSpace(dark_mode=...)`, `widget.dark_mode = ...` before or after display, even to the value it already reports, or the settings toggle) and then keeps the choice, also in later views; before, the page theme overwrote `dark_mode` passed from Python, and the widget stopped following the page after its first automatic change. The canvas `background` follows the theme unless chosen the same way; before, the theme overwrote it. Same contract as anywidget-graph and anywidget-archimate (`_theme_explicit`, `_background_explicit`)
|
|
15
|
+
- **Compact toolbar in a narrow widget**: The toolbar tightens when the widget itself is narrower than 600 px (a container query), not only when the window is narrow, as in anywidget-graph. Panels over the canvas (window narrower than 768 px) now cover the canvas's zoom and selection controls instead of sitting under them
|
|
16
|
+
- **WASM engine 0.6**: The browser-side Grafeo backend loads `@grafeo-db/wasm` 0.6.0 (was 0.5.0 in 0.3.2) from jsDelivr. The version is set once, `GRAFEO_WASM_VERSION` in `backends/grafeo/embed.js`, and a test keeps it in lockstep with the Python pin (npm and PyPI spellings of a pre-release, such as `0.6.1-rc.2` and `0.6.1rc2`, compare as the same version)
|
|
17
|
+
|
|
18
|
+
### Improvements
|
|
19
|
+
|
|
20
|
+
- **Decimals become numbers**: Grafeo 0.6 returns decimals (`decimal.Decimal` in Python, `{"$decimal": "1.50"}` in WASM). The widget turns them into floats in every Grafeo mode, also inside lists, maps and node properties, so `RETURN 0.5 AS score` maps to color and size, `1.5 AS x` places a point, and a plain list `[1.0, 0.0, 0.0]` still gives a vector. Without this, Python points could not be sent to the browser as JSON and WASM points landed at the origin
|
|
21
|
+
- **Vector search errors**: A query vector of the wrong size or with NaN is a regular `grafeo.GrafeoError` in Grafeo 0.6 (0.5.44 panicked, and its WASM build trapped), shown in the widget with the sizes it names. The panic guard stays for any other engine bug
|
|
22
|
+
- **Three.js 0.186.1, bundled**: The widget and `to_html()` use Three.js 0.186.1 (was 0.160.0 from esm.sh), bundled with the package (`ui/vendor/three.min.js` with its license, built by `scripts/vendor`), so both work offline and under a strict Content Security Policy. Only the `wasm` Grafeo mode loads code from a CDN. Three.js dropped WebGL 1 in 0.163, so a browser needs WebGL 2
|
|
23
|
+
- **Theme detection**: A `data-theme="dark"` or `"light"` on the widget's closest ancestor wins, then on `<html>` and `<body>`, then a `dark` or `light` class, then the operating system. `data-theme="light"` no longer loses to a dark operating system, and other `data-theme` values (design-system names) are ignored
|
|
24
|
+
- **Release safety**: The PyPI workflow runs the full CI suite first and stops when the release tag is not `v` plus the `pyproject.toml` version. CI also runs on `release/**` and `support/**` branches
|
|
25
|
+
- **Credentials documented**: The README says where backend credentials end up (the browser and saved notebook widget state) and how to limit that
|
|
26
|
+
- **Dependencies**: Requires anywidget 0.11 or later (was 0.9.21). The `chroma` and `all` extras pin `chromadb==1.5.8`, because 1.5.9 has security issues. All locked dependencies refreshed (`uv lock --upgrade`), and the dev tools need current releases (pytest 9.2, ruff 0.17.3, ty 0.0.94, prek 0.5.7, marimo 0.25.2); the `dev` extra includes grafeo, numpy and packaging so the full test suite runs everywhere. CI and the release workflow use uv (`uv lock --check`, `uv sync --locked`, `uv build`) and current GitHub Actions (checkout v7, setup-uv v10.3.3 pinned by commit since setup-uv publishes no moving major tag, setup-node v7, upload-artifact v7, download-artifact v8). The `tool.uv.dev-dependencies` table moved to `[dependency-groups]`, and ruff leaves Markdown files alone
|
|
27
|
+
- **Engine contract tests**: The tests that pin Grafeo behavior now cover 0.6: error classes and messages for unknown metrics, zero dimensions, wrong-size and NaN query vectors and NaN in an indexed vector, filter operators (`$in`, `$ne`), tied distances, decimal literals and an `INSERT` without rows. `tests/js/wasm_smoke.mjs` checks decimals and the wrong-size error in WASM
|
|
28
|
+
- **Same points in every Grafeo mode**: Embedded, server and WASM results go through the same rules: node values (`RETURN n`) contribute their properties, labels and id, unaliased columns such as `n.embedding` or `id(n)` are recognized, and explicit `x`/`y`/`z` win over the first vector components
|
|
29
|
+
- **Server errors**: grafeo-server error responses show their `detail` text instead of raw JSON
|
|
30
|
+
- **Scheduled engine check**: A weekly workflow runs the suite against the newest grafeo on PyPI (pre-releases included) and a smoke test against the pinned and the newest `@grafeo-db/wasm`
|
|
31
|
+
- **Python 3.15**: Tested on Python 3.15; CI runs the suite on 3.12 to 3.15 and the classifiers list 3.12 to 3.15
|
|
32
|
+
|
|
33
|
+
### Bug Fixes
|
|
34
|
+
|
|
35
|
+
- **Embedded Grafeo queries**: Queries failed with "'QueryBuilder' object is not iterable" because the client called `GrafeoDB.query()`, which returns a query builder. It now calls `execute()`
|
|
36
|
+
- **WASM mode**: `@grafeo-db/wasm` is published for bundlers since 0.5.x, so importing it from esm.sh no longer yields a working `Database`. The loader now imports the JS glue and instantiates the binary itself. WASM vectors (`Float32Array`) are converted to arrays, so they place points and sync to Python
|
|
37
|
+
- **Engine panics**: A Grafeo panic (for example a vector search with the wrong number of dimensions) escaped the query callback because pyo3 raises it as a `BaseException`. It is now reported as a query error
|
|
38
|
+
- **Query status**: A Python-side query with an empty result left the status at "connecting" and kept the old points. The result now replaces the points and the status becomes "connected"; a new query clears the previous error
|
|
39
|
+
- **NaN and infinity in points**: These values are not valid JSON and one NaN coordinate broke camera framing for the whole scene. Top-level non-finite values are now replaced with `None` (with a `RuntimeWarning`), and distance and focus methods treat `None` coordinates as 0
|
|
40
|
+
- **HTML injection**: Point labels and values from a database were inserted as HTML in the tooltip, the properties panel and the exported HTML page. They are now set as text. `to_html()` also escapes the title and keeps a `</script>` inside the data from ending the script
|
|
41
|
+
- **Vector edge cases**: `add_numpy()` with a single high-dimensional row, a 1-D or one-column array, or ids/labels/metadata of the wrong length raised an unrelated `IndexError`; it now works (single row) or raises a clear `ValueError`. `project()` handles a single point and reports ragged or non-finite vectors clearly. `compute_distances(vector_field=...)` leaves out points without that vector instead of returning infinity, and raises on vectors of different lengths instead of truncating them
|
|
42
|
+
- **Version**: `anywidget_vector.__version__` reported 0.2.5; it now reads the installed package version
|
|
43
|
+
- **Removed views kept running**: A removed or re-rendered widget kept its model listeners, its theme observers and its dark-mode media listener, so old views went on updating `dark_mode` and `background`. Removing a view now detaches all of them
|
|
44
|
+
- **WASM engine loaded twice**: Two copies of the widget module on one page (a cell run again, a marimo reconnect, anywidget-graph next to it) each instantiated the cached `@grafeo-db/wasm` glue, which broke the databases of the first copy. The loading promise now lives on `globalThis`, keyed by the glue URL
|
|
45
|
+
- **Stale query results**: A slower, older browser-side query could overwrite the result of a newer one. Only the newest query per widget now sets points, errors and the loading state
|
|
46
|
+
- **HTML export sizes**: `to_html(width=..., height=...)` placed the values in the page's `<style>` unchecked; a value that is not a plain CSS size now raises `ValueError`
|
|
47
|
+
- **Source distribution**: A local `uv build` packed the `.claude/` folder (agent notes and local settings) into the sdist; it is now excluded
|
|
48
|
+
|
|
49
|
+
## 0.3.2 (2026-03-16)
|
|
50
|
+
|
|
51
|
+
### Improvements
|
|
52
|
+
|
|
53
|
+
- **Marimo reactivity fix**: Removed camera and hover JS-to-Python sync to prevent continuous cell re-execution. Only user-initiated actions (selection, mode change) now trigger marimo reactive updates
|
|
54
|
+
- **Custom scroll zoom**: Replaced OrbitControls zoom with a custom wheel handler for much finer granularity
|
|
55
|
+
- **Selection hides completely**: Lasso/box selection now fully hides non-selected points (scale-to-zero for instanced meshes) instead of dimming
|
|
56
|
+
- **Auto zoom-to-fit on selection**: Camera automatically frames the selected points after lasso/box selection
|
|
57
|
+
- **Search filter modes**: Typing in the search bar dims non-matching points as a preview, pressing Run/Enter hides them completely
|
|
58
|
+
- **Hover via callback**: Properties panel hover now uses a direct JS callback instead of model sync, eliminating unnecessary Python round-trips
|
|
59
|
+
|
|
60
|
+
### Bug Fixes
|
|
61
|
+
|
|
62
|
+
- **setSelection scoping**: Moved `setSelection` helper to `createCanvas` scope so lasso/box/click handlers can access it
|
|
63
|
+
- **Camera debounce variable**: Fixed `_cameraDebounce` lexical declaration error by moving it to the correct scope
|
|
64
|
+
|
|
65
|
+
## 0.3.1 (2026-03-16)
|
|
66
|
+
|
|
67
|
+
### New Features
|
|
68
|
+
|
|
69
|
+
- **Lasso selection**: New lasso mode for freehand point selection in the 3D canvas, with point-in-polygon hit testing
|
|
70
|
+
- **Selection highlighting**: Selected points show wireframe highlight rings and non-selected points are dimmed to 15% brightness
|
|
71
|
+
- **Auto-sizing**: Width defaults to 100% (fill container), height defaults to 1:1 aspect ratio. Both can still be set to fixed pixel values
|
|
72
|
+
|
|
73
|
+
### Bug Fixes
|
|
74
|
+
|
|
75
|
+
- **Properties panel**: Panel is now always created (previously skipped when `show_properties=False`), so the toolbar button always works. Starts closed unless `show_properties=True`
|
|
76
|
+
- **Distance metric feedback**: Changing the metric now auto-enables k=5 connections when a point is selected, giving immediate visual feedback
|
|
77
|
+
|
|
78
|
+
### Improvements
|
|
79
|
+
|
|
80
|
+
- Reduced scroll zoom sensitivity (`zoomSpeed` halved to 0.5)
|
|
81
|
+
- Search filter dimming increased from 12% to 6% opacity for clearer visual contrast
|
|
82
|
+
- Camera no longer resets on every point update (only on initial load)
|
|
83
|
+
- Cross-widget filtering: example updated so VectorSpace lasso selection feeds back into ParallelCoordinates dimming via marimo reactivity
|
|
84
|
+
|
|
85
|
+
## 0.3.0 (2026-03-16)
|
|
86
|
+
|
|
87
|
+
### New Features
|
|
88
|
+
|
|
89
|
+
- **Distance metrics sidebar**: Distance section with metric selector (euclidean, cosine, manhattan, dot product), configurable k-neighbors (0-50) and live nearest-neighbor display for the selected point
|
|
90
|
+
- **Dimension mapping display**: Sidebar now shows active visual mapping fields: color field, size range, shape field and unique shape count
|
|
91
|
+
|
|
92
|
+
### Improvements
|
|
93
|
+
|
|
94
|
+
- Improved sidebar styling and layout
|
|
95
|
+
|
|
96
|
+
## 0.2.8 (2026-03-15)
|
|
97
|
+
|
|
98
|
+
### New Features
|
|
99
|
+
|
|
100
|
+
- **6D parallel coordinates example**: Fashion-MNIST demo with PCA across 6+ dimensions, interactive axis mapping and shape mapping to categorical labels
|
|
101
|
+
|
|
102
|
+
## 0.2.7 (2026-03-15)
|
|
103
|
+
|
|
104
|
+
### New Features
|
|
105
|
+
|
|
106
|
+
- **Dark/light mode toggle**: `dark_mode` trait with real-time CSS color scheme switching and theme-aware styling across all panels
|
|
107
|
+
|
|
108
|
+
## 0.2.6 (2026-03-15)
|
|
109
|
+
|
|
110
|
+
### New Features
|
|
111
|
+
|
|
112
|
+
- **NumPy array support**: `add_numpy()` method for adding points from arrays with automatic PCA projection for high-dimensional data (D > 3)
|
|
113
|
+
- **Dimensionality reduction**: `project()` method with PCA, t-SNE and UMAP support; `set_vectors()` for storing high-dimensional vectors separately
|
|
114
|
+
- **Example scripts**: Projection demo and numpy integration examples
|
|
115
|
+
|
|
116
|
+
### Improvements
|
|
117
|
+
|
|
118
|
+
- High-dimensional vector storage without syncing to JavaScript
|
|
119
|
+
- Coordinate normalization after projection
|
|
120
|
+
- Added demo screenshot to README
|
|
121
|
+
|
|
122
|
+
## 0.2.5 (2026-03-04)
|
|
123
|
+
|
|
124
|
+
### Bug Fixes
|
|
125
|
+
|
|
126
|
+
- Fixed lasso selection stability issues
|
|
127
|
+
- Removed problematic custom traitlets implementation
|
|
128
|
+
|
|
129
|
+
### Improvements
|
|
130
|
+
|
|
131
|
+
- Added keyboard shortcuts: F to fit view, Escape to clear selection
|
|
132
|
+
- Better visual feedback for selection modes
|
|
133
|
+
- Cleaner toolbar layout with integrated mode controls
|
|
134
|
+
|
|
135
|
+
## 0.2.4 (2026-03-02)
|
|
136
|
+
|
|
137
|
+
### New Features
|
|
138
|
+
|
|
139
|
+
- **Zoom and pan controls**: Zoom in, zoom out and fit-to-view buttons in the toolbar
|
|
140
|
+
- **Box selection mode**: New selection mode alongside click and multi-select, with visual feedback during selection
|
|
141
|
+
- **HTML export**: `to_html()` and `save_html()` methods for self-contained HTML output with embedded data and Three.js
|
|
142
|
+
|
|
143
|
+
### Improvements
|
|
144
|
+
|
|
145
|
+
- Improved camera fitting algorithm for better initial view framing
|
|
146
|
+
- Updated README with comprehensive usage examples
|
|
147
|
+
- Updated dependencies
|
|
148
|
+
|
|
149
|
+
## 0.2.3 (2026-02-12)
|
|
150
|
+
|
|
151
|
+
### New Features
|
|
152
|
+
|
|
153
|
+
- **Sidebar explorer**: Three collapsible sections: collections browser, dimensions explorer (point count, dimensionality, axis ranges) and clusters explorer (grouped by color field with sizes)
|
|
154
|
+
- **Browser-side Grafeo backend**: JavaScript client for Grafeo server and WASM-embedded queries
|
|
155
|
+
- **Demo module**: Reference implementation showing various widget features
|
|
156
|
+
|
|
157
|
+
### Improvements
|
|
158
|
+
|
|
159
|
+
- Consistency pass across all backend modules
|
|
160
|
+
- Ruff configuration tuned for marimo compatibility
|
|
161
|
+
|
|
162
|
+
## 0.2.2 (2026-02-07)
|
|
163
|
+
|
|
164
|
+
### New Features
|
|
165
|
+
|
|
166
|
+
- **Streaming factory methods**: `from_numpy()`, `from_umap()` and `from_arrays()` constructors for various data formats
|
|
167
|
+
|
|
168
|
+
### Improvements
|
|
169
|
+
|
|
170
|
+
- Added Apache 2.0 license
|
|
171
|
+
- Expanded test suite with 194 additional test cases
|
|
172
|
+
- ESM bundle aggregation for widget JavaScript
|
|
173
|
+
|
|
174
|
+
## 0.2.1 (2026-02-03)
|
|
175
|
+
|
|
176
|
+
### New Features
|
|
177
|
+
|
|
178
|
+
- **Multi-backend architecture**: Six backends: Qdrant, Pinecone, Weaviate (browser-side REST), Chroma, LanceDB, Grafeo (Python-side)
|
|
179
|
+
- **Modular UI**: Separated rendering into canvas, settings, properties and toolbar components
|
|
180
|
+
- **Backend factory methods**: `from_qdrant()`, `from_pinecone()`, `from_weaviate()`, `from_chroma()`, `from_lancedb()`, `from_grafeo()`
|
|
181
|
+
- **Event system**: `on_click()`, `on_hover()` and `on_selection()` decorators with callback signatures
|
|
182
|
+
- **CI/CD**: GitHub Actions pipelines for testing and PyPI publishing
|
|
183
|
+
|
|
184
|
+
### Improvements
|
|
185
|
+
|
|
186
|
+
- Refactored monolithic widget into modular component architecture
|
|
187
|
+
- Added README with usage examples
|
|
188
|
+
|
|
189
|
+
## 0.1.0 (2026-02-03)
|
|
190
|
+
|
|
191
|
+
- Initial release: Three.js-based interactive 3D vector visualization with instanced rendering, six shape types, continuous and categorical color mapping, orbit controls, hover tooltips, axes/grid display and raycast-based selection
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
2
|
Name: anywidget-vector
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
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
|
|
@@ -17,11 +17,12 @@ Classifier: Programming Language :: Python :: 3
|
|
|
17
17
|
Classifier: Programming Language :: Python :: 3.12
|
|
18
18
|
Classifier: Programming Language :: Python :: 3.13
|
|
19
19
|
Classifier: Programming Language :: Python :: 3.14
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.15
|
|
20
21
|
Classifier: Topic :: Scientific/Engineering :: Visualization
|
|
21
22
|
Requires-Python: >=3.12
|
|
22
|
-
Requires-Dist: anywidget>=0.
|
|
23
|
+
Requires-Dist: anywidget>=0.11.0
|
|
23
24
|
Provides-Extra: all
|
|
24
|
-
Requires-Dist: chromadb
|
|
25
|
+
Requires-Dist: chromadb==1.5.8; extra == 'all'
|
|
25
26
|
Requires-Dist: lancedb>=0.29.2; extra == 'all'
|
|
26
27
|
Requires-Dist: numpy>=2.4; extra == 'all'
|
|
27
28
|
Requires-Dist: pandas>=3; extra == 'all'
|
|
@@ -29,17 +30,20 @@ Requires-Dist: pinecone-client>=6.0; extra == 'all'
|
|
|
29
30
|
Requires-Dist: qdrant-client>=1; extra == 'all'
|
|
30
31
|
Requires-Dist: weaviate-client>=4.20; extra == 'all'
|
|
31
32
|
Provides-Extra: chroma
|
|
32
|
-
Requires-Dist: chromadb
|
|
33
|
+
Requires-Dist: chromadb==1.5.8; extra == 'chroma'
|
|
33
34
|
Provides-Extra: demo
|
|
34
35
|
Provides-Extra: dev
|
|
35
|
-
Requires-Dist:
|
|
36
|
-
Requires-Dist:
|
|
37
|
-
Requires-Dist:
|
|
38
|
-
Requires-Dist:
|
|
39
|
-
Requires-Dist:
|
|
36
|
+
Requires-Dist: grafeo<0.7,>=0.6.0; extra == 'dev'
|
|
37
|
+
Requires-Dist: marimo>=0.25.2; extra == 'dev'
|
|
38
|
+
Requires-Dist: numpy>=1.24; extra == 'dev'
|
|
39
|
+
Requires-Dist: packaging>=24; extra == 'dev'
|
|
40
|
+
Requires-Dist: prek>=0.5.7; extra == 'dev'
|
|
41
|
+
Requires-Dist: pytest>=9.2; extra == 'dev'
|
|
42
|
+
Requires-Dist: ruff>=0.17.3; extra == 'dev'
|
|
43
|
+
Requires-Dist: ty>=0.0.94; extra == 'dev'
|
|
40
44
|
Provides-Extra: embed
|
|
41
45
|
Provides-Extra: grafeo
|
|
42
|
-
Requires-Dist: grafeo
|
|
46
|
+
Requires-Dist: grafeo<0.7,>=0.6.0; extra == 'grafeo'
|
|
43
47
|
Provides-Extra: lancedb
|
|
44
48
|
Requires-Dist: lancedb>=0.1; extra == 'lancedb'
|
|
45
49
|
Provides-Extra: numpy
|
|
@@ -69,7 +73,7 @@ Works with Marimo, Jupyter, VS Code, Colab, anywhere [anywidget](https://anywidg
|
|
|
69
73
|
|
|
70
74
|
- **Universal**: One widget, every notebook environment
|
|
71
75
|
- **6D Visualization**: X, Y, Z position + Color, Shape, Size encoding
|
|
72
|
-
- **Backend-agnostic**: NumPy, pandas, Qdrant, Chroma, Pinecone, Weaviate, LanceDB, or raw dicts
|
|
76
|
+
- **Backend-agnostic**: NumPy, pandas, Grafeo, Qdrant, Chroma, Pinecone, Weaviate, LanceDB, or raw dicts
|
|
73
77
|
- **Interactive**: Orbit, pan, zoom, click, hover, box select
|
|
74
78
|
- **Customizable**: Color scales, shapes, sizes, themes
|
|
75
79
|
- **Performant**: Instanced rendering for large point clouds
|
|
@@ -78,8 +82,12 @@ Works with Marimo, Jupyter, VS Code, Colab, anywhere [anywidget](https://anywidg
|
|
|
78
82
|
|
|
79
83
|
```bash
|
|
80
84
|
uv add anywidget-vector
|
|
85
|
+
uv add "anywidget-vector[grafeo]" # with the embedded Grafeo backend (grafeo 0.6)
|
|
81
86
|
```
|
|
82
87
|
|
|
88
|
+
Requires Python 3.12 or later. The `grafeo` extra installs grafeo 0.6 (`grafeo>=0.6.0,<0.7`); the browser-side WASM mode loads the matching `@grafeo-db/wasm` from a CDN. Upgrading from 0.3 with Grafeo:
|
|
89
|
+
see [Upgrading to 0.4](#upgrading-to-04).
|
|
90
|
+
|
|
83
91
|
## Quick Start
|
|
84
92
|
|
|
85
93
|
```python
|
|
@@ -347,7 +355,8 @@ widget = VectorSpace(
|
|
|
347
355
|
points=data,
|
|
348
356
|
width=1000,
|
|
349
357
|
height=700,
|
|
350
|
-
|
|
358
|
+
dark_mode=None, # None (default) follows the page theme; True or False fixes it
|
|
359
|
+
background=None, # None (default) uses the theme's canvas color
|
|
351
360
|
show_axes=True,
|
|
352
361
|
show_grid=True,
|
|
353
362
|
axis_labels={"x": "PC1", "y": "PC2", "z": "PC3"},
|
|
@@ -358,6 +367,16 @@ widget = VectorSpace(
|
|
|
358
367
|
)
|
|
359
368
|
```
|
|
360
369
|
|
|
370
|
+
### Theme
|
|
371
|
+
|
|
372
|
+
The widget follows the theme of the page it is on: a `data-theme="dark"` or `"light"` on the widget's closest ancestor,
|
|
373
|
+
then on `<html>` and `<body>`, then a `dark` or `light` class on `<html>` or `<body>`, then the operating system's
|
|
374
|
+
dark-mode setting. It keeps following as the page changes. `dark_mode` reports the theme in use.
|
|
375
|
+
|
|
376
|
+
A theme you choose stays: `VectorSpace(dark_mode=False)`, `widget.dark_mode = ...` before or after the widget is shown
|
|
377
|
+
(also to the value it already reports), or the toggle in the settings panel. The canvas color follows the theme unless
|
|
378
|
+
you choose a `background` the same way. anywidget-graph and anywidget-archimate behave the same.
|
|
379
|
+
|
|
361
380
|
## Backends
|
|
362
381
|
|
|
363
382
|
Configure a backend for interactive querying:
|
|
@@ -368,6 +387,96 @@ widget.set_backend("lancedb", client=table)
|
|
|
368
387
|
widget.set_backend("grafeo", client=db)
|
|
369
388
|
```
|
|
370
389
|
|
|
390
|
+
Type a query in the toolbar and press Run (or Enter). An empty result clears the scene; errors show in
|
|
391
|
+
the settings panel.
|
|
392
|
+
|
|
393
|
+
### Credentials
|
|
394
|
+
|
|
395
|
+
Connection settings, including `apiKey`, `authToken`, `username` and `password` in `set_backend(...)` and the
|
|
396
|
+
embedding key in the settings panel, are widget state: they reach the browser, which needs them for the browser-side
|
|
397
|
+
backends (Qdrant, Pinecone, Weaviate, grafeo-server), and Jupyter saves them in the notebook file when it saves widget
|
|
398
|
+
state. Use a read-only key with the narrowest scope the backend offers, keep it out of notebooks you share, or query
|
|
399
|
+
from Python (`from_qdrant(...)`, `set_backend("chroma", client=...)` and the other Python-side clients keep their
|
|
400
|
+
credentials in the kernel).
|
|
401
|
+
|
|
402
|
+
### Grafeo
|
|
403
|
+
|
|
404
|
+
[Grafeo](https://grafeo.dev/) is the default backend. It runs in three modes, set with
|
|
405
|
+
`grafeo_connection_mode`:
|
|
406
|
+
|
|
407
|
+
| Mode | Where queries run | Setup |
|
|
408
|
+
|------|-------------------|-------|
|
|
409
|
+
| `embedded` (default) | In Python, on a `grafeo.GrafeoDB` | `uv add "anywidget-vector[grafeo]"` and `set_backend("grafeo", client=db)` |
|
|
410
|
+
| `server` | Over HTTP, `POST /query` on [grafeo-server](https://github.com/GrafeoDB/grafeo-server) | `grafeo_server_url="http://localhost:7474"`; start the server with `--cors-origins` so the notebook's origin may call it |
|
|
411
|
+
| `wasm` | In the browser, in-memory | Nothing to install: `@grafeo-db/wasm` 0.6.0 loads from the jsDelivr CDN on the first query (the only code the widget loads from a CDN) |
|
|
412
|
+
|
|
413
|
+
```python
|
|
414
|
+
import grafeo
|
|
415
|
+
from anywidget_vector import VectorSpace
|
|
416
|
+
|
|
417
|
+
db = grafeo.GrafeoDB()
|
|
418
|
+
db.create_node(["Doc"], {"title": "Graphs", "embedding": [0.9, 0.1, 0.0]})
|
|
419
|
+
db.create_node(["Doc"], {"title": "Vectors", "embedding": [0.1, 0.9, 0.2]})
|
|
420
|
+
db.create_vector_index("Doc", "embedding", metric="cosine")
|
|
421
|
+
|
|
422
|
+
widget = VectorSpace(color_field="distance")
|
|
423
|
+
widget.set_backend("grafeo", client=db)
|
|
424
|
+
widget
|
|
425
|
+
```
|
|
426
|
+
|
|
427
|
+
A k-nearest-neighbor query for the toolbar (GQL, one statement per query):
|
|
428
|
+
|
|
429
|
+
```
|
|
430
|
+
CALL grafeo.search.vector('Doc', 'embedding', [1.0, 0.0, 0.0], 10) YIELD node_id, distance
|
|
431
|
+
NEXT MATCH (n:Doc) WHERE id(n) = node_id RETURN n, distance ORDER BY distance
|
|
432
|
+
```
|
|
433
|
+
|
|
434
|
+
How results become points, the same in every mode:
|
|
435
|
+
|
|
436
|
+
- A node (`RETURN n`) contributes its properties, its labels (`labels`) and its id (`id`).
|
|
437
|
+
- An unaliased column is named after its expression (`n.embedding`), and the widget reads it as `embedding`.
|
|
438
|
+
- The first of `vector`, `embedding` or `embeddings` becomes the point's `vector`; its first three components
|
|
439
|
+
are the coordinates unless the row also has `x`, `y` and `z`.
|
|
440
|
+
- A GQL number with a point (`0.5`) is an exact decimal in Grafeo 0.6; the widget turns it into a float, also inside
|
|
441
|
+
lists and maps, so `RETURN 0.5 AS score` colors and sizes points like any other number.
|
|
442
|
+
|
|
443
|
+
In `wasm` mode the database starts empty, so load data with one `INSERT` per query and create the index with
|
|
444
|
+
`CREATE VECTOR INDEX doc_embedding ON :Doc(embedding) DIMENSION 3 METRIC 'cosine'`. Store embeddings
|
|
445
|
+
as `vector([...])` there: a plain list is not indexed. An `INSERT` returns no rows, so it clears the scene; run a
|
|
446
|
+
`MATCH` or a search afterwards to see the data.
|
|
447
|
+
|
|
448
|
+
A query vector with another number of dimensions than the index, or with NaN, is a query error that names the
|
|
449
|
+
sizes (for example "the query vector has 2 dimensions; the index on :Doc(embedding) expects 3"); the points stay
|
|
450
|
+
as they were.
|
|
451
|
+
|
|
452
|
+
The distance metrics of a Grafeo vector index (`cosine`, `euclidean`, `dot_product`, `manhattan`) give the
|
|
453
|
+
same values as the widget's `distance_metric` and `compute_distances()`.
|
|
454
|
+
|
|
455
|
+
The browser engine version is set in one place, `GRAFEO_WASM_VERSION` in
|
|
456
|
+
`src/anywidget_vector/backends/grafeo/embed.js`, and moves in lockstep with the `grafeo` extra. Before a bump,
|
|
457
|
+
run `node tests/js/wasm_smoke.mjs <unpacked @grafeo-db/wasm package>`.
|
|
458
|
+
|
|
459
|
+
### Upgrading to 0.4
|
|
460
|
+
|
|
461
|
+
0.4 moves the Grafeo backend to Grafeo 0.6, which changes some query results. What to check:
|
|
462
|
+
|
|
463
|
+
- **Install**: the `grafeo` extra needs grafeo 0.6; `uv add "anywidget-vector[grafeo]"` upgrades it. The `wasm` mode
|
|
464
|
+
loads `@grafeo-db/wasm` 0.6 from the CDN by itself.
|
|
465
|
+
- **Database files**: Grafeo 0.6 keeps every database in a single file. The first read-write open of a 0.5.x
|
|
466
|
+
database migrates it and keeps the old file as `<file>.pre-0.6`; 0.5.x cannot open the migrated file, so stop
|
|
467
|
+
every 0.5.x process first and keep the `.pre-0.6` copy until you no longer need to go back. Opening a directory that
|
|
468
|
+
is not a 0.5.x database fails: pass a file path, such as `data/vectors.grafeo`.
|
|
469
|
+
- **Numbers with a point**: `0.1` is an exact decimal in GQL, so `0.0/0.0` and `1/0` now fail the query (division by
|
|
470
|
+
zero) instead of giving NaN or null, and integer overflow fails too. Write float literals with an exponent
|
|
471
|
+
(`0.0e0 / 0.0e0`) where you want IEEE results.
|
|
472
|
+
- **Writes**: a `WHERE` right after `INSERT`, `CREATE`, `MERGE` or `DELETE` is an error; put the condition before the
|
|
473
|
+
write. An `INSERT` alone returns no rows.
|
|
474
|
+
- **Ordering**: GQL `ORDER BY` puts nulls last in both directions; add `NULLS FIRST` for the old descending order.
|
|
475
|
+
- **Errors**: a vector search with a query of the wrong size raises `grafeo.GrafeoError` (Grafeo 0.5.44 panicked);
|
|
476
|
+
the widget shows it as a query error either way.
|
|
477
|
+
|
|
478
|
+
See Grafeo's [Upgrading to 0.6](https://grafeo.dev/upgrading/0.6/) for the full list.
|
|
479
|
+
|
|
371
480
|
## Export
|
|
372
481
|
|
|
373
482
|
```python
|
|
@@ -377,6 +486,13 @@ widget.to_html(title="My Vectors") # Custom title
|
|
|
377
486
|
widget.save_html("vectors.html") # Write HTML to file
|
|
378
487
|
```
|
|
379
488
|
|
|
489
|
+
Three.js is bundled with the package (`ui/vendor/three.min.js`, built by `scripts/vendor`), so the widget and its
|
|
490
|
+
HTML export work offline and under a strict Content Security Policy. Only the `wasm` Grafeo mode loads code from a
|
|
491
|
+
CDN.
|
|
492
|
+
|
|
493
|
+
NaN and infinity cannot travel as JSON, so the widget replaces them with `None` in point values (with a
|
|
494
|
+
`RuntimeWarning`); a missing coordinate is drawn at 0.
|
|
495
|
+
|
|
380
496
|
## Environment Support
|
|
381
497
|
|
|
382
498
|
| Environment | Supported |
|