hyperview 0.4.1__tar.gz → 0.5.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.
- {hyperview-0.4.1 → hyperview-0.5.0}/.agents/skills/hyperview-cli/SKILL.md +13 -7
- {hyperview-0.4.1 → hyperview-0.5.0}/.agents/skills/hyperview-cli/references/commands.md +59 -2
- {hyperview-0.4.1 → hyperview-0.5.0}/PKG-INFO +6 -5
- {hyperview-0.4.1 → hyperview-0.5.0}/README.md +3 -3
- {hyperview-0.4.1 → hyperview-0.5.0}/pyproject.toml +2 -1
- {hyperview-0.4.1 → hyperview-0.5.0}/src/hyperview/_version.py +2 -2
- {hyperview-0.4.1 → hyperview-0.5.0}/src/hyperview/cli.py +109 -0
- {hyperview-0.4.1 → hyperview-0.5.0}/src/hyperview/core/selection.py +20 -0
- hyperview-0.5.0/src/hyperview/figures/__init__.py +13 -0
- hyperview-0.5.0/src/hyperview/figures/colors.py +102 -0
- hyperview-0.5.0/src/hyperview/figures/render.py +628 -0
- {hyperview-0.4.1 → hyperview-0.5.0}/src/hyperview/runtime.py +72 -0
- {hyperview-0.4.1 → hyperview-0.5.0}/src/hyperview/server/app.py +26 -3
- {hyperview-0.4.1/src/hyperview/server/static/_not-found → hyperview-0.5.0/src/hyperview/server/static/404}/index.html +1 -1
- {hyperview-0.4.1 → hyperview-0.5.0}/src/hyperview/server/static/404.html +1 -1
- {hyperview-0.4.1 → hyperview-0.5.0}/src/hyperview/server/static/__next.__PAGE__.txt +2 -2
- {hyperview-0.4.1 → hyperview-0.5.0}/src/hyperview/server/static/__next._full.txt +2 -2
- {hyperview-0.4.1 → hyperview-0.5.0}/src/hyperview/server/static/__next._head.txt +1 -1
- {hyperview-0.4.1 → hyperview-0.5.0}/src/hyperview/server/static/__next._index.txt +1 -1
- {hyperview-0.4.1 → hyperview-0.5.0}/src/hyperview/server/static/__next._tree.txt +1 -1
- hyperview-0.5.0/src/hyperview/server/static/_next/static/chunks/d91860e761ca6b99.js +8 -0
- {hyperview-0.4.1 → hyperview-0.5.0}/src/hyperview/server/static/_not-found/__next._full.txt +1 -1
- {hyperview-0.4.1 → hyperview-0.5.0}/src/hyperview/server/static/_not-found/__next._head.txt +1 -1
- {hyperview-0.4.1 → hyperview-0.5.0}/src/hyperview/server/static/_not-found/__next._index.txt +1 -1
- {hyperview-0.4.1 → hyperview-0.5.0}/src/hyperview/server/static/_not-found/__next._not-found.__PAGE__.txt +1 -1
- {hyperview-0.4.1 → hyperview-0.5.0}/src/hyperview/server/static/_not-found/__next._not-found.txt +1 -1
- {hyperview-0.4.1 → hyperview-0.5.0}/src/hyperview/server/static/_not-found/__next._tree.txt +1 -1
- {hyperview-0.4.1/src/hyperview/server/static/404 → hyperview-0.5.0/src/hyperview/server/static/_not-found}/index.html +1 -1
- {hyperview-0.4.1 → hyperview-0.5.0}/src/hyperview/server/static/_not-found/index.txt +1 -1
- {hyperview-0.4.1 → hyperview-0.5.0}/src/hyperview/server/static/index.html +1 -1
- {hyperview-0.4.1 → hyperview-0.5.0}/src/hyperview/server/static/index.txt +2 -2
- {hyperview-0.4.1 → hyperview-0.5.0}/src/hyperview/skill_install.py +30 -0
- {hyperview-0.4.1 → hyperview-0.5.0}/src/hyperview/storage/lancedb_backend.py +69 -2
- {hyperview-0.4.1 → hyperview-0.5.0}/src/hyperview/storage/memory_backend.py +25 -10
- hyperview-0.5.0/src/hyperview/storage/metrics.py +99 -0
- hyperview-0.4.1/src/hyperview/server/static/_next/static/chunks/52ce757ecb4458ef.js +0 -8
- {hyperview-0.4.1 → hyperview-0.5.0}/.agents/skills/hyperview-cli/references/native-panels.md +0 -0
- {hyperview-0.4.1 → hyperview-0.5.0}/.agents/skills/hyperview-cli/references/plugins.md +0 -0
- {hyperview-0.4.1 → hyperview-0.5.0}/.gitignore +0 -0
- {hyperview-0.4.1 → hyperview-0.5.0}/LICENSE +0 -0
- {hyperview-0.4.1 → hyperview-0.5.0}/src/hyperview/__init__.py +0 -0
- {hyperview-0.4.1 → hyperview-0.5.0}/src/hyperview/api.py +0 -0
- {hyperview-0.4.1 → hyperview-0.5.0}/src/hyperview/core/__init__.py +0 -0
- {hyperview-0.4.1 → hyperview-0.5.0}/src/hyperview/core/dataset.py +0 -0
- {hyperview-0.4.1 → hyperview-0.5.0}/src/hyperview/core/sample.py +0 -0
- {hyperview-0.4.1 → hyperview-0.5.0}/src/hyperview/embeddings/__init__.py +0 -0
- {hyperview-0.4.1 → hyperview-0.5.0}/src/hyperview/embeddings/compute.py +0 -0
- {hyperview-0.4.1 → hyperview-0.5.0}/src/hyperview/embeddings/engine.py +0 -0
- {hyperview-0.4.1 → hyperview-0.5.0}/src/hyperview/embeddings/pipelines.py +0 -0
- {hyperview-0.4.1 → hyperview-0.5.0}/src/hyperview/embeddings/projection.py +0 -0
- {hyperview-0.4.1 → hyperview-0.5.0}/src/hyperview/embeddings/providers/__init__.py +0 -0
- {hyperview-0.4.1 → hyperview-0.5.0}/src/hyperview/embeddings/providers/lancedb_providers.py +0 -0
- {hyperview-0.4.1 → hyperview-0.5.0}/src/hyperview/extensions.py +0 -0
- {hyperview-0.4.1 → hyperview-0.5.0}/src/hyperview/server/__init__.py +0 -0
- {hyperview-0.4.1/src/hyperview/server/static/_next/static/yjPErSjTf1wXihXj121n0 → hyperview-0.5.0/src/hyperview/server/static/_next/static/1tZtVoPDFS4Vb1x9TZkO-}/_buildManifest.js +0 -0
- {hyperview-0.4.1/src/hyperview/server/static/_next/static/yjPErSjTf1wXihXj121n0 → hyperview-0.5.0/src/hyperview/server/static/_next/static/1tZtVoPDFS4Vb1x9TZkO-}/_clientMiddlewareManifest.json +0 -0
- {hyperview-0.4.1/src/hyperview/server/static/_next/static/yjPErSjTf1wXihXj121n0 → hyperview-0.5.0/src/hyperview/server/static/_next/static/1tZtVoPDFS4Vb1x9TZkO-}/_ssgManifest.js +0 -0
- {hyperview-0.4.1 → hyperview-0.5.0}/src/hyperview/server/static/_next/static/chunks/4899f901f4ca16ad.css +0 -0
- {hyperview-0.4.1 → hyperview-0.5.0}/src/hyperview/server/static/_next/static/chunks/567993cf36cd4ab1.js +0 -0
- {hyperview-0.4.1 → hyperview-0.5.0}/src/hyperview/server/static/_next/static/chunks/661a08547c83f565.js +0 -0
- {hyperview-0.4.1 → hyperview-0.5.0}/src/hyperview/server/static/_next/static/chunks/86c1fc4cf542f408.js +0 -0
- {hyperview-0.4.1 → hyperview-0.5.0}/src/hyperview/server/static/_next/static/chunks/a6dad97d9634a72d.js +0 -0
- {hyperview-0.4.1 → hyperview-0.5.0}/src/hyperview/server/static/_next/static/chunks/a6dad97d9634a72d.js.map +0 -0
- {hyperview-0.4.1 → hyperview-0.5.0}/src/hyperview/server/static/_next/static/chunks/e954ba82c0a04100.js +0 -0
- {hyperview-0.4.1 → hyperview-0.5.0}/src/hyperview/server/static/_next/static/chunks/eac713f252f03efd.js +0 -0
- {hyperview-0.4.1 → hyperview-0.5.0}/src/hyperview/server/static/_next/static/chunks/f29dd35a99c216ea.js +0 -0
- {hyperview-0.4.1 → hyperview-0.5.0}/src/hyperview/server/static/_next/static/chunks/turbopack-cb59e03a04a579d1.js +0 -0
- {hyperview-0.4.1 → hyperview-0.5.0}/src/hyperview/server/static/_next/static/media/1bffadaabf893a1e-s.7cd81963.woff2 +0 -0
- {hyperview-0.4.1 → hyperview-0.5.0}/src/hyperview/server/static/_next/static/media/2bbe8d2671613f1f-s.76dcb0b2.woff2 +0 -0
- {hyperview-0.4.1 → hyperview-0.5.0}/src/hyperview/server/static/_next/static/media/2c55a0e60120577a-s.2a48534a.woff2 +0 -0
- {hyperview-0.4.1 → hyperview-0.5.0}/src/hyperview/server/static/_next/static/media/5476f68d60460930-s.c995e352.woff2 +0 -0
- {hyperview-0.4.1 → hyperview-0.5.0}/src/hyperview/server/static/_next/static/media/83afe278b6a6bb3c-s.p.3a6ba036.woff2 +0 -0
- {hyperview-0.4.1 → hyperview-0.5.0}/src/hyperview/server/static/_next/static/media/9c72aa0f40e4eef8-s.18a48cbc.woff2 +0 -0
- {hyperview-0.4.1 → hyperview-0.5.0}/src/hyperview/server/static/_next/static/media/ad66f9afd8947f86-s.7a40eb73.woff2 +0 -0
- {hyperview-0.4.1 → hyperview-0.5.0}/src/hyperview/storage/__init__.py +0 -0
- {hyperview-0.4.1 → hyperview-0.5.0}/src/hyperview/storage/backend.py +0 -0
- {hyperview-0.4.1 → hyperview-0.5.0}/src/hyperview/storage/config.py +0 -0
- {hyperview-0.4.1 → hyperview-0.5.0}/src/hyperview/storage/schema.py +0 -0
- {hyperview-0.4.1 → hyperview-0.5.0}/src/hyperview/tools.py +0 -0
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: hyperview-cli
|
|
3
|
-
description: Use HyperView's control-plane CLI for hyperview serve, dataset create, workspace create, embeddings compute, layouts compute, runtime jobs, ui layout set, ui selection set, ui panel add, extension add, tools run, native module panels, backend tools, and local HyperView plugin workflows.
|
|
3
|
+
description: Use HyperView's control-plane CLI for hyperview serve, dataset create, workspace create, embeddings compute, layouts compute, browserless paper figure export, runtime jobs, ui layout set, ui selection set, ui panel add, extension add, tools run, native module panels, backend tools, and local HyperView plugin workflows.
|
|
4
4
|
license: MIT
|
|
5
|
-
compatibility: Requires Python 3.10
|
|
5
|
+
compatibility: Requires Python 3.10-3.13 and the hyperview CLI (`uv tool install --python 3.12 hyperview`). Runtime-control commands require a running HyperView server.
|
|
6
6
|
metadata:
|
|
7
7
|
homepage: https://github.com/Hyper3Labs/HyperView
|
|
8
8
|
---
|
|
@@ -16,10 +16,10 @@ Use the `hyperview` CLI as the primary agent interface to HyperView.
|
|
|
16
16
|
For users who installed HyperView from a package, install or refresh this agent skill with:
|
|
17
17
|
|
|
18
18
|
```bash
|
|
19
|
-
uv tool install --upgrade hyperview && hyperview skill install
|
|
19
|
+
uv tool install --python 3.12 --upgrade hyperview && hyperview skill install
|
|
20
20
|
```
|
|
21
21
|
|
|
22
|
-
Re-running `hyperview skill install` replaces old HyperView skill copies. By default this installs into detected agent locations plus the universal `~/.agents/skills/` fallback. Limit targets with repeated `--agent` flags such as `--agent claude-code`, `--agent github-copilot`, `--agent cursor`, or `--agent universal`; use `--all-known` when you explicitly want every known agent profile. Use `--scope project` to write project-local skills such as `.claude/skills/`, `.github/skills/`, `.cursor/skills/`, or `.agents/skills/` depending on the selected agent.
|
|
22
|
+
HyperView currently supports Python 3.10 through 3.13; `--python 3.12` keeps the persistent CLI on a broadly supported runtime. Re-running `hyperview skill install` replaces old HyperView skill copies. By default this installs into detected agent locations plus the universal `~/.agents/skills/` fallback. Limit targets with repeated `--agent` flags such as `--agent claude-code`, `--agent github-copilot`, `--agent cursor`, or `--agent universal`; use `--all-known` when you explicitly want every known agent profile. Use `--scope project` to write project-local skills such as `.claude/skills/`, `.github/skills/`, `.cursor/skills/`, or `.agents/skills/` depending on the selected agent.
|
|
23
23
|
|
|
24
24
|
## When to use it
|
|
25
25
|
|
|
@@ -29,6 +29,7 @@ Re-running `hyperview skill install` replaces old HyperView skill copies. By def
|
|
|
29
29
|
- Start or control a running HyperView runtime.
|
|
30
30
|
- Register a custom embedding provider.
|
|
31
31
|
- Compute embeddings or layouts without restarting the UI.
|
|
32
|
+
- Export paper-ready static 3D embedding figures without a browser or Node runtime.
|
|
32
33
|
- Switch the active workspace, layout, or selection in a running session.
|
|
33
34
|
- Add or remove agent-authored native module panels from local files.
|
|
34
35
|
- Create, install, reload, or test a local plugin/extension with Python backend tools and a frontend panel.
|
|
@@ -41,7 +42,8 @@ Re-running `hyperview skill install` replaces old HyperView skill copies. By def
|
|
|
41
42
|
4. Register a provider if needed.
|
|
42
43
|
5. Submit embedding or layout jobs through the runtime.
|
|
43
44
|
6. Use `hyperview ui ...` commands to switch what the live UI shows.
|
|
44
|
-
7.
|
|
45
|
+
7. Export paper figures with `hyperview figure export` when the user needs screenshots or publication diagrams.
|
|
46
|
+
8. For plugins, create an extension folder and install it into the running workspace.
|
|
45
47
|
|
|
46
48
|
## Current model
|
|
47
49
|
|
|
@@ -54,8 +56,10 @@ Re-running `hyperview skill install` replaces old HyperView skill copies. By def
|
|
|
54
56
|
- Plugins are repo-local extension folders with `extension.toml`, optional Python tools, and optional native panel modules.
|
|
55
57
|
- Plugin panels call backend tools through `HyperViewPanelSDK.hooks.useTool()` or `hyperview tools run`.
|
|
56
58
|
- In practice, create datasets and workspaces before starting the runtime for that workspace. The current runtime loads workspace registry state on startup.
|
|
59
|
+
- `figure export` is browserless and supports 3D layouts only. It reuses the persisted 3D camera for the layout when available, otherwise it chooses a paper-oriented default view.
|
|
60
|
+
- Paper figure defaults are square, white-background, opaque PNGs with a faint sphere guide and direct labels for small label sets.
|
|
57
61
|
|
|
58
|
-
Read [references/commands.md](references/commands.md) for command recipes covering datasets, workspaces, providers, embeddings, layouts, runtime UI state, selections, and jobs.
|
|
62
|
+
Read [references/commands.md](references/commands.md) for command recipes covering datasets, workspaces, providers, embeddings, layouts, paper figures, runtime UI state, selections, and jobs.
|
|
59
63
|
Read [references/native-panels.md](references/native-panels.md) when the task involves authoring or registering a custom panel.
|
|
60
64
|
Read [references/plugins.md](references/plugins.md) when the task involves backend-plus-frontend plugins/extensions.
|
|
61
65
|
|
|
@@ -75,6 +79,8 @@ Read [references/plugins.md](references/plugins.md) when the task involves backe
|
|
|
75
79
|
- For provider args, use repeated `--provider-arg key=value` flags.
|
|
76
80
|
- Treat the workspace as the durable unit. Changing datasets means setting a new workspace dataset, not switching among many datasets inside one workspace.
|
|
77
81
|
- Prefer native module panels over raw HTML. The panel system no longer relies on iframes.
|
|
82
|
+
- For paper diagrams, prefer `hyperview figure export` over browser screenshots unless the user explicitly needs exact UI chrome. It does not require Playwright, browser bundling, or Node at runtime.
|
|
83
|
+
- For publication figures, keep the defaults first: `--theme light`, `--guide-style paper`, and `--legend auto`. Use `--show-selection` only when selected samples are meaningful and will be explained in the caption.
|
|
78
84
|
- The first `uv run hyperview ...` invocation in a session can take 30+ seconds (torch/datasets imports). Allow generous timeouts and avoid sending SIGINT.
|
|
79
85
|
|
|
80
86
|
## Inspecting runtime state
|
|
@@ -85,4 +91,4 @@ The runtime exposes JSON discovery endpoints alongside the CLI. Use them to obta
|
|
|
85
91
|
- `GET /api/embeddings?workspace_id=<ws>` — the active or default layout, including `layout_key`, `geometry`, and sample `ids`. Use the returned `layout_key` for `hyperview ui layout set --layout-key ...` and pick from `ids` for `hyperview ui selection set --ids ...`.
|
|
86
92
|
- `GET /api/tools` — registered tool URIs (also returned by `hyperview tools list --json`).
|
|
87
93
|
|
|
88
|
-
Layout keys encode geometry and dimension as a substring (e.g. `..._euclidean_umap__2d_...`, `..._hyperbolic_umap__3d_...`). Match on those substrings when filtering by geometry/dimension.
|
|
94
|
+
Layout keys encode geometry and dimension as a substring (e.g. `..._euclidean_umap__2d_...`, `..._hyperbolic_umap__3d_...`). Match on those substrings when filtering by geometry/dimension.
|
|
@@ -13,7 +13,7 @@ hyperview skill install
|
|
|
13
13
|
Refresh installed copies after upgrading HyperView by running install again:
|
|
14
14
|
|
|
15
15
|
```bash
|
|
16
|
-
uv tool install --upgrade hyperview && hyperview skill install
|
|
16
|
+
uv tool install --python 3.12 --upgrade hyperview && hyperview skill install
|
|
17
17
|
```
|
|
18
18
|
|
|
19
19
|
Limit to specific agent targets:
|
|
@@ -131,6 +131,63 @@ hyperview jobs list --json
|
|
|
131
131
|
hyperview jobs inspect <job-id> --json
|
|
132
132
|
```
|
|
133
133
|
|
|
134
|
+
## Paper Figures
|
|
135
|
+
|
|
136
|
+
Export a browserless, paper-ready PNG from the active 3D layout:
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
hyperview figure export figures/embedding-sphere.png \
|
|
140
|
+
--workspace research \
|
|
141
|
+
--layout active \
|
|
142
|
+
--json
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
If `--layout` is omitted, HyperView uses the active 3D layout when one is set, otherwise the first available 3D layout. Use `--layout active` when you specifically want the live UI's active layout and want the command to fail if none is active.
|
|
146
|
+
|
|
147
|
+
The export path is pure Python and does not require Playwright, browser bundling, Node, or a running frontend. It supports 3D layouts only; 2D layouts are rejected with a validation message.
|
|
148
|
+
|
|
149
|
+
Paper defaults are tuned for academic figures:
|
|
150
|
+
|
|
151
|
+
- `--width 900 --height 900 --scale 2`
|
|
152
|
+
- `--theme light`
|
|
153
|
+
- `--guide-style paper`
|
|
154
|
+
- `--legend auto` (direct labels for small label sets)
|
|
155
|
+
- opaque PNG output
|
|
156
|
+
- selection rings hidden unless explicitly requested
|
|
157
|
+
|
|
158
|
+
Use the 3D view selected in the UI by rotating the scatter panel first. HyperView persists the layout camera and `figure export` reuses it for that layout.
|
|
159
|
+
|
|
160
|
+
Common variants:
|
|
161
|
+
|
|
162
|
+
```bash
|
|
163
|
+
# Cleanest sphere context: silhouette only.
|
|
164
|
+
hyperview figure export figures/embedding-outline.png \
|
|
165
|
+
--workspace research \
|
|
166
|
+
--layout active \
|
|
167
|
+
--guide-style outline
|
|
168
|
+
|
|
169
|
+
# No sphere guide, useful when the embedding separation is the whole message.
|
|
170
|
+
hyperview figure export figures/embedding-clean.png \
|
|
171
|
+
--workspace research \
|
|
172
|
+
--layout active \
|
|
173
|
+
--guide-style none \
|
|
174
|
+
--legend direct
|
|
175
|
+
|
|
176
|
+
# Browser-like guide rings and current selection markers.
|
|
177
|
+
hyperview figure export figures/embedding-ui-like.png \
|
|
178
|
+
--workspace research \
|
|
179
|
+
--layout active \
|
|
180
|
+
--guide-style rings \
|
|
181
|
+
--legend on \
|
|
182
|
+
--show-selection
|
|
183
|
+
|
|
184
|
+
# Add a short panel title when the figure will stand alone.
|
|
185
|
+
hyperview figure export figures/embedding-panel-a.png \
|
|
186
|
+
--workspace research \
|
|
187
|
+
--layout active \
|
|
188
|
+
--title "ArcFace spherical embeddings"
|
|
189
|
+
```
|
|
190
|
+
|
|
134
191
|
## Runtime UI
|
|
135
192
|
|
|
136
193
|
Discover an existing layout key and sample IDs before mutating runtime state:
|
|
@@ -220,4 +277,4 @@ hyperview tools run selection_profile.summarize \
|
|
|
220
277
|
- `--param 'top_k=5'` for numbers
|
|
221
278
|
- `--param 'enabled=true'` for booleans
|
|
222
279
|
- `--param 'name=foo'` for short strings (raw fallback) or `--param 'name="foo bar"'` for explicit JSON strings
|
|
223
|
-
- `--param 'ids=["a","b"]'` or `--param 'opts={"k":1}'` for arrays/objects
|
|
280
|
+
- `--param 'ids=["a","b"]'` or `--param 'opts={"k":1}'` for arrays/objects
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: hyperview
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.5.0
|
|
4
4
|
Summary: Open-source dataset curation with hyperbolic embeddings visualization
|
|
5
5
|
Project-URL: Homepage, https://github.com/Hyper3Labs/HyperView
|
|
6
6
|
Project-URL: Documentation, https://github.com/Hyper3Labs/HyperView#readme
|
|
@@ -18,9 +18,10 @@ Classifier: Programming Language :: Python :: 3
|
|
|
18
18
|
Classifier: Programming Language :: Python :: 3.10
|
|
19
19
|
Classifier: Programming Language :: Python :: 3.11
|
|
20
20
|
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
21
22
|
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
22
23
|
Classifier: Topic :: Scientific/Engineering :: Visualization
|
|
23
|
-
Requires-Python:
|
|
24
|
+
Requires-Python: <3.14,>=3.10
|
|
24
25
|
Requires-Dist: aiofiles>=25.1.0
|
|
25
26
|
Requires-Dist: datasets>=4.5.0
|
|
26
27
|
Requires-Dist: embed-anything>=0.7.0
|
|
@@ -95,10 +96,10 @@ Install it when a scatterplot is no longer enough: you want a local, extensible
|
|
|
95
96
|
Install the HyperView CLI and refresh the agent skill in one copy-paste line:
|
|
96
97
|
|
|
97
98
|
```bash
|
|
98
|
-
uv tool install --upgrade hyperview && hyperview skill install
|
|
99
|
+
uv tool install --python 3.12 --upgrade hyperview && hyperview skill install
|
|
99
100
|
```
|
|
100
101
|
|
|
101
|
-
Re-running `hyperview skill install` replaces old HyperView skill copies, so the installed agent skill stays in sync with the upgraded CLI. By default this installs into detected agent locations plus the universal `~/.agents/skills/hyperview-cli` fallback. For a project-local Copilot install, run:
|
|
102
|
+
HyperView currently supports Python 3.10 through 3.13; `--python 3.12` keeps the tool install on a widely supported runtime while upstream ML wheels catch up with newer Python releases. Re-running `hyperview skill install` replaces old HyperView skill copies, so the installed agent skill stays in sync with the upgraded CLI. By default this installs into detected agent locations plus the universal `~/.agents/skills/hyperview-cli` fallback. For a project-local Copilot install, run:
|
|
102
103
|
|
|
103
104
|
```bash
|
|
104
105
|
hyperview skill install --scope project --agent github-copilot --yes
|
|
@@ -205,7 +206,7 @@ Traditional Euclidean embeddings struggle with hierarchical data. In Euclidean s
|
|
|
205
206
|
|
|
206
207
|
## Community
|
|
207
208
|
|
|
208
|
-
**Weekly Open Discussion** — Every Tuesday at 15:00 UTC on [Discord](https://discord.gg/
|
|
209
|
+
**Weekly Open Discussion** — Every Tuesday at 15:00 UTC on [Discord](https://discord.gg/Za3rBkTPSf)
|
|
209
210
|
|
|
210
211
|
Join us to see the latest features demoed live, walk through new code, and get help with local setup. Whether you're a core maintainer or looking for your first contribution, everyone is welcome.
|
|
211
212
|
|
|
@@ -45,10 +45,10 @@ Install it when a scatterplot is no longer enough: you want a local, extensible
|
|
|
45
45
|
Install the HyperView CLI and refresh the agent skill in one copy-paste line:
|
|
46
46
|
|
|
47
47
|
```bash
|
|
48
|
-
uv tool install --upgrade hyperview && hyperview skill install
|
|
48
|
+
uv tool install --python 3.12 --upgrade hyperview && hyperview skill install
|
|
49
49
|
```
|
|
50
50
|
|
|
51
|
-
Re-running `hyperview skill install` replaces old HyperView skill copies, so the installed agent skill stays in sync with the upgraded CLI. By default this installs into detected agent locations plus the universal `~/.agents/skills/hyperview-cli` fallback. For a project-local Copilot install, run:
|
|
51
|
+
HyperView currently supports Python 3.10 through 3.13; `--python 3.12` keeps the tool install on a widely supported runtime while upstream ML wheels catch up with newer Python releases. Re-running `hyperview skill install` replaces old HyperView skill copies, so the installed agent skill stays in sync with the upgraded CLI. By default this installs into detected agent locations plus the universal `~/.agents/skills/hyperview-cli` fallback. For a project-local Copilot install, run:
|
|
52
52
|
|
|
53
53
|
```bash
|
|
54
54
|
hyperview skill install --scope project --agent github-copilot --yes
|
|
@@ -155,7 +155,7 @@ Traditional Euclidean embeddings struggle with hierarchical data. In Euclidean s
|
|
|
155
155
|
|
|
156
156
|
## Community
|
|
157
157
|
|
|
158
|
-
**Weekly Open Discussion** — Every Tuesday at 15:00 UTC on [Discord](https://discord.gg/
|
|
158
|
+
**Weekly Open Discussion** — Every Tuesday at 15:00 UTC on [Discord](https://discord.gg/Za3rBkTPSf)
|
|
159
159
|
|
|
160
160
|
Join us to see the latest features demoed live, walk through new code, and get help with local setup. Whether you're a core maintainer or looking for your first contribution, everyone is welcome.
|
|
161
161
|
|
|
@@ -4,7 +4,7 @@ dynamic = ["version"]
|
|
|
4
4
|
description = "Open-source dataset curation with hyperbolic embeddings visualization"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
license = { text = "MIT" }
|
|
7
|
-
requires-python = ">=3.10"
|
|
7
|
+
requires-python = ">=3.10,<3.14"
|
|
8
8
|
authors = [
|
|
9
9
|
{ name = "hyper3labs" }
|
|
10
10
|
]
|
|
@@ -18,6 +18,7 @@ classifiers = [
|
|
|
18
18
|
"Programming Language :: Python :: 3.10",
|
|
19
19
|
"Programming Language :: Python :: 3.11",
|
|
20
20
|
"Programming Language :: Python :: 3.12",
|
|
21
|
+
"Programming Language :: Python :: 3.13",
|
|
21
22
|
"Topic :: Scientific/Engineering :: Artificial Intelligence",
|
|
22
23
|
"Topic :: Scientific/Engineering :: Visualization",
|
|
23
24
|
]
|
|
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
|
|
|
18
18
|
commit_id: str | None
|
|
19
19
|
__commit_id__: str | None
|
|
20
20
|
|
|
21
|
-
__version__ = version = '0.
|
|
22
|
-
__version_tuple__ = version_tuple = (0,
|
|
21
|
+
__version__ = version = '0.5.0'
|
|
22
|
+
__version_tuple__ = version_tuple = (0, 5, 0)
|
|
23
23
|
|
|
24
24
|
__commit_id__ = commit_id = None
|
|
@@ -13,7 +13,10 @@ from urllib.request import Request, urlopen
|
|
|
13
13
|
|
|
14
14
|
from hyperview import Dataset
|
|
15
15
|
from hyperview.api import Session
|
|
16
|
+
from hyperview.core.selection import OrbitViewState3D
|
|
17
|
+
from hyperview.figures import FigureRenderOptions, render_layout_figure
|
|
16
18
|
from hyperview.runtime import HyperViewRuntime, ProviderRegistry, WorkspaceRegistry
|
|
19
|
+
from hyperview.storage.schema import parse_layout_dimension
|
|
17
20
|
|
|
18
21
|
|
|
19
22
|
def _read_json_response(response: Any) -> Any:
|
|
@@ -270,6 +273,28 @@ def _build_control_parser() -> argparse.ArgumentParser:
|
|
|
270
273
|
jobs_inspect.add_argument("job_id")
|
|
271
274
|
_add_json_flag(jobs_inspect)
|
|
272
275
|
|
|
276
|
+
figure_parser = subparsers.add_parser("figure")
|
|
277
|
+
figure_subparsers = figure_parser.add_subparsers(dest="figure_command", required=True)
|
|
278
|
+
figure_export = figure_subparsers.add_parser("export")
|
|
279
|
+
figure_export.add_argument("output")
|
|
280
|
+
figure_export.add_argument("--workspace")
|
|
281
|
+
figure_export.add_argument("--dataset")
|
|
282
|
+
figure_export.add_argument("--layout")
|
|
283
|
+
figure_export.add_argument("--width", type=int, default=900)
|
|
284
|
+
figure_export.add_argument("--height", type=int, default=900)
|
|
285
|
+
figure_export.add_argument("--scale", type=int, default=2)
|
|
286
|
+
figure_export.add_argument("--theme", choices=["dark", "light"], default="light")
|
|
287
|
+
figure_export.add_argument("--background")
|
|
288
|
+
figure_export.add_argument("--point-radius", type=float, default=4.0)
|
|
289
|
+
figure_export.add_argument("--guide-style", choices=["paper", "rings", "outline", "none"], default="paper")
|
|
290
|
+
figure_export.add_argument("--guide-alpha", type=int)
|
|
291
|
+
figure_export.add_argument("--legend", choices=["auto", "on", "off", "direct"], default="auto")
|
|
292
|
+
figure_export.add_argument("--title")
|
|
293
|
+
figure_export.add_argument("--show-selection", action="store_true")
|
|
294
|
+
figure_export.add_argument("--no-guide", action="store_true")
|
|
295
|
+
figure_export.add_argument("--ignore-selection", action="store_true")
|
|
296
|
+
_add_json_flag(figure_export)
|
|
297
|
+
|
|
273
298
|
ui_parser = subparsers.add_parser("ui")
|
|
274
299
|
ui_subparsers = ui_parser.add_subparsers(dest="ui_command", required=True)
|
|
275
300
|
ui_workspace = ui_subparsers.add_parser("workspace")
|
|
@@ -598,6 +623,87 @@ def _run_jobs_command(args: argparse.Namespace) -> None:
|
|
|
598
623
|
raise RuntimeError(f"Unsupported jobs command: {args.jobs_command}")
|
|
599
624
|
|
|
600
625
|
|
|
626
|
+
def _resolve_figure_layout_key(
|
|
627
|
+
dataset: Dataset,
|
|
628
|
+
active_layout_key: str | None,
|
|
629
|
+
requested_layout_key: str | None,
|
|
630
|
+
) -> str:
|
|
631
|
+
layouts = dataset.list_layouts()
|
|
632
|
+
|
|
633
|
+
if requested_layout_key and requested_layout_key != "active":
|
|
634
|
+
return requested_layout_key
|
|
635
|
+
|
|
636
|
+
if requested_layout_key == "active":
|
|
637
|
+
if not active_layout_key:
|
|
638
|
+
raise RuntimeError("No active layout is set for this workspace")
|
|
639
|
+
return active_layout_key
|
|
640
|
+
|
|
641
|
+
if active_layout_key:
|
|
642
|
+
try:
|
|
643
|
+
if parse_layout_dimension(active_layout_key) == 3:
|
|
644
|
+
return active_layout_key
|
|
645
|
+
except ValueError:
|
|
646
|
+
pass
|
|
647
|
+
|
|
648
|
+
for layout in layouts:
|
|
649
|
+
try:
|
|
650
|
+
if parse_layout_dimension(layout.layout_key) == 3:
|
|
651
|
+
return layout.layout_key
|
|
652
|
+
except ValueError:
|
|
653
|
+
continue
|
|
654
|
+
|
|
655
|
+
raise RuntimeError("No 3D layout is available for figure export")
|
|
656
|
+
|
|
657
|
+
|
|
658
|
+
def _run_figure_command(args: argparse.Namespace) -> None:
|
|
659
|
+
if args.figure_command != "export":
|
|
660
|
+
raise RuntimeError(f"Unsupported figure command: {args.figure_command}")
|
|
661
|
+
|
|
662
|
+
runtime = HyperViewRuntime()
|
|
663
|
+
workspace = runtime.get_workspace(args.workspace)
|
|
664
|
+
dataset = runtime.get_dataset(workspace.id, args.dataset)
|
|
665
|
+
layout_key = _resolve_figure_layout_key(
|
|
666
|
+
dataset,
|
|
667
|
+
workspace.ui.active_layout_key,
|
|
668
|
+
args.layout,
|
|
669
|
+
)
|
|
670
|
+
|
|
671
|
+
layout_view = workspace.ui.layout_views.get(layout_key)
|
|
672
|
+
camera = layout_view.camera_3d if layout_view is not None else None
|
|
673
|
+
view = OrbitViewState3D(**camera) if camera is not None else None
|
|
674
|
+
|
|
675
|
+
options = FigureRenderOptions(
|
|
676
|
+
width=args.width,
|
|
677
|
+
height=args.height,
|
|
678
|
+
scale=args.scale,
|
|
679
|
+
theme=args.theme,
|
|
680
|
+
background=args.background,
|
|
681
|
+
point_radius=args.point_radius,
|
|
682
|
+
show_guide=not args.no_guide,
|
|
683
|
+
guide_style=args.guide_style,
|
|
684
|
+
guide_alpha=args.guide_alpha,
|
|
685
|
+
legend=args.legend,
|
|
686
|
+
title=args.title,
|
|
687
|
+
selected_ids=set(workspace.ui.selected_ids) if args.show_selection and not args.ignore_selection else set(),
|
|
688
|
+
)
|
|
689
|
+
try:
|
|
690
|
+
result = render_layout_figure(
|
|
691
|
+
dataset=dataset,
|
|
692
|
+
layout_key=layout_key,
|
|
693
|
+
output_path=args.output,
|
|
694
|
+
view=view,
|
|
695
|
+
options=options,
|
|
696
|
+
)
|
|
697
|
+
except ValueError as exc:
|
|
698
|
+
raise SystemExit(str(exc)) from None
|
|
699
|
+
|
|
700
|
+
payload = {"figure": result.to_dict()}
|
|
701
|
+
if args.json:
|
|
702
|
+
_print_output(payload, as_json=True)
|
|
703
|
+
return
|
|
704
|
+
print(f"Wrote {result.output_path} ({result.width}x{result.height}, {result.num_points} points)")
|
|
705
|
+
|
|
706
|
+
|
|
601
707
|
def _run_ui_command(args: argparse.Namespace) -> None:
|
|
602
708
|
base_url = _server_base_url(args.host, args.port)
|
|
603
709
|
if args.ui_command == "workspace" and args.ui_workspace_command == "set":
|
|
@@ -780,6 +886,9 @@ def main(argv: list[str] | None = None):
|
|
|
780
886
|
if args.command == "jobs":
|
|
781
887
|
_run_jobs_command(args)
|
|
782
888
|
return
|
|
889
|
+
if args.command == "figure":
|
|
890
|
+
_run_figure_command(args)
|
|
891
|
+
return
|
|
783
892
|
if args.command == "ui":
|
|
784
893
|
_run_ui_command(args)
|
|
785
894
|
return
|
|
@@ -236,6 +236,26 @@ def _project_points_3d_to_screen(
|
|
|
236
236
|
return screen_x, screen_y, depth, pixel_index
|
|
237
237
|
|
|
238
238
|
|
|
239
|
+
def build_mvp_for_orbit(
|
|
240
|
+
view: OrbitViewState3D,
|
|
241
|
+
coords: np.ndarray,
|
|
242
|
+
viewport_width: int,
|
|
243
|
+
viewport_height: int,
|
|
244
|
+
) -> np.ndarray:
|
|
245
|
+
"""Build an orbit-camera MVP matrix matching the 3D scatter renderer."""
|
|
246
|
+
return _build_mvp_for_orbit(view, coords, viewport_width, viewport_height)
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
def project_points_3d_to_screen(
|
|
250
|
+
mvp: np.ndarray,
|
|
251
|
+
coords: np.ndarray,
|
|
252
|
+
width: int,
|
|
253
|
+
height: int,
|
|
254
|
+
) -> tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray]:
|
|
255
|
+
"""Project 3D points to screen coordinates using scatter renderer math."""
|
|
256
|
+
return _project_points_3d_to_screen(mvp, coords, width, height)
|
|
257
|
+
|
|
258
|
+
|
|
239
259
|
def select_ids_for_3d_lasso(
|
|
240
260
|
*,
|
|
241
261
|
ids: list[str],
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"""Static figure export helpers for HyperView."""
|
|
2
|
+
|
|
3
|
+
from hyperview.figures.render import (
|
|
4
|
+
FigureExportResult,
|
|
5
|
+
FigureRenderOptions,
|
|
6
|
+
render_layout_figure,
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
__all__ = [
|
|
10
|
+
"FigureExportResult",
|
|
11
|
+
"FigureRenderOptions",
|
|
12
|
+
"render_layout_figure",
|
|
13
|
+
]
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
"""Deterministic categorical colors shared by static figure export."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import colorsys
|
|
6
|
+
|
|
7
|
+
MISSING_LABEL_SENTINEL = "undefined"
|
|
8
|
+
MISSING_LABEL_COLOR = "#39d3cc"
|
|
9
|
+
FALLBACK_LABEL_COLOR = "#8b949e"
|
|
10
|
+
|
|
11
|
+
TAB_20_LABEL_PALETTE = [
|
|
12
|
+
"#0072b2",
|
|
13
|
+
"#e69f00",
|
|
14
|
+
"#009e73",
|
|
15
|
+
"#d55e00",
|
|
16
|
+
"#cc79a7",
|
|
17
|
+
"#56b4e9",
|
|
18
|
+
"#000000",
|
|
19
|
+
"#7f7f7f",
|
|
20
|
+
"#332288",
|
|
21
|
+
"#88ccee",
|
|
22
|
+
"#44aa99",
|
|
23
|
+
"#117733",
|
|
24
|
+
"#999933",
|
|
25
|
+
"#ddcc77",
|
|
26
|
+
"#cc6677",
|
|
27
|
+
"#882255",
|
|
28
|
+
"#aa4499",
|
|
29
|
+
"#6699cc",
|
|
30
|
+
"#661100",
|
|
31
|
+
"#888888",
|
|
32
|
+
]
|
|
33
|
+
|
|
34
|
+
OVERFLOW_HUE_STEP_DEGREES = 137.508
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def normalize_label(label: str | None) -> str:
|
|
38
|
+
return label if label else MISSING_LABEL_SENTINEL
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def _stable_label_sort_key(label: str) -> tuple[int, str]:
|
|
42
|
+
return (1, label) if label == MISSING_LABEL_SENTINEL else (0, label)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def _overflow_color(index: int) -> str:
|
|
46
|
+
hue = (43.0 + index * OVERFLOW_HUE_STEP_DEGREES) % 360.0
|
|
47
|
+
saturation = [0.72, 0.64, 0.78][index % 3]
|
|
48
|
+
lightness = [0.46, 0.54, 0.38, 0.62][(index // 3) % 4]
|
|
49
|
+
r, g, b = colorsys.hls_to_rgb(hue / 360.0, lightness, saturation)
|
|
50
|
+
return f"#{round(r * 255):02x}{round(g * 255):02x}{round(b * 255):02x}"
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def create_label_color_map(labels: list[str | None]) -> dict[str, str]:
|
|
54
|
+
unique = sorted({normalize_label(label) for label in labels}, key=_stable_label_sort_key)
|
|
55
|
+
colors: dict[str, str] = {}
|
|
56
|
+
used: set[str] = set()
|
|
57
|
+
non_missing_index = 0
|
|
58
|
+
overflow_index = 0
|
|
59
|
+
|
|
60
|
+
for label in unique:
|
|
61
|
+
if label == MISSING_LABEL_SENTINEL:
|
|
62
|
+
colors[label] = MISSING_LABEL_COLOR
|
|
63
|
+
used.add(MISSING_LABEL_COLOR.lower())
|
|
64
|
+
continue
|
|
65
|
+
|
|
66
|
+
if non_missing_index < len(TAB_20_LABEL_PALETTE):
|
|
67
|
+
candidate = TAB_20_LABEL_PALETTE[non_missing_index]
|
|
68
|
+
else:
|
|
69
|
+
candidate = _overflow_color(overflow_index)
|
|
70
|
+
|
|
71
|
+
safety = 0
|
|
72
|
+
while candidate.lower() in used and safety < 2048:
|
|
73
|
+
overflow_index += 1
|
|
74
|
+
candidate = _overflow_color(overflow_index)
|
|
75
|
+
safety += 1
|
|
76
|
+
|
|
77
|
+
if non_missing_index >= len(TAB_20_LABEL_PALETTE):
|
|
78
|
+
overflow_index += 1
|
|
79
|
+
|
|
80
|
+
if candidate.lower() in used:
|
|
81
|
+
candidate = FALLBACK_LABEL_COLOR
|
|
82
|
+
|
|
83
|
+
colors[label] = candidate
|
|
84
|
+
used.add(candidate.lower())
|
|
85
|
+
non_missing_index += 1
|
|
86
|
+
|
|
87
|
+
return colors
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def hex_to_rgba(color: str, alpha: int = 255) -> tuple[int, int, int, int]:
|
|
91
|
+
raw = color.strip()
|
|
92
|
+
if raw.startswith("#"):
|
|
93
|
+
raw = raw[1:]
|
|
94
|
+
if len(raw) == 3:
|
|
95
|
+
raw = "".join(ch * 2 for ch in raw)
|
|
96
|
+
if len(raw) not in {6, 8}:
|
|
97
|
+
return 255, 255, 255, alpha
|
|
98
|
+
r = int(raw[0:2], 16)
|
|
99
|
+
g = int(raw[2:4], 16)
|
|
100
|
+
b = int(raw[4:6], 16)
|
|
101
|
+
a = int(raw[6:8], 16) if len(raw) == 8 else alpha
|
|
102
|
+
return r, g, b, a
|