ply-visualizer 0.1.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.
- ply_visualizer-0.1.0/LICENSE +21 -0
- ply_visualizer-0.1.0/PKG-INFO +376 -0
- ply_visualizer-0.1.0/README.md +360 -0
- ply_visualizer-0.1.0/ply_visualizer/__init__.py +4 -0
- ply_visualizer-0.1.0/ply_visualizer/__main__.py +24 -0
- ply_visualizer-0.1.0/ply_visualizer/_assets/292.bundle.js +2 -0
- ply_visualizer-0.1.0/ply_visualizer/_assets/292.bundle.js.map +1 -0
- ply_visualizer-0.1.0/ply_visualizer/_assets/31f44e750ca55f52a561.wasm +0 -0
- ply_visualizer-0.1.0/ply_visualizer/_assets/325.bundle.js +2 -0
- ply_visualizer-0.1.0/ply_visualizer/_assets/325.bundle.js.map +1 -0
- ply_visualizer-0.1.0/ply_visualizer/_assets/367.bundle.js +2 -0
- ply_visualizer-0.1.0/ply_visualizer/_assets/367.bundle.js.map +1 -0
- ply_visualizer-0.1.0/ply_visualizer/_assets/454.bundle.js +2 -0
- ply_visualizer-0.1.0/ply_visualizer/_assets/454.bundle.js.map +1 -0
- ply_visualizer-0.1.0/ply_visualizer/_assets/610.bundle.js +2 -0
- ply_visualizer-0.1.0/ply_visualizer/_assets/610.bundle.js.map +1 -0
- ply_visualizer-0.1.0/ply_visualizer/_assets/630.bundle.js +3 -0
- ply_visualizer-0.1.0/ply_visualizer/_assets/630.bundle.js.LICENSE.txt +5 -0
- ply_visualizer-0.1.0/ply_visualizer/_assets/630.bundle.js.map +1 -0
- ply_visualizer-0.1.0/ply_visualizer/_assets/702.bundle.js +2 -0
- ply_visualizer-0.1.0/ply_visualizer/_assets/702.bundle.js.map +1 -0
- ply_visualizer-0.1.0/ply_visualizer/_assets/962.bundle.js +2 -0
- ply_visualizer-0.1.0/ply_visualizer/_assets/962.bundle.js.map +1 -0
- ply_visualizer-0.1.0/ply_visualizer/_assets/apple-touch-icon.png +0 -0
- ply_visualizer-0.1.0/ply_visualizer/_assets/bundle.css +601 -0
- ply_visualizer-0.1.0/ply_visualizer/_assets/bundle.css.map +1 -0
- ply_visualizer-0.1.0/ply_visualizer/_assets/bundle.js +3 -0
- ply_visualizer-0.1.0/ply_visualizer/_assets/bundle.js.LICENSE.txt +7 -0
- ply_visualizer-0.1.0/ply_visualizer/_assets/bundle.js.map +1 -0
- ply_visualizer-0.1.0/ply_visualizer/_assets/examples/camera-path-2026-08-27-14-27-47.json +50 -0
- ply_visualizer-0.1.0/ply_visualizer/_assets/examples/example-point-cloud.ply +245080 -0
- ply_visualizer-0.1.0/ply_visualizer/_assets/examples/measurement-paths-2026-08-27-15-49-45.json +19 -0
- ply_visualizer-0.1.0/ply_visualizer/_assets/index.html +298 -0
- ply_visualizer-0.1.0/ply_visualizer/_assets/manifest.webmanifest +26 -0
- ply_visualizer-0.1.0/ply_visualizer/_assets/media/icons/measurement/clear.svg +4 -0
- ply_visualizer-0.1.0/ply_visualizer/_assets/media/icons/measurement/loop.svg +7 -0
- ply_visualizer-0.1.0/ply_visualizer/_assets/media/icons/measurement/measure.svg +9 -0
- ply_visualizer-0.1.0/ply_visualizer/_assets/media/icons/measurement/new-free.svg +4 -0
- ply_visualizer-0.1.0/ply_visualizer/_assets/media/icons/measurement/undo.svg +6 -0
- ply_visualizer-0.1.0/ply_visualizer/_assets/media/ply-icon.png +0 -0
- ply_visualizer-0.1.0/ply_visualizer/_assets/media/style.css +1312 -0
- ply_visualizer-0.1.0/ply_visualizer/_assets/media/tiff-icon.png +0 -0
- ply_visualizer-0.1.0/ply_visualizer/_assets/media/wasm/tiff_wasm.js +1 -0
- ply_visualizer-0.1.0/ply_visualizer/_assets/media/wasm/tiff_wasm_bg.wasm +0 -0
- ply_visualizer-0.1.0/ply_visualizer/_assets/src/themes/README.md +91 -0
- ply_visualizer-0.1.0/ply_visualizer/_assets/src/themes/dark-modern.json +175 -0
- ply_visualizer-0.1.0/ply_visualizer/_assets/src/themes/light-modern.json +175 -0
- ply_visualizer-0.1.0/ply_visualizer/arrays.py +44 -0
- ply_visualizer-0.1.0/ply_visualizer/scenes.py +66 -0
- ply_visualizer-0.1.0/ply_visualizer/session.py +360 -0
- ply_visualizer-0.1.0/ply_visualizer/training.py +40 -0
- ply_visualizer-0.1.0/ply_visualizer.egg-info/PKG-INFO +376 -0
- ply_visualizer-0.1.0/ply_visualizer.egg-info/SOURCES.txt +62 -0
- ply_visualizer-0.1.0/ply_visualizer.egg-info/dependency_links.txt +1 -0
- ply_visualizer-0.1.0/ply_visualizer.egg-info/entry_points.txt +2 -0
- ply_visualizer-0.1.0/ply_visualizer.egg-info/requires.txt +3 -0
- ply_visualizer-0.1.0/ply_visualizer.egg-info/top_level.txt +1 -0
- ply_visualizer-0.1.0/pyproject.toml +29 -0
- ply_visualizer-0.1.0/setup.cfg +4 -0
- ply_visualizer-0.1.0/setup.py +16 -0
- ply_visualizer-0.1.0/tests/test_arrays.py +102 -0
- ply_visualizer-0.1.0/tests/test_notebook.py +54 -0
- ply_visualizer-0.1.0/tests/test_session.py +83 -0
- ply_visualizer-0.1.0/tests/test_training.py +77 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 3D Visualizer Extension
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,376 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: ply-visualizer
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Local 3D point cloud and mesh viewer for Python and the command line
|
|
5
|
+
Author: Florian Kleinicke
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://3d.f-kleinicke.de
|
|
8
|
+
Project-URL: Repository, https://github.com/kleinicke/ply-visualizer
|
|
9
|
+
Project-URL: Issues, https://github.com/kleinicke/ply-visualizer/issues
|
|
10
|
+
Requires-Python: >=3.10
|
|
11
|
+
Description-Content-Type: text/markdown
|
|
12
|
+
License-File: LICENSE
|
|
13
|
+
Provides-Extra: notebook
|
|
14
|
+
Requires-Dist: ipython>=8; extra == "notebook"
|
|
15
|
+
Dynamic: license-file
|
|
16
|
+
|
|
17
|
+
# Python and CLI preview — 3D viewer
|
|
18
|
+
|
|
19
|
+
One Python package provides a browser viewer for local 3D files and point
|
|
20
|
+
arrays, plus the `ply-viewer` command. Python 3.10+ and a WebGL-capable browser
|
|
21
|
+
are required. There are no Python runtime dependencies; NumPy arrays work
|
|
22
|
+
without requiring NumPy for users who only open files. Node.js is needed only to
|
|
23
|
+
build the bundled viewer from this repository, not to use an installed wheel.
|
|
24
|
+
|
|
25
|
+
Install the Python package from PyPI as **`ply-visualizer`**. The npm package is
|
|
26
|
+
not published.
|
|
27
|
+
|
|
28
|
+
## Install with uv (recommended)
|
|
29
|
+
|
|
30
|
+
Install [uv](https://docs.astral.sh/uv/getting-started/installation/) first. For
|
|
31
|
+
source development, use this repository or a locally built wheel. From the
|
|
32
|
+
repository root, build the browser assets using Node 24:
|
|
33
|
+
|
|
34
|
+
```sh
|
|
35
|
+
npm ci
|
|
36
|
+
npm run build:python-viewer
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### CLI only
|
|
40
|
+
|
|
41
|
+
For occasional use, run the local package in an isolated tool environment:
|
|
42
|
+
|
|
43
|
+
```sh
|
|
44
|
+
uvx --from ./packages/python ply-viewer engine/examples/example-point-cloud.ply
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
For regular use, install its command persistently:
|
|
48
|
+
|
|
49
|
+
```sh
|
|
50
|
+
uv tool install ./packages/python
|
|
51
|
+
ply-viewer scan.ply
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
If uv reports that its executable directory is missing from PATH, run
|
|
55
|
+
`uv tool update-shell` and restart your shell. Tool installation makes the CLI
|
|
56
|
+
available, but does not add `ply_visualizer` to your Python project or notebook
|
|
57
|
+
kernel. [uv tools guide](https://docs.astral.sh/uv/guides/tools/).
|
|
58
|
+
|
|
59
|
+
### Python and local Jupyter notebooks
|
|
60
|
+
|
|
61
|
+
For an existing uv-managed Python project, add the built local package from that
|
|
62
|
+
project's directory (replace the path with your checkout location):
|
|
63
|
+
|
|
64
|
+
```sh
|
|
65
|
+
uv add /absolute/path/to/ply-visualizer/packages/python
|
|
66
|
+
uv run --with jupyter jupyter lab
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Choose the kernel using that project's environment. Then a notebook cell can run
|
|
70
|
+
`from ply_visualizer import show`. The viewer opens in a separate browser tab;
|
|
71
|
+
keep the kernel running. NumPy and PyTorch stay optional: use the versions
|
|
72
|
+
already installed in your project, or add them as needed.
|
|
73
|
+
[uv Jupyter guide](https://docs.astral.sh/uv/guides/integration/jupyter/).
|
|
74
|
+
|
|
75
|
+
For a virtual environment without uv project management, from this repository:
|
|
76
|
+
|
|
77
|
+
```sh
|
|
78
|
+
# Create this environment only if it does not already exist.
|
|
79
|
+
uv venv packages/python/.venv
|
|
80
|
+
uv pip install --python packages/python/.venv ./packages/python
|
|
81
|
+
packages/python/.venv/bin/ply-viewer engine/examples/example-point-cloud.ply
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
For notebooks in that environment, install JupyterLab into the same environment
|
|
85
|
+
and launch it directly:
|
|
86
|
+
|
|
87
|
+
```sh
|
|
88
|
+
uv pip install --python packages/python/.venv jupyterlab
|
|
89
|
+
packages/python/.venv/bin/jupyter lab
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### Installing a wheel
|
|
93
|
+
|
|
94
|
+
A wheel already contains the viewer assets and needs no Node.js build:
|
|
95
|
+
|
|
96
|
+
```sh
|
|
97
|
+
# CLI only:
|
|
98
|
+
uv tool install /path/to/ply_visualizer-0.1.0-py3-none-any.whl
|
|
99
|
+
# Or, from a uv-managed Python project:
|
|
100
|
+
uv add /path/to/ply_visualizer-0.1.0-py3-none-any.whl
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### Public PyPI installation
|
|
104
|
+
|
|
105
|
+
The public package name is **`ply-visualizer`**:
|
|
106
|
+
|
|
107
|
+
```sh
|
|
108
|
+
uv add ply-visualizer # Python project
|
|
109
|
+
uv add "ply-visualizer[notebook]" # Notebook display support
|
|
110
|
+
uv pip install ply-visualizer # Existing virtual environment
|
|
111
|
+
uv tool install ply-visualizer # Isolated CLI installation
|
|
112
|
+
uvx --from ply-visualizer ply-viewer scan.ply
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
The Python import remains `from ply_visualizer import show`. See
|
|
116
|
+
[publishing setup](PUBLISHING.md) for the release workflow.
|
|
117
|
+
|
|
118
|
+
## Alternative: install with pip from this repository
|
|
119
|
+
|
|
120
|
+
After building the browser assets above:
|
|
121
|
+
|
|
122
|
+
```sh
|
|
123
|
+
python3 -m venv packages/python/.venv
|
|
124
|
+
packages/python/.venv/bin/python -m pip install ./packages/python
|
|
125
|
+
packages/python/.venv/bin/ply-viewer engine/examples/example-point-cloud.ply
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
On Windows, replace the environment's `bin/` paths with `Scripts/`, e.g.
|
|
129
|
+
`packages\python\.venv\Scripts\python.exe`, `ply-viewer.exe`, or `jupyter.exe`.
|
|
130
|
+
After activating the environment, the command is simply:
|
|
131
|
+
|
|
132
|
+
```sh
|
|
133
|
+
ply-viewer scan.ply mesh.stl
|
|
134
|
+
ply-viewer --no-browser scan.ply
|
|
135
|
+
python -m ply_visualizer scan.ply
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
The command prints a local URL and keeps running until Ctrl+C. `--no-browser`
|
|
139
|
+
allows an agent or another application to open that URL itself. It does not
|
|
140
|
+
render an image or report successful browser rendering to the caller.
|
|
141
|
+
|
|
142
|
+
## Python
|
|
143
|
+
|
|
144
|
+
```python
|
|
145
|
+
from ply_visualizer import show
|
|
146
|
+
|
|
147
|
+
# In an interactive Python session or local notebook:
|
|
148
|
+
viewer = show("scan.ply", "mesh.stl")
|
|
149
|
+
print(viewer.url)
|
|
150
|
+
# Later:
|
|
151
|
+
viewer.close()
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
```python
|
|
155
|
+
from ply_visualizer import show
|
|
156
|
+
|
|
157
|
+
# Lists, iterables, NumPy arrays, and PyTorch tensors with shape (N, 3) work.
|
|
158
|
+
points = [[0, 0, 0], [1, 0, 0], [0, 1, 0]]
|
|
159
|
+
colors = [[255, 0, 0], [0, 255, 0], [0, 0, 255]]
|
|
160
|
+
|
|
161
|
+
# In a script, keep Python alive while the viewer is in use.
|
|
162
|
+
with show(points, colors=colors) as viewer:
|
|
163
|
+
print(viewer.url)
|
|
164
|
+
try:
|
|
165
|
+
viewer.wait()
|
|
166
|
+
except KeyboardInterrupt:
|
|
167
|
+
pass
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
Coordinates must be finite float32-compatible numbers. Optional colors must
|
|
171
|
+
match the point count and contain integer RGB values in 0..255. Point arrays are
|
|
172
|
+
serialized to a temporary binary PLY, decoded by the existing engine, and
|
|
173
|
+
removed when the session closes. This first implementation serializes arrays row
|
|
174
|
+
by row; it is not a zero-copy transport for very large arrays.
|
|
175
|
+
|
|
176
|
+
## NumPy and PyTorch
|
|
177
|
+
|
|
178
|
+
Pass arrays and tensors directly, including RGB colors:
|
|
179
|
+
|
|
180
|
+
```python
|
|
181
|
+
import numpy as np
|
|
182
|
+
from ply_visualizer import show
|
|
183
|
+
|
|
184
|
+
viewer = show(np.random.default_rng(0).normal(size=(1000, 3)))
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
```python
|
|
188
|
+
import torch
|
|
189
|
+
from ply_visualizer import show
|
|
190
|
+
|
|
191
|
+
device = "cuda" if torch.cuda.is_available() else (
|
|
192
|
+
"mps" if torch.backends.mps.is_available() else "cpu"
|
|
193
|
+
)
|
|
194
|
+
points = torch.randn(1000, 3, device=device, requires_grad=True)
|
|
195
|
+
rgb = torch.randint(0, 256, (1000, 3), device=device, dtype=torch.uint8)
|
|
196
|
+
viewer = show(points, colors=rgb)
|
|
197
|
+
# No manual .detach(), .cpu(), or .numpy() needed.
|
|
198
|
+
# Keep Python alive and call viewer.close() when finished.
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
- NumPy arrays can be transposed, sliced, read-only, or non-contiguous.
|
|
202
|
+
- PyTorch inputs can be CPU or GPU tensors, detached or attached to autograd.
|
|
203
|
+
Both coordinates and colors are handled independently, so mixing devices or
|
|
204
|
+
NumPy/PyTorch inputs works. Float16 and bfloat16 tensors are supported.
|
|
205
|
+
- Visualization detaches internally, transfers to CPU, and serializes a
|
|
206
|
+
snapshot. The original device, values, `requires_grad`, and autograd graph are
|
|
207
|
+
unchanged. GPU-to-CPU transfer synchronizes; avoid calling this every training
|
|
208
|
+
step.
|
|
209
|
+
- PyTorch conversion does not depend on NumPy. CPU rows are converted in bounded
|
|
210
|
+
chunks rather than performing a GPU scalar read for every coordinate.
|
|
211
|
+
- Inputs must be real, dense `(N, 3)` data. For `(B, N, 3)` batches, use
|
|
212
|
+
`show(batch[0])`; batches are deliberately not flattened automatically.
|
|
213
|
+
Sparse, quantized, complex, nested, and data-free meta tensors are rejected
|
|
214
|
+
with an error. RGB retains the integer-valued 0..255 convention, including
|
|
215
|
+
floating-point tensors; normalized RGB can be passed as `(rgb * 255).round()`.
|
|
216
|
+
|
|
217
|
+
## Training previews
|
|
218
|
+
|
|
219
|
+
All updates reuse the same browser tab/inline view and preserve its camera. The
|
|
220
|
+
viewer polls for the newest revision every 500 ms; intermediate revisions can be
|
|
221
|
+
skipped. Publish at a useful training interval, not every forward pass.
|
|
222
|
+
Serialization and GPU transfer are synchronous. Updates replace the scene;
|
|
223
|
+
manual files added to that scene are also replaced on the next update.
|
|
224
|
+
|
|
225
|
+
```python
|
|
226
|
+
viewer = show(initial_points)
|
|
227
|
+
|
|
228
|
+
# In your training loop, e.g. every 100 steps:
|
|
229
|
+
if step % 100 == 0:
|
|
230
|
+
viewer.update(prediction[0], target=target[0], step=step)
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
Prediction is orange and target cyan. Supply `colors=` to override prediction
|
|
234
|
+
RGB. Targets may have a different number of points. This is a geometric overlay,
|
|
235
|
+
not a computed nearest-neighbor error metric. Visibility can be toggled in the
|
|
236
|
+
standard file panel. Use **Pause updates** to inspect one revision and **Fit
|
|
237
|
+
scene** to reset the framing explicitly.
|
|
238
|
+
|
|
239
|
+
### Batch and augmentation inspection
|
|
240
|
+
|
|
241
|
+
```python
|
|
242
|
+
from ply_visualizer import show_batch
|
|
243
|
+
|
|
244
|
+
viewer = show_batch(batch, target=target_batch)
|
|
245
|
+
viewer.update_batch(next_batch, target=next_targets, step=step)
|
|
246
|
+
|
|
247
|
+
# A list of differently sized point arrays also works:
|
|
248
|
+
viewer = show_batch([original, augmented], labels=["Original", "Augmented"])
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
The sample selector switches batches in one scene and retains the camera.
|
|
252
|
+
Colors, targets, and vectors (when supplied) must match the batch size. Batch
|
|
253
|
+
snapshots serialize every sample; select a small inspection subset for large
|
|
254
|
+
training batches. Only the chosen sample is loaded by the browser.
|
|
255
|
+
|
|
256
|
+
### Gradient and displacement arrows
|
|
257
|
+
|
|
258
|
+
```python
|
|
259
|
+
# After loss.backward(); non-leaf predictions need retain_grad() beforehand.
|
|
260
|
+
viewer.update(
|
|
261
|
+
points,
|
|
262
|
+
vectors=points.grad,
|
|
263
|
+
vector_scale=-learning_rate,
|
|
264
|
+
max_vectors=256,
|
|
265
|
+
step=step,
|
|
266
|
+
)
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
Arrows are anchored at the corresponding input points. Negative learning-rate
|
|
270
|
+
scaling shows a plain gradient-descent direction; it is not an exact Adam or
|
|
271
|
+
momentum optimizer step. To inspect the actual update, pass measured coordinate
|
|
272
|
+
displacements instead. Nonzero arrows are magenta. Up to `max_vectors` evenly
|
|
273
|
+
spaced vectors are displayed (default 256, maximum 2000). All supplied vector
|
|
274
|
+
rows are validated; no autograd hooks or gradient computation are installed by
|
|
275
|
+
this operation.
|
|
276
|
+
|
|
277
|
+
### Layer inspection with a removable forward hook
|
|
278
|
+
|
|
279
|
+
```python
|
|
280
|
+
viewer = show(initial_points)
|
|
281
|
+
with viewer.inspect_layer(model, select=lambda output: output[0], every=100):
|
|
282
|
+
train(model)
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
For dictionary outputs use a selector such as
|
|
286
|
+
`lambda output: output["points"][0]`. The selector must return `(N, 3)`
|
|
287
|
+
coordinates, not arbitrary feature channels. The hook captures the first forward
|
|
288
|
+
call and then every `every` calls. It returns `None`, preserving the model's
|
|
289
|
+
output. A visualization error disables the hook, emits a warning and is
|
|
290
|
+
accessible as `inspection.error`; it does not invalidate training. The context
|
|
291
|
+
manager removes the hook, while the caller owns the viewer session's lifetime.
|
|
292
|
+
`inspection.close()` also removes it explicitly.
|
|
293
|
+
|
|
294
|
+
Run viewer updates in the main process, on one rank in distributed training, and
|
|
295
|
+
outside compiled model code. GPU-to-CPU transfer introduces synchronization.
|
|
296
|
+
[PyTorch forward hooks](https://docs.pytorch.org/docs/stable/generated/torch.nn.Module.html#torch.nn.Module.register_forward_hook).
|
|
297
|
+
|
|
298
|
+
The server binds only to `127.0.0.1`, uses a random session URL, and serves only
|
|
299
|
+
the explicitly supplied files and bundled viewer assets. Source files remain on
|
|
300
|
+
your machine; the package does not upload them. Keep file paths available for
|
|
301
|
+
the life of the session. Do not share the session URL with untrusted code.
|
|
302
|
+
|
|
303
|
+
## Inline Jupyter notebooks
|
|
304
|
+
|
|
305
|
+
In a **local** Jupyter notebook, return the viewer as the last expression in a
|
|
306
|
+
cell. Browser auto-opening is disabled when a notebook kernel is detected:
|
|
307
|
+
|
|
308
|
+
```python
|
|
309
|
+
viewer = show(points)
|
|
310
|
+
viewer # Interactive viewer appears in the output cell.
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
Or display explicitly, using the notebook extra:
|
|
314
|
+
|
|
315
|
+
```python
|
|
316
|
+
viewer.display(height=480, ui="collapsed")
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
Settings are collapsed by default. A compact toolbar keeps **Settings**, **Fit
|
|
320
|
+
scene**, **Pause updates**, and the batch selector accessible. Choose
|
|
321
|
+
`ui="full"` to show settings immediately or `ui="none"` for a presentation-only
|
|
322
|
+
canvas with mouse controls. In UI-free mode, batch selection is unavailable;
|
|
323
|
+
choose the sample in Python before displaying it.
|
|
324
|
+
|
|
325
|
+
`viewer.update(...)` updates every open view, including notebook output. Keep
|
|
326
|
+
the kernel running, call `viewer.close()` when done, and do not call
|
|
327
|
+
`viewer.wait()` in a cell. Notebook output contains a live local iframe, not an
|
|
328
|
+
offline saved scene. Reopen the session after restarting the kernel.
|
|
329
|
+
|
|
330
|
+
This initial inline transport requires the browser and kernel on the same
|
|
331
|
+
machine and a notebook host that permits local iframes. Remote Jupyter, Colab,
|
|
332
|
+
and notebook environments that block local iframe URLs need a widget/proxy
|
|
333
|
+
transport; they are not supported by this transport yet.
|
|
334
|
+
|
|
335
|
+
For a mature widget-based alternative, [K3D](https://k3d-jupyter.org/) supports
|
|
336
|
+
notebook point clouds and other 3D primitives.
|
|
337
|
+
[Rerun](https://rerun.io/examples/feature-showcase/notebook_viewer) is worth
|
|
338
|
+
considering for recorded, time-based diagnostics. This package embeds the
|
|
339
|
+
existing 3D viewer to retain its file formats and interaction controls.
|
|
340
|
+
|
|
341
|
+
## Current scope
|
|
342
|
+
|
|
343
|
+
- Supported inputs: PLY, XYZ, XYZN, XYZRGB, PCD, PTS, OBJ, STL, OFF, GLB,
|
|
344
|
+
LAS/LAZ, E57, SPZ, SPLAT, KSPLAT, and SOG.
|
|
345
|
+
- Multiple files appear together in one scene.
|
|
346
|
+
- OBJ input currently provides geometry; automatic sidecar material/texture
|
|
347
|
+
resolution and external-resource glTF are outside this preview.
|
|
348
|
+
- No separate image-viewer integration, MCP tools, headless capture, or desktop
|
|
349
|
+
launch integration yet. The shared 3D viewer retains its existing manual
|
|
350
|
+
controls and depth-conversion features.
|
|
351
|
+
|
|
352
|
+
## Build a distributable wheel
|
|
353
|
+
|
|
354
|
+
```sh
|
|
355
|
+
npm run build:python-viewer
|
|
356
|
+
packages/python/.venv/bin/python -m pip wheel --no-deps ./packages/python --wheel-dir /tmp/ply-viewer-wheels
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
The wheel includes the browser engine and its assets. Install that wheel on
|
|
360
|
+
another machine with `python -m pip install /path/to/the.whl`; no Node.js or
|
|
361
|
+
Tauri installation is necessary there. Build assets before packaging.
|
|
362
|
+
|
|
363
|
+
## Verify
|
|
364
|
+
|
|
365
|
+
```sh
|
|
366
|
+
npm run test:python-viewer
|
|
367
|
+
# Also test actual NumPy/PyTorch inputs in the isolated environment:
|
|
368
|
+
packages/python/.venv/bin/python -m pip install numpy torch
|
|
369
|
+
packages/python/.venv/bin/python -m unittest discover -s packages/python/tests -v
|
|
370
|
+
cd engine
|
|
371
|
+
npx playwright test local-session.spec.ts --reporter=line
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
The browser test requires `npm run build:python-viewer` and the existing engine
|
|
375
|
+
test server assets in `engine/dist` (`npm run build --workspace=engine`). Array
|
|
376
|
+
tests skip optional libraries and GPU backends that are unavailable.
|