lbm_suite2p_python 2.0.2__tar.gz → 2.0.4__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.0.2/lbm_suite2p_python.egg-info → lbm_suite2p_python-2.0.4}/PKG-INFO +2 -2
- {lbm_suite2p_python-2.0.2 → lbm_suite2p_python-2.0.4}/lbm_suite2p_python/postprocessing.py +42 -0
- {lbm_suite2p_python-2.0.2 → lbm_suite2p_python-2.0.4}/lbm_suite2p_python/run_lsp.py +150 -81
- {lbm_suite2p_python-2.0.2 → lbm_suite2p_python-2.0.4/lbm_suite2p_python.egg-info}/PKG-INFO +2 -2
- {lbm_suite2p_python-2.0.2 → lbm_suite2p_python-2.0.4}/lbm_suite2p_python.egg-info/requires.txt +1 -1
- {lbm_suite2p_python-2.0.2 → lbm_suite2p_python-2.0.4}/pyproject.toml +2 -2
- {lbm_suite2p_python-2.0.2 → lbm_suite2p_python-2.0.4}/LICENSE.md +0 -0
- {lbm_suite2p_python-2.0.2 → lbm_suite2p_python-2.0.4}/MANIFEST.in +0 -0
- {lbm_suite2p_python-2.0.2 → lbm_suite2p_python-2.0.4}/README.md +0 -0
- {lbm_suite2p_python-2.0.2 → lbm_suite2p_python-2.0.4}/lbm_suite2p_python/__init__.py +0 -0
- {lbm_suite2p_python-2.0.2 → lbm_suite2p_python-2.0.4}/lbm_suite2p_python/__main__.py +0 -0
- {lbm_suite2p_python-2.0.2 → lbm_suite2p_python-2.0.4}/lbm_suite2p_python/_benchmarking.py +0 -0
- {lbm_suite2p_python-2.0.2 → lbm_suite2p_python-2.0.4}/lbm_suite2p_python/default_ops.py +0 -0
- {lbm_suite2p_python-2.0.2 → lbm_suite2p_python-2.0.4}/lbm_suite2p_python/merging.py +0 -0
- {lbm_suite2p_python-2.0.2 → lbm_suite2p_python-2.0.4}/lbm_suite2p_python/utils.py +0 -0
- {lbm_suite2p_python-2.0.2 → lbm_suite2p_python-2.0.4}/lbm_suite2p_python/volume.py +0 -0
- {lbm_suite2p_python-2.0.2 → lbm_suite2p_python-2.0.4}/lbm_suite2p_python/zplane.py +0 -0
- {lbm_suite2p_python-2.0.2 → lbm_suite2p_python-2.0.4}/lbm_suite2p_python.egg-info/SOURCES.txt +0 -0
- {lbm_suite2p_python-2.0.2 → lbm_suite2p_python-2.0.4}/lbm_suite2p_python.egg-info/dependency_links.txt +0 -0
- {lbm_suite2p_python-2.0.2 → lbm_suite2p_python-2.0.4}/lbm_suite2p_python.egg-info/entry_points.txt +0 -0
- {lbm_suite2p_python-2.0.2 → lbm_suite2p_python-2.0.4}/lbm_suite2p_python.egg-info/top_level.txt +0 -0
- {lbm_suite2p_python-2.0.2 → lbm_suite2p_python-2.0.4}/setup.cfg +0 -0
- {lbm_suite2p_python-2.0.2 → lbm_suite2p_python-2.0.4}/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.0.
|
|
3
|
+
Version: 2.0.4
|
|
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
|
|
@@ -11,7 +11,7 @@ Classifier: Programming Language :: Python :: 3 :: Only
|
|
|
11
11
|
Requires-Python: <3.12.10,>=3.12.7
|
|
12
12
|
Description-Content-Type: text/markdown
|
|
13
13
|
License-File: LICENSE.md
|
|
14
|
-
Requires-Dist: mbo_utilities>=2.0.
|
|
14
|
+
Requires-Dist: mbo_utilities>=2.0.4
|
|
15
15
|
Provides-Extra: cpsam
|
|
16
16
|
Requires-Dist: cellpose==4.0.6; extra == "cpsam"
|
|
17
17
|
Requires-Dist: pytorch; extra == "cpsam"
|
|
@@ -13,6 +13,7 @@ def _normalize_iscell(iscell):
|
|
|
13
13
|
iscell = iscell[:, 0]
|
|
14
14
|
return iscell.astype(bool)
|
|
15
15
|
|
|
16
|
+
|
|
16
17
|
def filter_by_diameter(iscell, stat, ops, min_mult=0.3, max_mult=3.0):
|
|
17
18
|
"""
|
|
18
19
|
Set iscell=False for ROIs whose radius is out of range relative to ops['diameter'].
|
|
@@ -97,6 +98,7 @@ def mode_robust(x):
|
|
|
97
98
|
j = i
|
|
98
99
|
return mode_robust(x[j:j+N+1])
|
|
99
100
|
|
|
101
|
+
|
|
100
102
|
def compute_event_exceptionality(traces, N=5, robust_std=False):
|
|
101
103
|
"""
|
|
102
104
|
traces: ndarray (n_cells x T)
|
|
@@ -430,3 +432,43 @@ def load_ops(ops_input: str | Path | list[str | Path]) -> dict:
|
|
|
430
432
|
return {}
|
|
431
433
|
|
|
432
434
|
|
|
435
|
+
def load_traces(ops):
|
|
436
|
+
"""
|
|
437
|
+
Load fluorescence traces and related data from an ops file directory and return valid cells.
|
|
438
|
+
|
|
439
|
+
This function loads the raw fluorescence traces, neuropil traces, and spike data from the directory
|
|
440
|
+
specified in the ops dictionary. It also loads the 'iscell' file and returns only the traces corresponding
|
|
441
|
+
to valid cells (i.e. where iscell is True).
|
|
442
|
+
|
|
443
|
+
Parameters
|
|
444
|
+
----------
|
|
445
|
+
ops : dict
|
|
446
|
+
Dictionary containing at least the key 'save_path', which specifies the directory where the following
|
|
447
|
+
files are stored: 'F.npy', 'Fneu.npy', 'spks.npy', and 'iscell.npy'.
|
|
448
|
+
|
|
449
|
+
Returns
|
|
450
|
+
-------
|
|
451
|
+
F_valid : ndarray
|
|
452
|
+
Array of fluorescence traces for valid cells (n_valid x n_timepoints).
|
|
453
|
+
Fneu_valid : ndarray
|
|
454
|
+
Array of neuropil fluorescence traces for valid cells (n_valid x n_timepoints).
|
|
455
|
+
spks_valid : ndarray
|
|
456
|
+
Array of spike data for valid cells (n_valid x n_timepoints).
|
|
457
|
+
|
|
458
|
+
Notes
|
|
459
|
+
-----
|
|
460
|
+
The 'iscell.npy' file is expected to be an array where the first column (iscell[:, 0]) contains
|
|
461
|
+
boolean values indicating valid cells.
|
|
462
|
+
"""
|
|
463
|
+
save_path = Path(ops['save_path'])
|
|
464
|
+
F = np.load(save_path.joinpath('F.npy'))
|
|
465
|
+
Fneu = np.load(save_path.joinpath('Fneu.npy'))
|
|
466
|
+
spks = np.load(save_path.joinpath('spks.npy'))
|
|
467
|
+
iscell = np.load(save_path.joinpath('iscell.npy'), allow_pickle=True)[:, 0].astype(bool)
|
|
468
|
+
|
|
469
|
+
F_valid = F[iscell]
|
|
470
|
+
Fneu_valid = Fneu[iscell]
|
|
471
|
+
spks_valid = spks[iscell]
|
|
472
|
+
|
|
473
|
+
return F_valid, Fneu_valid, spks_valid
|
|
474
|
+
|
|
@@ -18,10 +18,7 @@ from lbm_suite2p_python.postprocessing import (
|
|
|
18
18
|
)
|
|
19
19
|
from mbo_utilities.log import get as get_logger
|
|
20
20
|
|
|
21
|
-
from lbm_suite2p_python.zplane import
|
|
22
|
-
save_pc_panels_and_metrics,
|
|
23
|
-
plot_zplane_figures
|
|
24
|
-
)
|
|
21
|
+
from lbm_suite2p_python.zplane import save_pc_panels_and_metrics, plot_zplane_figures
|
|
25
22
|
|
|
26
23
|
logger = get_logger("run_lsp")
|
|
27
24
|
|
|
@@ -31,7 +28,9 @@ from lbm_suite2p_python.volume import (
|
|
|
31
28
|
plot_volume_neuron_counts,
|
|
32
29
|
get_volume_stats,
|
|
33
30
|
)
|
|
34
|
-
from mbo_utilities.file_io import
|
|
31
|
+
from mbo_utilities.file_io import (
|
|
32
|
+
get_plane_from_filename,
|
|
33
|
+
) # derive_tag_from_filename, PIPELINE_TAGS
|
|
35
34
|
|
|
36
35
|
PIPELINE_TAGS = ("plane", "roi", "z", "plane_", "roi_", "z_")
|
|
37
36
|
|
|
@@ -160,6 +159,7 @@ def run_volume(
|
|
|
160
159
|
- Optional rastermap clustering results
|
|
161
160
|
"""
|
|
162
161
|
from mbo_utilities.file_io import get_files, get_plane_from_filename
|
|
162
|
+
|
|
163
163
|
start = time.time()
|
|
164
164
|
if save_path is None:
|
|
165
165
|
save_path = Path(input_files[0]).parent
|
|
@@ -204,6 +204,7 @@ def run_volume(
|
|
|
204
204
|
if "roi" in Path(input_files[0]).stem.lower():
|
|
205
205
|
print("Detected mROI data, merging ROIs for each z-plane...")
|
|
206
206
|
from .merging import merge_mrois
|
|
207
|
+
|
|
207
208
|
merged_savepath = save_path.joinpath("merged_mrois")
|
|
208
209
|
merge_mrois(save_path, merged_savepath)
|
|
209
210
|
save_path = merged_savepath
|
|
@@ -271,90 +272,144 @@ def run_volume(
|
|
|
271
272
|
|
|
272
273
|
def _should_write_bin(ops_path: Path, force: bool = False) -> bool:
|
|
273
274
|
"""
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
Conditions that trigger re-write:
|
|
277
|
-
- force=True
|
|
278
|
-
- bin file missing
|
|
279
|
-
- ops.npy missing
|
|
280
|
-
- mismatch between ops metadata (Ly, Lx, nframes) and bin file size
|
|
281
|
-
- bin file cannot be read or has wrong shape
|
|
275
|
+
Return True if data_raw.bin should be re-written.
|
|
282
276
|
"""
|
|
283
277
|
if force:
|
|
284
278
|
return True
|
|
279
|
+
|
|
285
280
|
ops_path = Path(ops_path)
|
|
286
281
|
if not ops_path.is_file():
|
|
287
282
|
return True
|
|
288
283
|
|
|
289
|
-
|
|
290
|
-
|
|
284
|
+
raw_path = ops_path.parent / "data_raw.bin"
|
|
285
|
+
chan2_path = ops_path.parent / "data_chan2.bin"
|
|
291
286
|
|
|
292
|
-
|
|
287
|
+
# no raw data at all
|
|
288
|
+
if not raw_path.is_file() and not chan2_path.is_file():
|
|
293
289
|
return True
|
|
294
290
|
|
|
295
291
|
try:
|
|
296
292
|
ops = np.load(ops_path, allow_pickle=True).item()
|
|
297
|
-
Ly, Lx = ops.get("Ly"), ops.get("Lx")
|
|
298
|
-
nframes = ops.get("nframes", ops.get("n_frames"))
|
|
299
293
|
|
|
300
|
-
|
|
301
|
-
|
|
294
|
+
for bin_path in (raw_path, chan2_path):
|
|
295
|
+
if not bin_path.is_file():
|
|
296
|
+
continue
|
|
302
297
|
|
|
303
|
-
|
|
304
|
-
|
|
298
|
+
if "chan2" in bin_path.name:
|
|
299
|
+
nframes = ops.get("nframes_chan2")
|
|
300
|
+
else:
|
|
301
|
+
nframes = (
|
|
302
|
+
ops.get("nframes_chan1")
|
|
303
|
+
or ops.get("nframes")
|
|
304
|
+
or ops.get("num_frames")
|
|
305
|
+
)
|
|
305
306
|
|
|
306
|
-
|
|
307
|
-
|
|
307
|
+
Ly, Lx = ops.get("Ly"), ops.get("Lx")
|
|
308
|
+
if None in (Ly, Lx, nframes):
|
|
309
|
+
return True
|
|
308
310
|
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
311
|
+
expected_size = nframes * Ly * Lx * np.dtype(np.int16).itemsize
|
|
312
|
+
actual_size = bin_path.stat().st_size
|
|
313
|
+
if actual_size != expected_size:
|
|
314
|
+
return True
|
|
315
|
+
|
|
316
|
+
# lightweight validation read
|
|
317
|
+
arr = np.memmap(bin_path, dtype=np.int16, mode="r", shape=(nframes, Ly, Lx))
|
|
318
|
+
_ = arr[0, 0, 0]
|
|
319
|
+
del arr
|
|
313
320
|
|
|
314
321
|
return False # all checks passed
|
|
322
|
+
|
|
315
323
|
except Exception as e:
|
|
316
|
-
print(f"Bin validation failed: {e}")
|
|
324
|
+
print(f"Bin validation failed for {ops_path.parent}: {e}")
|
|
317
325
|
return True
|
|
318
326
|
|
|
319
327
|
|
|
328
|
+
def _should_register(ops_path: str | Path) -> bool:
|
|
329
|
+
"""
|
|
330
|
+
Determine whether Suite2p registration still needs to be performed.
|
|
331
|
+
|
|
332
|
+
Registration is considered complete if any of the following hold:
|
|
333
|
+
- A reference image (refImg) exists and is a valid ndarray
|
|
334
|
+
- meanImg exists (Suite2p always produces it post-registration)
|
|
335
|
+
- Valid registration offsets (xoff/yoff) are present
|
|
336
|
+
|
|
337
|
+
Returns True if registration *should* be run, False otherwise.
|
|
338
|
+
"""
|
|
339
|
+
ops = load_ops(ops_path)
|
|
340
|
+
|
|
341
|
+
has_ref = isinstance(ops.get("refImg"), np.ndarray)
|
|
342
|
+
has_mean = isinstance(ops.get("meanImg"), np.ndarray)
|
|
343
|
+
has_offsets = ("xoff" in ops and np.any(np.isfinite(ops["xoff"]))) or (
|
|
344
|
+
"yoff" in ops and np.any(np.isfinite(ops["yoff"]))
|
|
345
|
+
)
|
|
346
|
+
has_metrics = any(k in ops for k in ("regDX", "regPC", "regPC1", "regDX1"))
|
|
347
|
+
|
|
348
|
+
# registration done if any of these are true
|
|
349
|
+
registration_done = has_ref or has_mean or has_offsets or has_metrics
|
|
350
|
+
return not registration_done
|
|
351
|
+
|
|
352
|
+
|
|
320
353
|
def run_plane_bin(ops) -> bool:
|
|
321
|
-
from
|
|
354
|
+
from mbo_utilities._binary import BinaryFile
|
|
322
355
|
from suite2p.run_s2p import pipeline
|
|
356
|
+
from contextlib import nullcontext
|
|
357
|
+
|
|
323
358
|
ops = load_ops(ops)
|
|
324
|
-
if "nframes" in ops and "n_frames" not in ops:
|
|
325
|
-
ops["n_frames"] = ops["nframes"]
|
|
326
|
-
if "n_frames" not in ops:
|
|
327
|
-
raise KeyError("run_plane_bin: missing frame count (nframes or n_frames)")
|
|
328
|
-
n_frames = ops["n_frames"]
|
|
329
359
|
Ly, Lx = ops["Ly"], ops["Lx"]
|
|
330
360
|
|
|
331
|
-
#
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
361
|
+
# input functional channel (unregistered)
|
|
362
|
+
raw_file = ops.get("raw_file")
|
|
363
|
+
nframes_chan1 = (
|
|
364
|
+
ops.get("nframes_chan1") or ops.get("nframes") or ops.get("n_frames")
|
|
365
|
+
)
|
|
366
|
+
if raw_file is None or nframes_chan1 is None:
|
|
367
|
+
raise KeyError("Missing raw_file or nframes_chan1")
|
|
368
|
+
|
|
369
|
+
# optional structural channel
|
|
370
|
+
chan2_file = ops.get("chan2_file", "")
|
|
371
|
+
nframes_chan2 = ops.get("nframes_chan2", 0)
|
|
372
|
+
|
|
373
|
+
ops_parent = Path(ops.get("ops_path")).parent
|
|
374
|
+
ops["save_path"] = ops_parent
|
|
339
375
|
|
|
376
|
+
align_structural = ops.get("align_by_chan", 1) == 2
|
|
377
|
+
ops["align_structural"] = align_structural
|
|
378
|
+
|
|
379
|
+
reg_file = ops_parent / "data.bin"
|
|
380
|
+
ops["reg_file"] = str(reg_file)
|
|
381
|
+
|
|
382
|
+
# sanity fix for diameter
|
|
383
|
+
if "diameter" in ops:
|
|
384
|
+
if ops["diameter"] is not None and np.isnan(ops["diameter"]):
|
|
385
|
+
ops["diameter"] = 8
|
|
386
|
+
if (ops["diameter"] is None or ops["diameter"] == 0) and ops.get(
|
|
387
|
+
"anatomical_only", 0
|
|
388
|
+
) > 0:
|
|
389
|
+
ops["diameter"] = 8
|
|
390
|
+
print("Warning: diameter was not set, defaulting to 8.")
|
|
391
|
+
|
|
392
|
+
with (
|
|
340
393
|
BinaryFile(
|
|
341
|
-
Ly=Ly, Lx=Lx, filename=
|
|
394
|
+
Ly=Ly, Lx=Lx, filename=str(reg_file), n_frames=nframes_chan1
|
|
342
395
|
) as f_reg,
|
|
396
|
+
BinaryFile(Ly=Ly, Lx=Lx, filename=raw_file, n_frames=nframes_chan1) as f_raw,
|
|
343
397
|
(
|
|
344
|
-
BinaryFile(
|
|
345
|
-
|
|
346
|
-
)
|
|
347
|
-
if "raw_file" in ops and ops["raw_file"] is not None
|
|
398
|
+
BinaryFile(Ly=Ly, Lx=Lx, filename=chan2_file, n_frames=nframes_chan2)
|
|
399
|
+
if align_structural
|
|
348
400
|
else nullcontext()
|
|
349
|
-
) as
|
|
401
|
+
) as f_reg_chan2,
|
|
350
402
|
):
|
|
351
403
|
ops = pipeline(
|
|
352
|
-
f_reg,
|
|
404
|
+
f_reg=f_reg,
|
|
405
|
+
f_raw=f_raw,
|
|
406
|
+
f_reg_chan2=f_reg_chan2,
|
|
407
|
+
f_raw_chan2=f_reg_chan2 if align_structural else None,
|
|
408
|
+
run_registration=ops.get("do_registration", True),
|
|
409
|
+
ops=ops,
|
|
410
|
+
stat=None,
|
|
353
411
|
)
|
|
354
|
-
|
|
355
412
|
np.save(ops["ops_path"], ops)
|
|
356
|
-
del f_reg, f_raw, ops
|
|
357
|
-
|
|
358
413
|
return True
|
|
359
414
|
|
|
360
415
|
|
|
@@ -441,18 +496,18 @@ def run_plane(
|
|
|
441
496
|
logger.setLevel(logging.DEBUG)
|
|
442
497
|
logger.info("Debug mode enabled.")
|
|
443
498
|
|
|
444
|
-
assert isinstance(
|
|
445
|
-
|
|
446
|
-
)
|
|
499
|
+
assert isinstance(
|
|
500
|
+
input_path, (Path, str)
|
|
501
|
+
), f"input_path should be a pathlib.Path or string, not: {type(input_path)}"
|
|
447
502
|
input_path = Path(input_path)
|
|
448
503
|
if not input_path.is_file():
|
|
449
504
|
if input_path.suffix != ".zarr":
|
|
450
505
|
raise ValueError(f"Input file does not exist: {input_path}")
|
|
451
506
|
input_parent = input_path.parent
|
|
452
507
|
|
|
453
|
-
assert isinstance(
|
|
454
|
-
|
|
455
|
-
)
|
|
508
|
+
assert isinstance(
|
|
509
|
+
save_path, (Path, str, type(None))
|
|
510
|
+
), f"save_path should be a pathlib.Path or string, not: {type(save_path)}"
|
|
456
511
|
if save_path is None:
|
|
457
512
|
logger.debug(f"save_path is None, using parent of input file: {input_parent}")
|
|
458
513
|
save_path = input_parent
|
|
@@ -469,8 +524,11 @@ def run_plane(
|
|
|
469
524
|
ops = {**ops_default, **ops_user, "data_path": str(input_path.resolve())}
|
|
470
525
|
|
|
471
526
|
# suite2p diameter handling
|
|
472
|
-
if
|
|
473
|
-
|
|
527
|
+
if (
|
|
528
|
+
isinstance(ops["diameter"], list)
|
|
529
|
+
and len(ops["diameter"]) > 1
|
|
530
|
+
and ops["aspect"] == 1.0
|
|
531
|
+
):
|
|
474
532
|
ops["aspect"] = ops["diameter"][0] / ops["diameter"][1] # noqa
|
|
475
533
|
|
|
476
534
|
file = imread(input_path)
|
|
@@ -519,7 +577,8 @@ def run_plane(
|
|
|
519
577
|
else:
|
|
520
578
|
print(
|
|
521
579
|
f"ops['roidetect'] is True with no stat.npy file present, "
|
|
522
|
-
f"proceeding with segmentation/detection for plane {plane}."
|
|
580
|
+
f"proceeding with segmentation/detection for plane {plane}."
|
|
581
|
+
)
|
|
523
582
|
needs_detect = True
|
|
524
583
|
elif (plane_dir / "stat.npy").is_file():
|
|
525
584
|
# check contents of stat.npy
|
|
@@ -532,8 +591,6 @@ def run_plane(
|
|
|
532
591
|
needs_detect = True
|
|
533
592
|
|
|
534
593
|
ops_file = plane_dir / "ops.npy"
|
|
535
|
-
reg_data_file = plane_dir / "data.bin"
|
|
536
|
-
reg_data_file_tiff = plane_dir / "reg_tif"
|
|
537
594
|
|
|
538
595
|
if _should_write_bin(ops_file, force=kwargs.get("force_save", False)):
|
|
539
596
|
md_combined = {**metadata, **ops}
|
|
@@ -549,17 +606,13 @@ def run_plane(
|
|
|
549
606
|
else {}
|
|
550
607
|
)
|
|
551
608
|
|
|
552
|
-
exists = False
|
|
553
|
-
if reg_data_file.exists():
|
|
554
|
-
exists = True
|
|
555
|
-
if reg_data_file_tiff.exists():
|
|
556
|
-
exists = True
|
|
557
609
|
if force_reg:
|
|
558
610
|
needs_reg = True
|
|
559
611
|
else:
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
612
|
+
if not ops_file.exists():
|
|
613
|
+
needs_reg = True
|
|
614
|
+
else:
|
|
615
|
+
needs_reg = _should_register(ops_file)
|
|
563
616
|
ops = {
|
|
564
617
|
**ops_default,
|
|
565
618
|
**ops_outpath,
|
|
@@ -598,11 +651,13 @@ def run_plane(
|
|
|
598
651
|
print(f"Skipping {ops_file.name}, processing was not completed.")
|
|
599
652
|
return ops_file
|
|
600
653
|
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
if not
|
|
605
|
-
|
|
654
|
+
raw_file = Path(ops.get("raw_file", plane_dir / "data_raw.bin"))
|
|
655
|
+
reg_file = Path(ops.get("reg_file", plane_dir / "data.bin"))
|
|
656
|
+
|
|
657
|
+
if not keep_raw and raw_file.exists():
|
|
658
|
+
raw_file.unlink(missing_ok=True)
|
|
659
|
+
if not keep_reg and reg_file.exists():
|
|
660
|
+
reg_file.unlink(missing_ok=True)
|
|
606
661
|
|
|
607
662
|
save_pc_panels_and_metrics(ops_file, plane_dir / "pc_metrics")
|
|
608
663
|
|
|
@@ -623,6 +678,8 @@ def run_grid_search(
|
|
|
623
678
|
grid_search_dict: dict,
|
|
624
679
|
input_file: Path | str,
|
|
625
680
|
save_root: Path | str,
|
|
681
|
+
force_reg: bool,
|
|
682
|
+
force_detect: bool,
|
|
626
683
|
):
|
|
627
684
|
"""
|
|
628
685
|
Run a grid search over all combinations of the input suite2p parameters.
|
|
@@ -643,6 +700,12 @@ def run_grid_search(
|
|
|
643
700
|
Root directory where each parameter combination's output will be saved.
|
|
644
701
|
A subdirectory will be created for each run using a short parameter tag.
|
|
645
702
|
|
|
703
|
+
force_reg : bool
|
|
704
|
+
Whether to force suite2p registration.
|
|
705
|
+
|
|
706
|
+
force_detect : bool
|
|
707
|
+
Whether to force suite2p detection.
|
|
708
|
+
|
|
646
709
|
Notes
|
|
647
710
|
-----
|
|
648
711
|
- Subfolder names for each parameter are abbreviated to 3-character keys and truncated/rounded values.
|
|
@@ -695,16 +758,22 @@ def run_grid_search(
|
|
|
695
758
|
for k, v in combo_dict.items()
|
|
696
759
|
]
|
|
697
760
|
tag = "_".join(tag_parts)
|
|
761
|
+
save_path = save_root / tag
|
|
762
|
+
print(f"\nRunning grid search combination: {tag}")
|
|
698
763
|
|
|
699
|
-
|
|
764
|
+
ops_file = save_path / "ops.npy"
|
|
765
|
+
|
|
766
|
+
# Skip runs that are already registered
|
|
767
|
+
if ops_file.exists() and not force_reg and not _should_register(ops_file):
|
|
768
|
+
print(f"Skipping {tag}: registration already complete.")
|
|
769
|
+
continue
|
|
700
770
|
|
|
701
|
-
save_path = save_root / tag
|
|
702
771
|
run_plane(
|
|
703
772
|
input_path=input_file,
|
|
704
773
|
save_path=save_path,
|
|
705
774
|
ops=ops,
|
|
706
775
|
keep_reg=True,
|
|
707
776
|
keep_raw=True,
|
|
708
|
-
force_reg=
|
|
709
|
-
force_detect=
|
|
777
|
+
force_reg=force_reg,
|
|
778
|
+
force_detect=force_detect,
|
|
710
779
|
)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: lbm_suite2p_python
|
|
3
|
-
Version: 2.0.
|
|
3
|
+
Version: 2.0.4
|
|
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
|
|
@@ -11,7 +11,7 @@ Classifier: Programming Language :: Python :: 3 :: Only
|
|
|
11
11
|
Requires-Python: <3.12.10,>=3.12.7
|
|
12
12
|
Description-Content-Type: text/markdown
|
|
13
13
|
License-File: LICENSE.md
|
|
14
|
-
Requires-Dist: mbo_utilities>=2.0.
|
|
14
|
+
Requires-Dist: mbo_utilities>=2.0.4
|
|
15
15
|
Provides-Extra: cpsam
|
|
16
16
|
Requires-Dist: cellpose==4.0.6; extra == "cpsam"
|
|
17
17
|
Requires-Dist: pytorch; extra == "cpsam"
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "lbm_suite2p_python"
|
|
7
|
-
version = "2.0.
|
|
7
|
+
version = "2.0.4"
|
|
8
8
|
description = "Light Beads Microscopy Pipeline using Suite2p"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = "BSD-3-Clause"
|
|
@@ -18,7 +18,7 @@ classifiers=[
|
|
|
18
18
|
"Programming Language :: Python :: 3 :: Only",
|
|
19
19
|
]
|
|
20
20
|
dependencies = [
|
|
21
|
-
"mbo_utilities>=2.0.
|
|
21
|
+
"mbo_utilities>=2.0.4",
|
|
22
22
|
]
|
|
23
23
|
|
|
24
24
|
[project.optional-dependencies]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{lbm_suite2p_python-2.0.2 → lbm_suite2p_python-2.0.4}/lbm_suite2p_python.egg-info/SOURCES.txt
RENAMED
|
File without changes
|
|
File without changes
|
{lbm_suite2p_python-2.0.2 → lbm_suite2p_python-2.0.4}/lbm_suite2p_python.egg-info/entry_points.txt
RENAMED
|
File without changes
|
{lbm_suite2p_python-2.0.2 → lbm_suite2p_python-2.0.4}/lbm_suite2p_python.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|