arrayview 0.45.1__tar.gz → 0.46.1__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.
- {arrayview-0.45.1 → arrayview-0.46.1}/PKG-INFO +1 -14
- {arrayview-0.45.1 → arrayview-0.46.1}/README.md +0 -13
- {arrayview-0.45.1 → arrayview-0.46.1}/pyproject.toml +1 -1
- {arrayview-0.45.1 → arrayview-0.46.1}/src/arrayview/_analysis.py +4 -0
- {arrayview-0.45.1 → arrayview-0.46.1}/src/arrayview/_io.py +37 -5
- {arrayview-0.45.1 → arrayview-0.46.1}/src/arrayview/_launcher.py +15 -4
- {arrayview-0.45.1 → arrayview-0.46.1}/src/arrayview/_routes_loading.py +38 -14
- {arrayview-0.45.1 → arrayview-0.46.1}/src/arrayview/_viewer.html +1981 -415
- {arrayview-0.45.1 → arrayview-0.46.1}/src/arrayview/_vscode_extension.py +1 -1
- arrayview-0.46.1/src/arrayview/arrayview-opener.vsix +0 -0
- {arrayview-0.45.1 → arrayview-0.46.1}/tests/test_browser.py +81 -8
- {arrayview-0.45.1 → arrayview-0.46.1}/tests/test_mode_consistency.py +141 -0
- {arrayview-0.45.1 → arrayview-0.46.1}/tests/test_mode_roundtrip.py +9 -22
- arrayview-0.46.1/tests/test_tunnel_warm_path.py +160 -0
- arrayview-0.45.1/src/arrayview/arrayview-opener.vsix +0 -0
- {arrayview-0.45.1 → arrayview-0.46.1}/.gitignore +0 -0
- {arrayview-0.45.1 → arrayview-0.46.1}/LICENSE +0 -0
- {arrayview-0.45.1 → arrayview-0.46.1}/src/arrayview/ARCHITECTURE.md +0 -0
- {arrayview-0.45.1 → arrayview-0.46.1}/src/arrayview/__init__.py +0 -0
- {arrayview-0.45.1 → arrayview-0.46.1}/src/arrayview/__main__.py +0 -0
- {arrayview-0.45.1 → arrayview-0.46.1}/src/arrayview/_app.py +0 -0
- {arrayview-0.45.1 → arrayview-0.46.1}/src/arrayview/_bootstrap_app.py +0 -0
- {arrayview-0.45.1 → arrayview-0.46.1}/src/arrayview/_config.py +0 -0
- {arrayview-0.45.1 → arrayview-0.46.1}/src/arrayview/_diagnostics.py +0 -0
- {arrayview-0.45.1 → arrayview-0.46.1}/src/arrayview/_dicom.py +0 -0
- {arrayview-0.45.1 → arrayview-0.46.1}/src/arrayview/_diff.py +0 -0
- {arrayview-0.45.1 → arrayview-0.46.1}/src/arrayview/_extra_ports.py +0 -0
- {arrayview-0.45.1 → arrayview-0.46.1}/src/arrayview/_icon.png +0 -0
- {arrayview-0.45.1 → arrayview-0.46.1}/src/arrayview/_imaging.py +0 -0
- {arrayview-0.45.1 → arrayview-0.46.1}/src/arrayview/_instance_registry.py +0 -0
- {arrayview-0.45.1 → arrayview-0.46.1}/src/arrayview/_launch_plan.py +0 -0
- {arrayview-0.45.1 → arrayview-0.46.1}/src/arrayview/_launch_trace.py +0 -0
- {arrayview-0.45.1 → arrayview-0.46.1}/src/arrayview/_lifecycle.py +0 -0
- {arrayview-0.45.1 → arrayview-0.46.1}/src/arrayview/_overlays.py +0 -0
- {arrayview-0.45.1 → arrayview-0.46.1}/src/arrayview/_platform.py +0 -0
- {arrayview-0.45.1 → arrayview-0.46.1}/src/arrayview/_render.py +0 -0
- {arrayview-0.45.1 → arrayview-0.46.1}/src/arrayview/_routes_analysis.py +0 -0
- {arrayview-0.45.1 → arrayview-0.46.1}/src/arrayview/_routes_drop.py +0 -0
- {arrayview-0.45.1 → arrayview-0.46.1}/src/arrayview/_routes_export.py +0 -0
- {arrayview-0.45.1 → arrayview-0.46.1}/src/arrayview/_routes_persistence.py +0 -0
- {arrayview-0.45.1 → arrayview-0.46.1}/src/arrayview/_routes_preferences.py +0 -0
- {arrayview-0.45.1 → arrayview-0.46.1}/src/arrayview/_routes_preload.py +0 -0
- {arrayview-0.45.1 → arrayview-0.46.1}/src/arrayview/_routes_query.py +0 -0
- {arrayview-0.45.1 → arrayview-0.46.1}/src/arrayview/_routes_rendering.py +0 -0
- {arrayview-0.45.1 → arrayview-0.46.1}/src/arrayview/_routes_segmentation.py +0 -0
- {arrayview-0.45.1 → arrayview-0.46.1}/src/arrayview/_routes_state.py +0 -0
- {arrayview-0.45.1 → arrayview-0.46.1}/src/arrayview/_routes_vectorfield.py +0 -0
- {arrayview-0.45.1 → arrayview-0.46.1}/src/arrayview/_routes_websocket.py +0 -0
- {arrayview-0.45.1 → arrayview-0.46.1}/src/arrayview/_segmentation.py +0 -0
- {arrayview-0.45.1 → arrayview-0.46.1}/src/arrayview/_server.py +0 -0
- {arrayview-0.45.1 → arrayview-0.46.1}/src/arrayview/_session.py +0 -0
- {arrayview-0.45.1 → arrayview-0.46.1}/src/arrayview/_session_spec.py +0 -0
- {arrayview-0.45.1 → arrayview-0.46.1}/src/arrayview/_shell.html +0 -0
- {arrayview-0.45.1 → arrayview-0.46.1}/src/arrayview/_source_safety.py +0 -0
- {arrayview-0.45.1 → arrayview-0.46.1}/src/arrayview/_synthetic_mri.py +0 -0
- {arrayview-0.45.1 → arrayview-0.46.1}/src/arrayview/_torch.py +0 -0
- {arrayview-0.45.1 → arrayview-0.46.1}/src/arrayview/_tutorial.py +0 -0
- {arrayview-0.45.1 → arrayview-0.46.1}/src/arrayview/_vectorfield.py +0 -0
- {arrayview-0.45.1 → arrayview-0.46.1}/src/arrayview/_vscode.py +0 -0
- {arrayview-0.45.1 → arrayview-0.46.1}/src/arrayview/_vscode_browser.py +0 -0
- {arrayview-0.45.1 → arrayview-0.46.1}/src/arrayview/_vscode_signal.py +0 -0
- {arrayview-0.45.1 → arrayview-0.46.1}/src/arrayview/_watch.py +0 -0
- {arrayview-0.45.1 → arrayview-0.46.1}/src/arrayview/gsap.min.js +0 -0
- {arrayview-0.45.1 → arrayview-0.46.1}/src/arrayview/todo.md +0 -0
- {arrayview-0.45.1 → arrayview-0.46.1}/tests/capture_patient_loading.py +0 -0
- {arrayview-0.45.1 → arrayview-0.46.1}/tests/capture_v_animation.py +0 -0
- {arrayview-0.45.1 → arrayview-0.46.1}/tests/conftest.py +0 -0
- {arrayview-0.45.1 → arrayview-0.46.1}/tests/lifecycle_matrix.py +0 -0
- {arrayview-0.45.1 → arrayview-0.46.1}/tests/make_vectorfield_test_arrays.py +0 -0
- {arrayview-0.45.1 → arrayview-0.46.1}/tests/test_1d_arrays.py +0 -0
- {arrayview-0.45.1 → arrayview-0.46.1}/tests/test_api.py +0 -0
- {arrayview-0.45.1 → arrayview-0.46.1}/tests/test_backend_shared.py +0 -0
- {arrayview-0.45.1 → arrayview-0.46.1}/tests/test_bootstrap_app.py +0 -0
- {arrayview-0.45.1 → arrayview-0.46.1}/tests/test_cli.py +0 -0
- {arrayview-0.45.1 → arrayview-0.46.1}/tests/test_colorbar_hover_highlight.py +0 -0
- {arrayview-0.45.1 → arrayview-0.46.1}/tests/test_config.py +0 -0
- {arrayview-0.45.1 → arrayview-0.46.1}/tests/test_dicom.py +0 -0
- {arrayview-0.45.1 → arrayview-0.46.1}/tests/test_display_opener_results.py +0 -0
- {arrayview-0.45.1 → arrayview-0.46.1}/tests/test_doctor_commands.py +0 -0
- {arrayview-0.45.1 → arrayview-0.46.1}/tests/test_drop_import.py +0 -0
- {arrayview-0.45.1 → arrayview-0.46.1}/tests/test_instance_registry.py +0 -0
- {arrayview-0.45.1 → arrayview-0.46.1}/tests/test_invocation_contract_matrix.py +0 -0
- {arrayview-0.45.1 → arrayview-0.46.1}/tests/test_io.py +0 -0
- {arrayview-0.45.1 → arrayview-0.46.1}/tests/test_large_arrays.py +0 -0
- {arrayview-0.45.1 → arrayview-0.46.1}/tests/test_launch_blackbox.py +0 -0
- {arrayview-0.45.1 → arrayview-0.46.1}/tests/test_launch_diagnostics.py +0 -0
- {arrayview-0.45.1 → arrayview-0.46.1}/tests/test_launch_execution_ownership.py +0 -0
- {arrayview-0.45.1 → arrayview-0.46.1}/tests/test_launch_plan.py +0 -0
- {arrayview-0.45.1 → arrayview-0.46.1}/tests/test_launch_trace.py +0 -0
- {arrayview-0.45.1 → arrayview-0.46.1}/tests/test_lifecycle_contract.py +0 -0
- {arrayview-0.45.1 → arrayview-0.46.1}/tests/test_loading_server.py +0 -0
- {arrayview-0.45.1 → arrayview-0.46.1}/tests/test_mode_matrix.py +0 -0
- {arrayview-0.45.1 → arrayview-0.46.1}/tests/test_nifti_meta.py +0 -0
- {arrayview-0.45.1 → arrayview-0.46.1}/tests/test_nifti_series.py +0 -0
- {arrayview-0.45.1 → arrayview-0.46.1}/tests/test_preferences_ui.py +0 -0
- {arrayview-0.45.1 → arrayview-0.46.1}/tests/test_public_invocation_regressions.py +0 -0
- {arrayview-0.45.1 → arrayview-0.46.1}/tests/test_render_failure_reporting.py +0 -0
- {arrayview-0.45.1 → arrayview-0.46.1}/tests/test_render_progress.py +0 -0
- {arrayview-0.45.1 → arrayview-0.46.1}/tests/test_rgb_pixel_art.py +0 -0
- {arrayview-0.45.1 → arrayview-0.46.1}/tests/test_roi_hud.py +0 -0
- {arrayview-0.45.1 → arrayview-0.46.1}/tests/test_safe_server_stop.py +0 -0
- {arrayview-0.45.1 → arrayview-0.46.1}/tests/test_server_identity_status.py +0 -0
- {arrayview-0.45.1 → arrayview-0.46.1}/tests/test_session_spec.py +0 -0
- {arrayview-0.45.1 → arrayview-0.46.1}/tests/test_source_safety.py +0 -0
- {arrayview-0.45.1 → arrayview-0.46.1}/tests/test_spawn_ownership.py +0 -0
- {arrayview-0.45.1 → arrayview-0.46.1}/tests/test_torch.py +0 -0
- {arrayview-0.45.1 → arrayview-0.46.1}/tests/test_tutorial.py +0 -0
- {arrayview-0.45.1 → arrayview-0.46.1}/tests/test_tutorial_browser.py +0 -0
- {arrayview-0.45.1 → arrayview-0.46.1}/tests/test_value_formatting.py +0 -0
- {arrayview-0.45.1 → arrayview-0.46.1}/tests/test_view_handle_lifecycle.py +0 -0
- {arrayview-0.45.1 → arrayview-0.46.1}/tests/test_view_launch_execution.py +0 -0
- {arrayview-0.45.1 → arrayview-0.46.1}/tests/test_vscode_ack_protocol.py +0 -0
- {arrayview-0.45.1 → arrayview-0.46.1}/tests/test_window_level_preview.py +0 -0
- {arrayview-0.45.1 → arrayview-0.46.1}/tests/ui_audit.py +0 -0
- {arrayview-0.45.1 → arrayview-0.46.1}/tests/v_anim_frames/.gitkeep +0 -0
- {arrayview-0.45.1 → arrayview-0.46.1}/tests/visual_smoke.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: arrayview
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.46.1
|
|
4
4
|
Summary: Fast multi-dimensional array viewer
|
|
5
5
|
Project-URL: Home, https://github.com/oscarvanderheide/arrayview
|
|
6
6
|
Project-URL: Source, https://github.com/oscarvanderheide/arrayview
|
|
@@ -56,19 +56,6 @@ uvx arrayview your_array.npy
|
|
|
56
56
|
uvx arrayview path/to/dicom-series/
|
|
57
57
|
```
|
|
58
58
|
|
|
59
|
-
Press `v` for the three-plane ortho view. `Shift+3` replaces the current slice,
|
|
60
|
-
or all three ortho panes, with interactive 3D cutaway renders.
|
|
61
|
-
Drop another file onto an open viewer to compare, open separately, or overlay it.
|
|
62
|
-
Press `Shift+R` for ROI analysis: a compact HUD lists each region's mean and standard
|
|
63
|
-
deviation. The HUD sits beside the image when space allows; drag its header
|
|
64
|
-
to move it. Hover a row or region to highlight its counterpart, and use each
|
|
65
|
-
row's trash icon to delete that region. Open the detailed analysis with the
|
|
66
|
-
button beside the HUD's column headings.
|
|
67
|
-
Hold a flood-fill seed and drag up/down to adjust sensitivity; a translucent tapered gauge
|
|
68
|
-
at the starting point shows the current value and the 1%–100% range. The
|
|
69
|
-
pointer hides while adjusting; only the gauge marker moves.
|
|
70
|
-
|
|
71
|
-
|
|
72
59
|
Check the [docs](https://oscarvanderheide.github.io/arrayview/) to learn more.
|
|
73
60
|
|
|
74
61
|
**Warning**: Arrayview is still under active development. Things may break or change without warning.
|
|
@@ -19,19 +19,6 @@ uvx arrayview your_array.npy
|
|
|
19
19
|
uvx arrayview path/to/dicom-series/
|
|
20
20
|
```
|
|
21
21
|
|
|
22
|
-
Press `v` for the three-plane ortho view. `Shift+3` replaces the current slice,
|
|
23
|
-
or all three ortho panes, with interactive 3D cutaway renders.
|
|
24
|
-
Drop another file onto an open viewer to compare, open separately, or overlay it.
|
|
25
|
-
Press `Shift+R` for ROI analysis: a compact HUD lists each region's mean and standard
|
|
26
|
-
deviation. The HUD sits beside the image when space allows; drag its header
|
|
27
|
-
to move it. Hover a row or region to highlight its counterpart, and use each
|
|
28
|
-
row's trash icon to delete that region. Open the detailed analysis with the
|
|
29
|
-
button beside the HUD's column headings.
|
|
30
|
-
Hold a flood-fill seed and drag up/down to adjust sensitivity; a translucent tapered gauge
|
|
31
|
-
at the starting point shows the current value and the 1%–100% range. The
|
|
32
|
-
pointer hides while adjusting; only the gauge marker moves.
|
|
33
|
-
|
|
34
|
-
|
|
35
22
|
Check the [docs](https://oscarvanderheide.github.io/arrayview/) to learn more.
|
|
36
23
|
|
|
37
24
|
**Warning**: Arrayview is still under active development. Things may break or change without warning.
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
5
|
import itertools
|
|
6
|
+
import os
|
|
6
7
|
|
|
7
8
|
import numpy as np
|
|
8
9
|
|
|
@@ -63,6 +64,9 @@ def _build_metadata(session) -> dict:
|
|
|
63
64
|
)
|
|
64
65
|
if getattr(session, "array_keys", None):
|
|
65
66
|
meta["array_keys"] = session.array_keys
|
|
67
|
+
meta["array_key"] = getattr(session, "array_key", None)
|
|
68
|
+
meta["array_prompt"] = bool(getattr(session, "array_prompt", False))
|
|
69
|
+
meta["array_filename"] = os.path.basename(getattr(session, "array_filepath", "") or "")
|
|
66
70
|
if collection_spatial_ndim is not None:
|
|
67
71
|
meta["collection_spatial_ndim"] = int(collection_spatial_ndim)
|
|
68
72
|
if getattr(session.data, "_av_ragged", False):
|
|
@@ -67,6 +67,38 @@ def _is_viewable_mat_array(value):
|
|
|
67
67
|
)
|
|
68
68
|
|
|
69
69
|
|
|
70
|
+
def _is_viewable_h5_dataset(ds):
|
|
71
|
+
"""True for HDF5 datasets in a v7.3 .mat file ArrayView can display.
|
|
72
|
+
|
|
73
|
+
MATLAB v7.3 stores complex arrays as a compound dtype with 'real' and
|
|
74
|
+
'imag' fields, which has dtype kind 'V' rather than 'c'.
|
|
75
|
+
"""
|
|
76
|
+
import h5py
|
|
77
|
+
|
|
78
|
+
if not isinstance(ds, h5py.Dataset) or len(ds.shape) < 1:
|
|
79
|
+
return False
|
|
80
|
+
names = ds.dtype.names
|
|
81
|
+
if names:
|
|
82
|
+
return "real" in names and "imag" in names
|
|
83
|
+
return ds.dtype.kind in ("b", "i", "u", "f", "c")
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def _h5_display_dtype(ds):
|
|
87
|
+
"""Dtype string to show for a v7.3 .mat dataset (compound complex → complex)."""
|
|
88
|
+
if ds.dtype.names:
|
|
89
|
+
return "complex128" if ds.dtype["real"].itemsize == 8 else "complex64"
|
|
90
|
+
return str(ds.dtype)
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def array_choice_placeholder():
|
|
94
|
+
"""Stand-in data for a multi-array file whose array is not chosen yet.
|
|
95
|
+
|
|
96
|
+
The session exists so the viewer can open and ask which array to load;
|
|
97
|
+
nothing from the file is read until the user picks one.
|
|
98
|
+
"""
|
|
99
|
+
return np.zeros((2, 2), dtype=np.float32)
|
|
100
|
+
|
|
101
|
+
|
|
70
102
|
def list_npz_keys(filepath):
|
|
71
103
|
"""Return [{key, shape, dtype}] for each ndarray in an .npz file.
|
|
72
104
|
|
|
@@ -106,8 +138,8 @@ def list_mat_keys(filepath):
|
|
|
106
138
|
keys = []
|
|
107
139
|
for k in f.keys():
|
|
108
140
|
ds = f[k]
|
|
109
|
-
if
|
|
110
|
-
keys.append({"key": k, "shape": list(ds.shape), "dtype":
|
|
141
|
+
if _is_viewable_h5_dataset(ds):
|
|
142
|
+
keys.append({"key": k, "shape": list(ds.shape), "dtype": _h5_display_dtype(ds)})
|
|
111
143
|
f.close()
|
|
112
144
|
return keys
|
|
113
145
|
|
|
@@ -1726,11 +1758,11 @@ def load_data(filepath, key=None, *, progress=None):
|
|
|
1726
1758
|
import h5py
|
|
1727
1759
|
|
|
1728
1760
|
f = h5py.File(filepath, "r")
|
|
1729
|
-
arrays = {k: f[k] for k in f.keys() if
|
|
1761
|
+
arrays = {k: f[k] for k in f.keys() if _is_viewable_h5_dataset(f[k])}
|
|
1730
1762
|
if key is not None:
|
|
1731
|
-
return np.array(arrays[key])
|
|
1763
|
+
return _fix_mat_complex(np.array(arrays[key]))
|
|
1732
1764
|
if len(arrays) == 1:
|
|
1733
|
-
return np.array(next(iter(arrays.values())))
|
|
1765
|
+
return _fix_mat_complex(np.array(next(iter(arrays.values()))))
|
|
1734
1766
|
raise ValueError(
|
|
1735
1767
|
f".mat (v7.3) file contains multiple datasets: {list(arrays.keys())}. "
|
|
1736
1768
|
"Select one in the viewer or pass a key."
|
|
@@ -1321,6 +1321,9 @@ def _load_session_from_filepath(
|
|
|
1321
1321
|
"requested_sid": requested_sid,
|
|
1322
1322
|
"release_on_disconnect": release_on_disconnect,
|
|
1323
1323
|
"related_sids": related_sids or [],
|
|
1324
|
+
# Multi-array .npz/.mat: open the first array instead of returning
|
|
1325
|
+
# the key list; the viewer then offers the choice.
|
|
1326
|
+
"array_default": True,
|
|
1324
1327
|
}
|
|
1325
1328
|
if source_staging_dir:
|
|
1326
1329
|
payload["source_staging_dir"] = source_staging_dir
|
|
@@ -4691,6 +4694,7 @@ def _serve_daemon(
|
|
|
4691
4694
|
|
|
4692
4695
|
def _load():
|
|
4693
4696
|
from arrayview._io import (
|
|
4697
|
+
array_choice_placeholder,
|
|
4694
4698
|
load_data,
|
|
4695
4699
|
load_data_with_meta,
|
|
4696
4700
|
load_dir_collection,
|
|
@@ -4705,8 +4709,8 @@ def _serve_daemon(
|
|
|
4705
4709
|
if dir_patterns is None and not cleanup
|
|
4706
4710
|
else None
|
|
4707
4711
|
)
|
|
4708
|
-
# Multi-array .npz/.mat:
|
|
4709
|
-
#
|
|
4712
|
+
# Multi-array .npz/.mat: create the session with a placeholder and
|
|
4713
|
+
# store the keys; the viewer asks which array to load.
|
|
4710
4714
|
_array_keys = None
|
|
4711
4715
|
if dir_patterns is not None:
|
|
4712
4716
|
data, spatial_meta, dir_overlay_items, _summary = load_dir_collection(
|
|
@@ -4723,8 +4727,12 @@ def _serve_daemon(
|
|
|
4723
4727
|
_array_keys = list_array_keys(filepath)
|
|
4724
4728
|
except Exception:
|
|
4725
4729
|
pass
|
|
4726
|
-
|
|
4727
|
-
|
|
4730
|
+
if _array_keys and len(_array_keys) > 1:
|
|
4731
|
+
_load_key = None
|
|
4732
|
+
data, spatial_meta = array_choice_placeholder(), None
|
|
4733
|
+
else:
|
|
4734
|
+
_load_key = _array_keys[0]["key"] if _array_keys else None
|
|
4735
|
+
data, spatial_meta = load_data_with_meta(filepath, key=_load_key)
|
|
4728
4736
|
dir_overlay_items = None
|
|
4729
4737
|
collection_spatial_ndim = None
|
|
4730
4738
|
else:
|
|
@@ -4758,6 +4766,9 @@ def _serve_daemon(
|
|
|
4758
4766
|
if _array_keys and len(_array_keys) > 1:
|
|
4759
4767
|
session.array_keys = _array_keys
|
|
4760
4768
|
session.array_filepath = filepath
|
|
4769
|
+
session.array_key = _load_key
|
|
4770
|
+
# Nothing is loaded yet; the viewer asks once which array to show.
|
|
4771
|
+
session.array_prompt = True
|
|
4761
4772
|
if spatial_meta is not None:
|
|
4762
4773
|
session.original_volume = data
|
|
4763
4774
|
if rgb:
|
|
@@ -413,12 +413,18 @@ def register_loading_routes(app, *, notify_shells, setup_rgb) -> None:
|
|
|
413
413
|
PENDING_SESSIONS.add(dir_pending_sid)
|
|
414
414
|
try:
|
|
415
415
|
try:
|
|
416
|
-
from ._io import
|
|
416
|
+
from ._io import (
|
|
417
|
+
array_choice_placeholder,
|
|
418
|
+
list_array_keys,
|
|
419
|
+
load_data_with_meta,
|
|
420
|
+
load_dir_collection,
|
|
421
|
+
)
|
|
417
422
|
|
|
418
423
|
# Multi-array .npz/.mat: if no key provided, return the key list so
|
|
419
424
|
# the client can show a picker instead of blocking on terminal input.
|
|
420
425
|
_key = body.get("key")
|
|
421
426
|
_array_keys = None
|
|
427
|
+
_array_prompt = False
|
|
422
428
|
if dir_patterns:
|
|
423
429
|
data, spatial_meta, dir_overlay_items, summary = await asyncio.to_thread(
|
|
424
430
|
load_dir_collection,
|
|
@@ -432,16 +438,22 @@ def register_loading_routes(app, *, notify_shells, setup_rgb) -> None:
|
|
|
432
438
|
elif filepath.endswith(".npz") or filepath.endswith(".mat"):
|
|
433
439
|
_array_keys = await asyncio.to_thread(list_array_keys, filepath)
|
|
434
440
|
if len(_array_keys) > 1 and not _key:
|
|
435
|
-
|
|
441
|
+
if not body.get("array_default"):
|
|
442
|
+
return {"array_keys": _array_keys, "filepath": filepath}
|
|
443
|
+
# Command-line launch: open the viewer without reading
|
|
444
|
+
# any array; it asks which one to load.
|
|
445
|
+
_array_prompt = True
|
|
446
|
+
data, spatial_meta = array_choice_placeholder(), None
|
|
436
447
|
if len(_array_keys) == 1 and not _key:
|
|
437
448
|
_key = _array_keys[0]["key"]
|
|
438
449
|
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
450
|
+
if not dir_patterns and not _array_prompt:
|
|
451
|
+
data, spatial_meta = await asyncio.to_thread(
|
|
452
|
+
load_data_with_meta,
|
|
453
|
+
filepath,
|
|
454
|
+
key=_key,
|
|
455
|
+
select=body.get("select"),
|
|
456
|
+
)
|
|
445
457
|
except Exception as e:
|
|
446
458
|
if staging_dir:
|
|
447
459
|
cleanup_staging_directory(staging_dir)
|
|
@@ -482,6 +494,8 @@ def register_loading_routes(app, *, notify_shells, setup_rgb) -> None:
|
|
|
482
494
|
if _array_keys and len(_array_keys) > 1:
|
|
483
495
|
session.array_keys = _array_keys
|
|
484
496
|
session.array_filepath = filepath
|
|
497
|
+
session.array_key = _key
|
|
498
|
+
session.array_prompt = _array_prompt
|
|
485
499
|
if body.get("rgb"):
|
|
486
500
|
try:
|
|
487
501
|
await asyncio.to_thread(setup_rgb, session)
|
|
@@ -627,15 +641,25 @@ def register_loading_routes(app, *, notify_shells, setup_rgb) -> None:
|
|
|
627
641
|
return {"error": str(e)}
|
|
628
642
|
session.data = data
|
|
629
643
|
session.shape = data.shape
|
|
644
|
+
session.spatial_shape = data.shape
|
|
645
|
+
session.rgb_axis = None
|
|
646
|
+
session.fft_original_data = None
|
|
647
|
+
session.fft_axes = None
|
|
648
|
+
session.reset_caches()
|
|
630
649
|
session.data_version += 1
|
|
631
|
-
session.raw_cache.clear()
|
|
632
|
-
session.rgba_cache.clear()
|
|
633
|
-
session.mosaic_cache.clear()
|
|
634
|
-
session._raw_bytes = 0
|
|
635
|
-
session._rgba_bytes = 0
|
|
636
|
-
session._mosaic_bytes = 0
|
|
637
650
|
session._estimated_mem = session._estimate_memory()
|
|
638
651
|
# Keep array_keys so the user can switch again, but don't auto-prompt
|
|
652
|
+
session.array_key = key
|
|
653
|
+
session.array_prompt = False
|
|
654
|
+
return {"ok": True}
|
|
655
|
+
|
|
656
|
+
@app.post("/session/{sid}/array-prompt-done")
|
|
657
|
+
async def array_prompt_done(sid: str):
|
|
658
|
+
"""Record that the array picker was offered, so it never reopens by itself."""
|
|
659
|
+
session = SESSIONS.get(sid)
|
|
660
|
+
if session is None:
|
|
661
|
+
raise HTTPException(status_code=404, detail="Session not found")
|
|
662
|
+
session.array_prompt = False
|
|
639
663
|
return {"ok": True}
|
|
640
664
|
|
|
641
665
|
@app.get("/fs/list")
|