arrayview 0.50.1__tar.gz → 0.51.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.50.1 → arrayview-0.51.1}/PKG-INFO +3 -1
- {arrayview-0.50.1 → arrayview-0.51.1}/README.md +2 -0
- {arrayview-0.50.1 → arrayview-0.51.1}/pyproject.toml +1 -1
- {arrayview-0.50.1 → arrayview-0.51.1}/src/arrayview/_io.py +6 -4
- {arrayview-0.50.1 → arrayview-0.51.1}/src/arrayview/_launcher.py +39 -2
- {arrayview-0.50.1 → arrayview-0.51.1}/src/arrayview/_routes_loading.py +2 -0
- {arrayview-0.50.1 → arrayview-0.51.1}/src/arrayview/_routes_query.py +15 -1
- {arrayview-0.50.1 → arrayview-0.51.1}/src/arrayview/_viewer.html +3045 -850
- {arrayview-0.50.1 → arrayview-0.51.1}/tests/test_api.py +46 -0
- {arrayview-0.50.1 → arrayview-0.51.1}/tests/test_browser.py +634 -29
- {arrayview-0.50.1 → arrayview-0.51.1}/tests/test_cli.py +50 -6
- arrayview-0.51.1/tests/test_glides.py +166 -0
- {arrayview-0.50.1 → arrayview-0.51.1}/tests/test_mode_roundtrip.py +5 -1
- arrayview-0.51.1/tests/test_pane_names.py +512 -0
- {arrayview-0.50.1 → arrayview-0.51.1}/.gitignore +0 -0
- {arrayview-0.50.1 → arrayview-0.51.1}/LICENSE +0 -0
- {arrayview-0.50.1 → arrayview-0.51.1}/src/arrayview/ARCHITECTURE.md +0 -0
- {arrayview-0.50.1 → arrayview-0.51.1}/src/arrayview/__init__.py +0 -0
- {arrayview-0.50.1 → arrayview-0.51.1}/src/arrayview/__main__.py +0 -0
- {arrayview-0.50.1 → arrayview-0.51.1}/src/arrayview/_analysis.py +0 -0
- {arrayview-0.50.1 → arrayview-0.51.1}/src/arrayview/_app.py +0 -0
- {arrayview-0.50.1 → arrayview-0.51.1}/src/arrayview/_bootstrap_app.py +0 -0
- {arrayview-0.50.1 → arrayview-0.51.1}/src/arrayview/_config.py +0 -0
- {arrayview-0.50.1 → arrayview-0.51.1}/src/arrayview/_diagnostics.py +0 -0
- {arrayview-0.50.1 → arrayview-0.51.1}/src/arrayview/_dicom.py +0 -0
- {arrayview-0.50.1 → arrayview-0.51.1}/src/arrayview/_diff.py +0 -0
- {arrayview-0.50.1 → arrayview-0.51.1}/src/arrayview/_extra_ports.py +0 -0
- {arrayview-0.50.1 → arrayview-0.51.1}/src/arrayview/_icon.png +0 -0
- {arrayview-0.50.1 → arrayview-0.51.1}/src/arrayview/_imaging.py +0 -0
- {arrayview-0.50.1 → arrayview-0.51.1}/src/arrayview/_instance_registry.py +0 -0
- {arrayview-0.50.1 → arrayview-0.51.1}/src/arrayview/_launch_plan.py +0 -0
- {arrayview-0.50.1 → arrayview-0.51.1}/src/arrayview/_launch_trace.py +0 -0
- {arrayview-0.50.1 → arrayview-0.51.1}/src/arrayview/_lifecycle.py +0 -0
- {arrayview-0.50.1 → arrayview-0.51.1}/src/arrayview/_overlays.py +0 -0
- {arrayview-0.50.1 → arrayview-0.51.1}/src/arrayview/_platform.py +0 -0
- {arrayview-0.50.1 → arrayview-0.51.1}/src/arrayview/_render.py +0 -0
- {arrayview-0.50.1 → arrayview-0.51.1}/src/arrayview/_routes_analysis.py +0 -0
- {arrayview-0.50.1 → arrayview-0.51.1}/src/arrayview/_routes_drop.py +0 -0
- {arrayview-0.50.1 → arrayview-0.51.1}/src/arrayview/_routes_export.py +0 -0
- {arrayview-0.50.1 → arrayview-0.51.1}/src/arrayview/_routes_persistence.py +0 -0
- {arrayview-0.50.1 → arrayview-0.51.1}/src/arrayview/_routes_preferences.py +0 -0
- {arrayview-0.50.1 → arrayview-0.51.1}/src/arrayview/_routes_preload.py +0 -0
- {arrayview-0.50.1 → arrayview-0.51.1}/src/arrayview/_routes_rendering.py +0 -0
- {arrayview-0.50.1 → arrayview-0.51.1}/src/arrayview/_routes_segmentation.py +0 -0
- {arrayview-0.50.1 → arrayview-0.51.1}/src/arrayview/_routes_state.py +0 -0
- {arrayview-0.50.1 → arrayview-0.51.1}/src/arrayview/_routes_vectorfield.py +0 -0
- {arrayview-0.50.1 → arrayview-0.51.1}/src/arrayview/_routes_websocket.py +0 -0
- {arrayview-0.50.1 → arrayview-0.51.1}/src/arrayview/_segmentation.py +0 -0
- {arrayview-0.50.1 → arrayview-0.51.1}/src/arrayview/_server.py +0 -0
- {arrayview-0.50.1 → arrayview-0.51.1}/src/arrayview/_session.py +0 -0
- {arrayview-0.50.1 → arrayview-0.51.1}/src/arrayview/_session_spec.py +0 -0
- {arrayview-0.50.1 → arrayview-0.51.1}/src/arrayview/_shell.html +0 -0
- {arrayview-0.50.1 → arrayview-0.51.1}/src/arrayview/_source_safety.py +0 -0
- {arrayview-0.50.1 → arrayview-0.51.1}/src/arrayview/_synthetic_mri.py +0 -0
- {arrayview-0.50.1 → arrayview-0.51.1}/src/arrayview/_torch.py +0 -0
- {arrayview-0.50.1 → arrayview-0.51.1}/src/arrayview/_tutorial.py +0 -0
- {arrayview-0.50.1 → arrayview-0.51.1}/src/arrayview/_vectorfield.py +0 -0
- {arrayview-0.50.1 → arrayview-0.51.1}/src/arrayview/_view_memory.py +0 -0
- {arrayview-0.50.1 → arrayview-0.51.1}/src/arrayview/_vscode.py +0 -0
- {arrayview-0.50.1 → arrayview-0.51.1}/src/arrayview/_vscode_browser.py +0 -0
- {arrayview-0.50.1 → arrayview-0.51.1}/src/arrayview/_vscode_extension.py +0 -0
- {arrayview-0.50.1 → arrayview-0.51.1}/src/arrayview/_vscode_signal.py +0 -0
- {arrayview-0.50.1 → arrayview-0.51.1}/src/arrayview/_watch.py +0 -0
- {arrayview-0.50.1 → arrayview-0.51.1}/src/arrayview/arrayview-opener.vsix +0 -0
- {arrayview-0.50.1 → arrayview-0.51.1}/src/arrayview/gsap.min.js +0 -0
- {arrayview-0.50.1 → arrayview-0.51.1}/src/arrayview/todo.md +0 -0
- {arrayview-0.50.1 → arrayview-0.51.1}/tests/capture_patient_loading.py +0 -0
- {arrayview-0.50.1 → arrayview-0.51.1}/tests/capture_v_animation.py +0 -0
- {arrayview-0.50.1 → arrayview-0.51.1}/tests/conftest.py +0 -0
- {arrayview-0.50.1 → arrayview-0.51.1}/tests/make_vectorfield_test_arrays.py +0 -0
- {arrayview-0.50.1 → arrayview-0.51.1}/tests/test_1d_arrays.py +0 -0
- {arrayview-0.50.1 → arrayview-0.51.1}/tests/test_backend_shared.py +0 -0
- {arrayview-0.50.1 → arrayview-0.51.1}/tests/test_config.py +0 -0
- {arrayview-0.50.1 → arrayview-0.51.1}/tests/test_dicom.py +0 -0
- {arrayview-0.50.1 → arrayview-0.51.1}/tests/test_drop_import.py +0 -0
- {arrayview-0.50.1 → arrayview-0.51.1}/tests/test_instance_registry.py +0 -0
- {arrayview-0.50.1 → arrayview-0.51.1}/tests/test_io.py +0 -0
- {arrayview-0.50.1 → arrayview-0.51.1}/tests/test_large_arrays.py +0 -0
- {arrayview-0.50.1 → arrayview-0.51.1}/tests/test_launch_blackbox.py +0 -0
- {arrayview-0.50.1 → arrayview-0.51.1}/tests/test_nifti_meta.py +0 -0
- {arrayview-0.50.1 → arrayview-0.51.1}/tests/test_nifti_series.py +0 -0
- {arrayview-0.50.1 → arrayview-0.51.1}/tests/test_rgb_pixel_art.py +0 -0
- {arrayview-0.50.1 → arrayview-0.51.1}/tests/test_safe_server_stop.py +0 -0
- {arrayview-0.50.1 → arrayview-0.51.1}/tests/test_source_safety.py +0 -0
- {arrayview-0.50.1 → arrayview-0.51.1}/tests/test_torch.py +0 -0
- {arrayview-0.50.1 → arrayview-0.51.1}/tests/test_tutorial.py +0 -0
- {arrayview-0.50.1 → arrayview-0.51.1}/tests/test_view_memory.py +0 -0
- {arrayview-0.50.1 → arrayview-0.51.1}/tests/test_vsix_bundle.py +0 -0
- {arrayview-0.50.1 → arrayview-0.51.1}/tests/ui_audit.py +0 -0
- {arrayview-0.50.1 → arrayview-0.51.1}/tests/v_anim_frames/.gitkeep +0 -0
- {arrayview-0.50.1 → arrayview-0.51.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.51.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
|
|
@@ -39,6 +39,8 @@ Description-Content-Type: text/markdown
|
|
|
39
39
|
|
|
40
40
|
_This is my array viewer. There are many like it, but this one is mine._
|
|
41
41
|
|
|
42
|
+
<img src="docs/teaser.gif" alt="ArrayView: scrolling a volume, switching colormaps, three planes, and a difference view" width="800">
|
|
43
|
+
|
|
42
44
|
Arrayview lets you scroll through multi-dimensional arrays.
|
|
43
45
|
|
|
44
46
|
Open it from the shell, from Python, Julia, or Matlab, or inside a Jupyter notebook. Use it locally or over SSH.
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
_This is my array viewer. There are many like it, but this one is mine._
|
|
4
4
|
|
|
5
|
+
<img src="docs/teaser.gif" alt="ArrayView: scrolling a volume, switching colormaps, three planes, and a difference view" width="800">
|
|
6
|
+
|
|
5
7
|
Arrayview lets you scroll through multi-dimensional arrays.
|
|
6
8
|
|
|
7
9
|
Open it from the shell, from Python, Julia, or Matlab, or inside a Jupyter notebook. Use it locally or over SSH.
|
|
@@ -1452,7 +1452,7 @@ def _collection_pattern_paths(pattern):
|
|
|
1452
1452
|
return paths
|
|
1453
1453
|
|
|
1454
1454
|
|
|
1455
|
-
def _explicit_case_files(patterns):
|
|
1455
|
+
def _explicit_case_files(patterns, keep_order=False):
|
|
1456
1456
|
"""Plain file paths given as several patterns, or None.
|
|
1457
1457
|
|
|
1458
1458
|
An unquoted ``--match dir/*/maps.nii`` reaches us already expanded by the
|
|
@@ -1467,7 +1467,7 @@ def _explicit_case_files(patterns):
|
|
|
1467
1467
|
paths = [os.path.abspath(p) for p in patterns if _is_supported_collection_path(p)]
|
|
1468
1468
|
if len(paths) != len(patterns) or len(set(paths)) != len(paths):
|
|
1469
1469
|
return None
|
|
1470
|
-
return sorted(paths)
|
|
1470
|
+
return paths if keep_order else sorted(paths)
|
|
1471
1471
|
|
|
1472
1472
|
|
|
1473
1473
|
def _distinguishing_path_parts(paths):
|
|
@@ -1720,6 +1720,7 @@ def load_dir_collection(
|
|
|
1720
1720
|
stack="auto",
|
|
1721
1721
|
scan_progress=None,
|
|
1722
1722
|
exclude_cases=None,
|
|
1723
|
+
keep_order=False,
|
|
1723
1724
|
):
|
|
1724
1725
|
"""Load recursive collection patterns as aligned lazy image/overlay stacks.
|
|
1725
1726
|
|
|
@@ -1730,7 +1731,8 @@ def load_dir_collection(
|
|
|
1730
1731
|
*case_regex*, files are paired by the regex's named ``case`` group instead.
|
|
1731
1732
|
*exclude_cases* removes known case ids before any image or overlay data is
|
|
1732
1733
|
opened. It is used by the interactive CLI after the user accepts a partial
|
|
1733
|
-
overlay match.
|
|
1734
|
+
overlay match. *keep_order* stacks an explicit file list in the order
|
|
1735
|
+
given instead of sorted.
|
|
1734
1736
|
"""
|
|
1735
1737
|
if not base_patterns:
|
|
1736
1738
|
raise ValueError("--match requires at least one positional image pattern.")
|
|
@@ -1753,7 +1755,7 @@ def load_dir_collection(
|
|
|
1753
1755
|
raise ValueError("; ".join(missing))
|
|
1754
1756
|
base_matrix = [[by_case[case] for by_case in base_maps] for case in case_ids]
|
|
1755
1757
|
else:
|
|
1756
|
-
explicit_cases = _explicit_case_files(base_patterns)
|
|
1758
|
+
explicit_cases = _explicit_case_files(base_patterns, keep_order=keep_order)
|
|
1757
1759
|
base_lists = (
|
|
1758
1760
|
[explicit_cases]
|
|
1759
1761
|
if explicit_cases is not None
|
|
@@ -1323,6 +1323,7 @@ def _load_session_from_filepath(
|
|
|
1323
1323
|
dir_exclude_cases: list[str] | None = None,
|
|
1324
1324
|
collection_load: str = "lazy",
|
|
1325
1325
|
collection_stack: str = "auto",
|
|
1326
|
+
collection_keep_order: bool = False,
|
|
1326
1327
|
background: bool = False,
|
|
1327
1328
|
expected_server_id: str | None = None,
|
|
1328
1329
|
native_request_id: str | None = None,
|
|
@@ -1365,6 +1366,7 @@ def _load_session_from_filepath(
|
|
|
1365
1366
|
payload["dir_exclude_cases"] = dir_exclude_cases or []
|
|
1366
1367
|
payload["load"] = collection_load
|
|
1367
1368
|
payload["stack"] = collection_stack
|
|
1369
|
+
payload["keep_order"] = collection_keep_order
|
|
1368
1370
|
if notify and compare_sids:
|
|
1369
1371
|
payload["compare_sid"] = compare_sids[0]
|
|
1370
1372
|
payload["compare_sids"] = _join_query_values(compare_sids)
|
|
@@ -1686,6 +1688,7 @@ def _register_cli_session_with_existing_server_impl(
|
|
|
1686
1688
|
dir_exclude_cases: list[str] | None = None,
|
|
1687
1689
|
collection_load: str = "lazy",
|
|
1688
1690
|
collection_stack: str = "auto",
|
|
1691
|
+
collection_keep_order: bool = False,
|
|
1689
1692
|
overlay_names: list[str] | None = None,
|
|
1690
1693
|
background_base: bool = False,
|
|
1691
1694
|
expected_server_id: str | None = None,
|
|
@@ -1741,6 +1744,7 @@ def _register_cli_session_with_existing_server_impl(
|
|
|
1741
1744
|
dir_exclude_cases=dir_exclude_cases,
|
|
1742
1745
|
collection_load=collection_load,
|
|
1743
1746
|
collection_stack=collection_stack,
|
|
1747
|
+
collection_keep_order=collection_keep_order,
|
|
1744
1748
|
background=background_base,
|
|
1745
1749
|
expected_server_id=expected_server_id,
|
|
1746
1750
|
native_request_id=native_request_id,
|
|
@@ -1838,6 +1842,7 @@ def _handle_cli_existing_server(
|
|
|
1838
1842
|
dir_exclude_cases: list[str] | None = None,
|
|
1839
1843
|
collection_load: str = "lazy",
|
|
1840
1844
|
collection_stack: str = "auto",
|
|
1845
|
+
collection_keep_order: bool = False,
|
|
1841
1846
|
overlay_names: list[str] | None = None,
|
|
1842
1847
|
cleanup_dir: str | None = None,
|
|
1843
1848
|
source_staging_dirs: dict[str, str] | None = None,
|
|
@@ -1866,6 +1871,7 @@ def _handle_cli_existing_server(
|
|
|
1866
1871
|
dir_exclude_cases=dir_exclude_cases,
|
|
1867
1872
|
collection_load=collection_load,
|
|
1868
1873
|
collection_stack=collection_stack,
|
|
1874
|
+
collection_keep_order=collection_keep_order,
|
|
1869
1875
|
overlay_names=overlay_names,
|
|
1870
1876
|
background_base=(
|
|
1871
1877
|
is_remote
|
|
@@ -1954,6 +1960,7 @@ def _handle_cli_existing_server(
|
|
|
1954
1960
|
dir_exclude_cases=dir_exclude_cases,
|
|
1955
1961
|
collection_load=collection_load,
|
|
1956
1962
|
collection_stack=collection_stack,
|
|
1963
|
+
collection_keep_order=collection_keep_order,
|
|
1957
1964
|
overlay_names=overlay_names,
|
|
1958
1965
|
source_staging_dirs=source_staging_dirs,
|
|
1959
1966
|
)
|
|
@@ -2084,6 +2091,7 @@ def _handle_cli_spawned_daemon(
|
|
|
2084
2091
|
dir_exclude_cases: list[str] | None = None,
|
|
2085
2092
|
collection_load: str = "lazy",
|
|
2086
2093
|
collection_stack: str = "auto",
|
|
2094
|
+
collection_keep_order: bool = False,
|
|
2087
2095
|
overlay_names: list[str] | None = None,
|
|
2088
2096
|
cleanup_dir: str | None = None,
|
|
2089
2097
|
source_staging_dirs: dict[str, str] | None = None,
|
|
@@ -2147,6 +2155,7 @@ def _handle_cli_spawned_daemon(
|
|
|
2147
2155
|
dir_exclude_cases=dir_exclude_cases,
|
|
2148
2156
|
collection_load=collection_load,
|
|
2149
2157
|
collection_stack=collection_stack,
|
|
2158
|
+
collection_keep_order=collection_keep_order,
|
|
2150
2159
|
overlay_names=resolved_overlay_names,
|
|
2151
2160
|
cleanup_dir=cleanup_dir,
|
|
2152
2161
|
source_staging_dirs=source_staging_dirs,
|
|
@@ -2202,6 +2211,7 @@ def _handle_cli_spawned_daemon(
|
|
|
2202
2211
|
f" dir_exclude_cases={repr(dir_exclude_cases)},"
|
|
2203
2212
|
f" collection_load={repr(collection_load)},"
|
|
2204
2213
|
f" collection_stack={repr(collection_stack)},"
|
|
2214
|
+
f" collection_keep_order={repr(collection_keep_order)},"
|
|
2205
2215
|
f" cleanup_dir={repr(cleanup_dir)},"
|
|
2206
2216
|
f" source_staging_dirs={repr(source_staging_dirs or {})},"
|
|
2207
2217
|
f" watch={watch},"
|
|
@@ -4729,6 +4739,7 @@ def _serve_daemon(
|
|
|
4729
4739
|
dir_exclude_cases: list[str] | None = None,
|
|
4730
4740
|
collection_load: str = "lazy",
|
|
4731
4741
|
collection_stack: str = "auto",
|
|
4742
|
+
collection_keep_order: bool = False,
|
|
4732
4743
|
cleanup_dir: str | None = None,
|
|
4733
4744
|
source_staging_dirs: dict[str, str] | None = None,
|
|
4734
4745
|
watch: bool = False,
|
|
@@ -4868,6 +4879,7 @@ def _serve_daemon(
|
|
|
4868
4879
|
exclude_cases=dir_exclude_cases,
|
|
4869
4880
|
load=collection_load,
|
|
4870
4881
|
stack=collection_stack,
|
|
4882
|
+
keep_order=collection_keep_order,
|
|
4871
4883
|
)
|
|
4872
4884
|
collection_spatial_ndim = len(_summary["spatial_shape"])
|
|
4873
4885
|
elif (filepath.endswith(".npz") or filepath.endswith(".mat")) and not cleanup:
|
|
@@ -6052,6 +6064,27 @@ def arrayview():
|
|
|
6052
6064
|
"stacking: a directory of arrays is stacked either way. It selects "
|
|
6053
6065
|
"which files form the collection."
|
|
6054
6066
|
)
|
|
6067
|
+
if (
|
|
6068
|
+
args.files
|
|
6069
|
+
and len(args.files) > 4
|
|
6070
|
+
and not args.stack_mode
|
|
6071
|
+
and not (
|
|
6072
|
+
args.compare
|
|
6073
|
+
or args.overlay
|
|
6074
|
+
or args.vectorfield
|
|
6075
|
+
or args.watch
|
|
6076
|
+
or args.rgb
|
|
6077
|
+
or args.relay
|
|
6078
|
+
)
|
|
6079
|
+
):
|
|
6080
|
+
# Too many for a side-by-side compare: stack them along a new last
|
|
6081
|
+
# axis, one case per file, as --match does for explicit file lists.
|
|
6082
|
+
args.stack_mode = True
|
|
6083
|
+
args.keep_file_order = True
|
|
6084
|
+
print(
|
|
6085
|
+
f"[ArrayView] {len(args.files)} files: opened as one stack; "
|
|
6086
|
+
"step through the last dimension to switch files."
|
|
6087
|
+
)
|
|
6055
6088
|
if args.dry_run and not args.stack_mode:
|
|
6056
6089
|
parser.error("--dry-run requires --match.")
|
|
6057
6090
|
excluded_cases = set()
|
|
@@ -6098,9 +6131,10 @@ def arrayview():
|
|
|
6098
6131
|
dims_override = (0, 1)
|
|
6099
6132
|
if not args.serve and not args.kill and not args.files:
|
|
6100
6133
|
_configure_tutorial_args(args)
|
|
6101
|
-
if args.files and len(args.files) >
|
|
6134
|
+
if args.files and len(args.files) > 4 and not args.stack_mode:
|
|
6102
6135
|
parser.error(
|
|
6103
|
-
"
|
|
6136
|
+
"More than four FILE arguments open as one stack, which does not "
|
|
6137
|
+
"support --compare, --overlay, --vectorfield, --watch, --rgb, or --relay."
|
|
6104
6138
|
)
|
|
6105
6139
|
if args.compare and len(args.files) > 1 and not args.stack_mode:
|
|
6106
6140
|
parser.error("Use either positional compare files or --compare, not both.")
|
|
@@ -6310,6 +6344,7 @@ def arrayview():
|
|
|
6310
6344
|
stack=args.stack_policy or "auto",
|
|
6311
6345
|
scan_progress=scan_progress.update,
|
|
6312
6346
|
exclude_cases=excluded_cases,
|
|
6347
|
+
keep_order=getattr(args, "keep_file_order", False),
|
|
6313
6348
|
)
|
|
6314
6349
|
finally:
|
|
6315
6350
|
scan_progress.finish()
|
|
@@ -6683,6 +6718,7 @@ def arrayview():
|
|
|
6683
6718
|
dir_exclude_cases=sorted(excluded_cases),
|
|
6684
6719
|
collection_load=args.load,
|
|
6685
6720
|
collection_stack=args.stack_policy or "auto",
|
|
6721
|
+
collection_keep_order=getattr(args, "keep_file_order", False),
|
|
6686
6722
|
cleanup_dir=getattr(args, "_tutorial_cleanup_dir", None),
|
|
6687
6723
|
source_staging_dirs=(
|
|
6688
6724
|
source_staging_dirs if not args.stack_mode else None
|
|
@@ -6723,6 +6759,7 @@ def arrayview():
|
|
|
6723
6759
|
dir_exclude_cases=sorted(excluded_cases),
|
|
6724
6760
|
collection_load=args.load,
|
|
6725
6761
|
collection_stack=args.stack_policy or "auto",
|
|
6762
|
+
collection_keep_order=getattr(args, "keep_file_order", False),
|
|
6726
6763
|
source_staging_dirs=(
|
|
6727
6764
|
source_staging_dirs if not args.stack_mode else None
|
|
6728
6765
|
),
|
|
@@ -227,6 +227,7 @@ def register_loading_routes(app, *, notify_shells, setup_rgb) -> None:
|
|
|
227
227
|
tuple(str(case) for case in body.get("dir_exclude_cases", [])),
|
|
228
228
|
body.get("load", "lazy"),
|
|
229
229
|
body.get("stack", "auto"),
|
|
230
|
+
bool(body.get("keep_order", False)),
|
|
230
231
|
)
|
|
231
232
|
for existing in [] if requested_sid else SESSIONS.values():
|
|
232
233
|
if getattr(existing, "collection_identity", None) == collection_identity:
|
|
@@ -440,6 +441,7 @@ def register_loading_routes(app, *, notify_shells, setup_rgb) -> None:
|
|
|
440
441
|
exclude_cases=body.get("dir_exclude_cases", []),
|
|
441
442
|
load=body.get("load", "lazy"),
|
|
442
443
|
stack=body.get("stack", "auto"),
|
|
444
|
+
keep_order=bool(body.get("keep_order", False)),
|
|
443
445
|
)
|
|
444
446
|
elif filepath.endswith(".npz") or filepath.endswith(".mat"):
|
|
445
447
|
_array_keys = await asyncio.to_thread(list_array_keys, filepath)
|
|
@@ -429,7 +429,7 @@ def register_query_routes(app, *, get_session_or_404, pil_image, pil_imageops) -
|
|
|
429
429
|
info["overlay_labels"] = []
|
|
430
430
|
try:
|
|
431
431
|
if np.issubdtype(session.data.dtype, np.integer):
|
|
432
|
-
labels = np.unique(session
|
|
432
|
+
labels = np.unique(_overlay_label_sample(session))
|
|
433
433
|
labels = labels[labels > 0]
|
|
434
434
|
if labels.size <= 16:
|
|
435
435
|
info["overlay_labels"] = [int(value) for value in labels]
|
|
@@ -531,6 +531,18 @@ def register_query_routes(app, *, get_session_or_404, pil_image, pil_imageops) -
|
|
|
531
531
|
)
|
|
532
532
|
|
|
533
533
|
|
|
534
|
+
def _overlay_label_sample(session):
|
|
535
|
+
"""Overlay values to read label ids from: the whole array, or only the
|
|
536
|
+
first case of a collection (reading every case would stall opening; the
|
|
537
|
+
viewer adds labels found in other cases as they are visited)."""
|
|
538
|
+
spatial = getattr(session, "collection_spatial_ndim", None)
|
|
539
|
+
shape = tuple(session.shape)
|
|
540
|
+
if spatial is None or not (0 < spatial < len(shape)):
|
|
541
|
+
return np.asarray(session.data)
|
|
542
|
+
index = (slice(None),) * spatial + (0,) * (len(shape) - spatial)
|
|
543
|
+
return np.asarray(session.data[index])
|
|
544
|
+
|
|
545
|
+
|
|
534
546
|
def _overlay_slice_counts(ov_session, base_shape, dim_x, dim_y, axis, idx_list):
|
|
535
547
|
"""Count overlay pixels per label on every slice along ``axis``."""
|
|
536
548
|
n = int(base_shape[axis])
|
|
@@ -555,6 +567,8 @@ def _overlay_slice_counts(ov_session, base_shape, dim_x, dim_y, axis, idx_list):
|
|
|
555
567
|
return empty
|
|
556
568
|
kept = [a for a in base_axes if a in (dim_x, dim_y, axis)]
|
|
557
569
|
if axis in kept:
|
|
570
|
+
# Ragged collections return this case's own size, not the max-shape facade.
|
|
571
|
+
n = int(vol.shape[kept.index(axis)])
|
|
558
572
|
vol = np.moveaxis(vol, kept.index(axis), 0).reshape(n, -1)
|
|
559
573
|
else:
|
|
560
574
|
# The overlay has no such axis: it looks the same on every slice.
|