lbm_suite2p_python 2.5.4__tar.gz → 2.5.7__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.
- {lbm_suite2p_python-2.5.4/lbm_suite2p_python.egg-info → lbm_suite2p_python-2.5.7}/PKG-INFO +6 -6
- {lbm_suite2p_python-2.5.4 → lbm_suite2p_python-2.5.7}/lbm_suite2p_python/cellpose.py +16 -11
- {lbm_suite2p_python-2.5.4 → lbm_suite2p_python-2.5.7}/lbm_suite2p_python/grid_search.py +24 -15
- {lbm_suite2p_python-2.5.4 → lbm_suite2p_python-2.5.7}/lbm_suite2p_python/postprocessing.py +12 -6
- {lbm_suite2p_python-2.5.4 → lbm_suite2p_python-2.5.7}/lbm_suite2p_python/run_lsp.py +842 -261
- {lbm_suite2p_python-2.5.4 → lbm_suite2p_python-2.5.7}/lbm_suite2p_python/utils.py +12 -5
- {lbm_suite2p_python-2.5.4 → lbm_suite2p_python-2.5.7}/lbm_suite2p_python/zplane.py +249 -258
- {lbm_suite2p_python-2.5.4 → lbm_suite2p_python-2.5.7/lbm_suite2p_python.egg-info}/PKG-INFO +6 -6
- {lbm_suite2p_python-2.5.4 → lbm_suite2p_python-2.5.7}/lbm_suite2p_python.egg-info/SOURCES.txt +1 -0
- {lbm_suite2p_python-2.5.4 → lbm_suite2p_python-2.5.7}/lbm_suite2p_python.egg-info/requires.txt +4 -5
- {lbm_suite2p_python-2.5.4 → lbm_suite2p_python-2.5.7}/pyproject.toml +6 -22
- lbm_suite2p_python-2.5.7/tests/test_frame_count_aliases.py +317 -0
- {lbm_suite2p_python-2.5.4 → lbm_suite2p_python-2.5.7}/LICENSE.md +0 -0
- {lbm_suite2p_python-2.5.4 → lbm_suite2p_python-2.5.7}/MANIFEST.in +0 -0
- {lbm_suite2p_python-2.5.4 → lbm_suite2p_python-2.5.7}/README.md +0 -0
- {lbm_suite2p_python-2.5.4 → lbm_suite2p_python-2.5.7}/lbm_suite2p_python/__init__.py +0 -0
- {lbm_suite2p_python-2.5.4 → lbm_suite2p_python-2.5.7}/lbm_suite2p_python/__main__.py +0 -0
- {lbm_suite2p_python-2.5.4 → lbm_suite2p_python-2.5.7}/lbm_suite2p_python/_benchmarking.py +0 -0
- {lbm_suite2p_python-2.5.4 → lbm_suite2p_python-2.5.7}/lbm_suite2p_python/cli.py +0 -0
- {lbm_suite2p_python-2.5.4 → lbm_suite2p_python-2.5.7}/lbm_suite2p_python/conversion.py +0 -0
- {lbm_suite2p_python-2.5.4 → lbm_suite2p_python-2.5.7}/lbm_suite2p_python/default_ops.py +0 -0
- {lbm_suite2p_python-2.5.4 → lbm_suite2p_python-2.5.7}/lbm_suite2p_python/gui.py +0 -0
- {lbm_suite2p_python-2.5.4 → lbm_suite2p_python-2.5.7}/lbm_suite2p_python/merging.py +0 -0
- {lbm_suite2p_python-2.5.4 → lbm_suite2p_python-2.5.7}/lbm_suite2p_python/volume.py +0 -0
- {lbm_suite2p_python-2.5.4 → lbm_suite2p_python-2.5.7}/lbm_suite2p_python.egg-info/dependency_links.txt +0 -0
- {lbm_suite2p_python-2.5.4 → lbm_suite2p_python-2.5.7}/lbm_suite2p_python.egg-info/entry_points.txt +0 -0
- {lbm_suite2p_python-2.5.4 → lbm_suite2p_python-2.5.7}/lbm_suite2p_python.egg-info/top_level.txt +0 -0
- {lbm_suite2p_python-2.5.4 → lbm_suite2p_python-2.5.7}/setup.cfg +0 -0
- {lbm_suite2p_python-2.5.4 → lbm_suite2p_python-2.5.7}/tests/test_pipeline_parameters.py +0 -0
- {lbm_suite2p_python-2.5.4 → lbm_suite2p_python-2.5.7}/tests/test_refactored_pipeline.py +0 -0
- {lbm_suite2p_python-2.5.4 → lbm_suite2p_python-2.5.7}/tests/test_run_volume.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: lbm_suite2p_python
|
|
3
|
-
Version: 2.5.
|
|
3
|
+
Version: 2.5.7
|
|
4
4
|
Summary: Light Beads Microscopy Pipeline using Suite2p
|
|
5
5
|
License-Expression: BSD-3-Clause
|
|
6
6
|
Project-URL: homepage, https://github.com/MillerBrainObservatory/LBM-Suite2p-Python
|
|
@@ -8,12 +8,12 @@ Keywords: Pipeline,Numpy,Microscopy,ScanImage,Suite2p,tiff
|
|
|
8
8
|
Classifier: Development Status :: 3 - Alpha
|
|
9
9
|
Classifier: Intended Audience :: Science/Research
|
|
10
10
|
Classifier: Programming Language :: Python :: 3 :: Only
|
|
11
|
-
Requires-Python: <3.
|
|
11
|
+
Requires-Python: <3.14,>=3.12.7
|
|
12
12
|
Description-Content-Type: text/markdown
|
|
13
13
|
License-File: LICENSE.md
|
|
14
|
-
Requires-Dist: mbo_utilities>=2.6.
|
|
15
|
-
|
|
16
|
-
Requires-Dist:
|
|
14
|
+
Requires-Dist: mbo_utilities>=2.6.3
|
|
15
|
+
Requires-Dist: suite2p_mbo>=2.0.1
|
|
16
|
+
Requires-Dist: setuptools<81
|
|
17
17
|
Provides-Extra: rastermap
|
|
18
18
|
Requires-Dist: rastermap; extra == "rastermap"
|
|
19
19
|
Provides-Extra: cellpose
|
|
@@ -22,7 +22,7 @@ Provides-Extra: torch
|
|
|
22
22
|
Requires-Dist: torch>=2.7.0; extra == "torch"
|
|
23
23
|
Requires-Dist: torchvision>=0.22.0; extra == "torch"
|
|
24
24
|
Provides-Extra: all
|
|
25
|
-
Requires-Dist: lbm_suite2p_python[cellpose,rastermap,
|
|
25
|
+
Requires-Dist: lbm_suite2p_python[cellpose,rastermap,torch]; extra == "all"
|
|
26
26
|
Dynamic: license-file
|
|
27
27
|
|
|
28
28
|
<p align="center">
|
|
@@ -37,9 +37,10 @@ def _compute_projection(
|
|
|
37
37
|
Parameters
|
|
38
38
|
----------
|
|
39
39
|
arr : array-like
|
|
40
|
-
Input array
|
|
40
|
+
Input array. mbo_utilities arrays are 5D TCZYX.
|
|
41
|
+
Legacy 4D TZYX and 3D TYX inputs are also supported.
|
|
41
42
|
plane_idx : int, optional
|
|
42
|
-
For
|
|
43
|
+
For volumetric arrays, which z-plane to extract (0-indexed).
|
|
43
44
|
If None, uses all planes for 3D segmentation.
|
|
44
45
|
method : str
|
|
45
46
|
Projection method: 'max', 'mean', 'std', or 'percentile'.
|
|
@@ -53,19 +54,23 @@ def _compute_projection(
|
|
|
53
54
|
"""
|
|
54
55
|
ndim = len(arr.shape)
|
|
55
56
|
|
|
56
|
-
if ndim ==
|
|
57
|
-
#
|
|
57
|
+
if ndim == 5:
|
|
58
|
+
# 5D TCZYX: use channel 0
|
|
59
|
+
if plane_idx is not None:
|
|
60
|
+
data = arr[:, 0, plane_idx, :, :] # (T, Y, X)
|
|
61
|
+
else:
|
|
62
|
+
data = arr[:, 0, :, :, :] # (T, Z, Y, X)
|
|
63
|
+
elif ndim == 4:
|
|
64
|
+
# legacy 4D TZYX
|
|
58
65
|
if plane_idx is not None:
|
|
59
|
-
# extract single plane -> (T, Y, X)
|
|
60
66
|
data = arr[:, plane_idx, :, :]
|
|
61
67
|
else:
|
|
62
|
-
# keep all planes -> (T, Z, Y, X)
|
|
63
68
|
data = arr[:]
|
|
64
69
|
elif ndim == 3:
|
|
65
|
-
#
|
|
70
|
+
# legacy 3D TYX
|
|
66
71
|
data = arr[:]
|
|
67
72
|
else:
|
|
68
|
-
raise ValueError(f"Expected 3D or
|
|
73
|
+
raise ValueError(f"Expected 3D, 4D, or 5D array, got {ndim}D")
|
|
69
74
|
|
|
70
75
|
# convert to numpy if lazy
|
|
71
76
|
if hasattr(data, "compute"):
|
|
@@ -577,18 +582,18 @@ def cellpose(
|
|
|
577
582
|
|
|
578
583
|
# get array info
|
|
579
584
|
shape = arr.shape
|
|
580
|
-
ndim = len(shape)
|
|
581
585
|
num_planes = _get_num_planes(arr)
|
|
582
586
|
num_frames = shape[0]
|
|
587
|
+
is_volumetric = num_planes > 1
|
|
583
588
|
|
|
584
589
|
print(f"\nDataset info:")
|
|
585
590
|
print(f" Shape: {shape}")
|
|
586
591
|
print(f" Frames: {num_frames}")
|
|
587
592
|
print(f" Planes: {num_planes}")
|
|
588
|
-
print(f" Data type: {'
|
|
593
|
+
print(f" Data type: {'volumetric' if is_volumetric else 'planar'}")
|
|
589
594
|
|
|
590
595
|
# normalize planes to 0-indexed list
|
|
591
|
-
if
|
|
596
|
+
if is_volumetric:
|
|
592
597
|
planes_to_process = _normalize_planes(planes, num_planes)
|
|
593
598
|
else:
|
|
594
599
|
planes_to_process = [None] # single plane data
|
|
@@ -246,12 +246,15 @@ def grid_search(
|
|
|
246
246
|
print(f"Processing plane {plane_num}")
|
|
247
247
|
print(f"{'='*60}")
|
|
248
248
|
|
|
249
|
-
# get plane dimensions
|
|
250
|
-
|
|
251
|
-
|
|
249
|
+
# get plane spatial dimensions
|
|
250
|
+
# mbo_utilities arrays are 5D TCZYX; legacy 4D TZYX and 3D TYX still supported
|
|
251
|
+
ndim = len(arr.shape)
|
|
252
|
+
if ndim == 5:
|
|
253
|
+
plane_Ly, plane_Lx = arr.shape[3], arr.shape[4]
|
|
254
|
+
elif ndim == 4:
|
|
255
|
+
plane_Ly, plane_Lx = arr.shape[2], arr.shape[3]
|
|
252
256
|
else:
|
|
253
|
-
|
|
254
|
-
plane_Ly, plane_Lx = sample_frame.shape[-2], sample_frame.shape[-1]
|
|
257
|
+
plane_Ly, plane_Lx = arr.shape[-2], arr.shape[-1]
|
|
255
258
|
|
|
256
259
|
# create plane subdirectory
|
|
257
260
|
plane_tag = f"plane{plane_num:02d}" if len(planes_to_process) > 1 else ""
|
|
@@ -300,18 +303,24 @@ def grid_search(
|
|
|
300
303
|
else:
|
|
301
304
|
print(f"\nUsing existing base binary: {base_bin_file}")
|
|
302
305
|
|
|
303
|
-
# run registration once on base
|
|
306
|
+
# run registration once on base (or skip if user disabled it)
|
|
304
307
|
base_reg_file = base_dir / "data.bin"
|
|
308
|
+
user_wants_reg = ops.get("do_registration", 1) not in (0, False)
|
|
309
|
+
|
|
305
310
|
if not base_reg_file.exists() or force_reg:
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
311
|
+
if user_wants_reg:
|
|
312
|
+
print(f"Running registration on base...")
|
|
313
|
+
reg_ops = copy.deepcopy(default_ops())
|
|
314
|
+
if base_ops_file.exists():
|
|
315
|
+
reg_ops.update(load_ops(base_ops_file))
|
|
316
|
+
reg_ops["do_registration"] = 1
|
|
317
|
+
reg_ops["roidetect"] = 0
|
|
318
|
+
np.save(base_ops_file, reg_ops)
|
|
319
|
+
run_plane_bin(base_ops_file)
|
|
320
|
+
print(f"Registration complete.")
|
|
321
|
+
else:
|
|
322
|
+
print(f"Registration disabled, using raw binary as base.")
|
|
323
|
+
shutil.copy2(base_bin_file, base_reg_file)
|
|
315
324
|
else:
|
|
316
325
|
print(f"Using existing registered binary: {base_reg_file}")
|
|
317
326
|
|
|
@@ -77,8 +77,12 @@ def _save_filtered_iscell(plane_dir, iscell_filtered, iscell_original=None):
|
|
|
77
77
|
iscell_path = plane_dir / "iscell.npy"
|
|
78
78
|
|
|
79
79
|
# Load original to preserve probabilities
|
|
80
|
-
if iscell_original is None
|
|
81
|
-
|
|
80
|
+
if iscell_original is None:
|
|
81
|
+
backup_path = plane_dir / "iscell_suite2p.npy"
|
|
82
|
+
if backup_path.exists():
|
|
83
|
+
iscell_original = np.load(backup_path, allow_pickle=True)
|
|
84
|
+
elif iscell_path.exists():
|
|
85
|
+
iscell_original = np.load(iscell_path, allow_pickle=True)
|
|
82
86
|
|
|
83
87
|
if iscell_original is not None and iscell_original.ndim == 2:
|
|
84
88
|
# Preserve probability column
|
|
@@ -611,7 +615,7 @@ def apply_filters(
|
|
|
611
615
|
|
|
612
616
|
# Save final result if requested
|
|
613
617
|
if save and plane_dir is not None:
|
|
614
|
-
_save_filtered_iscell(plane_dir, iscell_current)
|
|
618
|
+
_save_filtered_iscell(plane_dir, iscell_current, iscell_original=iscell_orig)
|
|
615
619
|
|
|
616
620
|
n_total = total_removed.sum()
|
|
617
621
|
n_orig = iscell_orig.sum()
|
|
@@ -1031,13 +1035,14 @@ def compute_trace_quality_score(
|
|
|
1031
1035
|
|
|
1032
1036
|
n_neurons = F.shape[0]
|
|
1033
1037
|
|
|
1034
|
-
#
|
|
1038
|
+
# neuropil correction and rectification
|
|
1035
1039
|
if Fneu is not None:
|
|
1036
1040
|
F_corr = F - 0.7 * Fneu
|
|
1037
1041
|
else:
|
|
1038
1042
|
F_corr = F
|
|
1043
|
+
F_corr = np.maximum(F_corr, 0)
|
|
1039
1044
|
|
|
1040
|
-
#
|
|
1045
|
+
# compute baseline and dF/F
|
|
1041
1046
|
baseline = np.percentile(F_corr, 20, axis=1, keepdims=True)
|
|
1042
1047
|
baseline = np.maximum(baseline, 1e-6)
|
|
1043
1048
|
dff = (F_corr - baseline) / baseline
|
|
@@ -1203,8 +1208,9 @@ def compute_roi_stats(plane_dir, fs=None):
|
|
|
1203
1208
|
|
|
1204
1209
|
n_rois = F.shape[0]
|
|
1205
1210
|
|
|
1206
|
-
# neuropil correction and dF/F
|
|
1211
|
+
# neuropil correction, rectify negatives, and dF/F
|
|
1207
1212
|
F_corr = F - 0.7 * Fneu
|
|
1213
|
+
F_corr = np.maximum(F_corr, 0)
|
|
1208
1214
|
baseline = np.percentile(F_corr, 20, axis=1, keepdims=True)
|
|
1209
1215
|
baseline = np.maximum(baseline, 1e-6)
|
|
1210
1216
|
dff = (F_corr - baseline) / baseline
|