spacr 0.4.15__py3-none-any.whl → 0.5.0__py3-none-any.whl
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.
- spacr/__init__.py +2 -2
- spacr/core.py +52 -10
- spacr/deep_spacr.py +2 -3
- spacr/gui.py +0 -1
- spacr/gui_core.py +247 -41
- spacr/gui_elements.py +133 -2
- spacr/gui_utils.py +22 -17
- spacr/io.py +624 -149
- spacr/ml.py +141 -258
- spacr/plot.py +76 -34
- spacr/resources/MEDIAR/__pycache__/SetupDict.cpython-39.pyc +0 -0
- spacr/resources/MEDIAR/__pycache__/evaluate.cpython-39.pyc +0 -0
- spacr/resources/MEDIAR/__pycache__/generate_mapping.cpython-39.pyc +0 -0
- spacr/resources/MEDIAR/__pycache__/main.cpython-39.pyc +0 -0
- spacr/resources/MEDIAR/core/Baseline/__pycache__/Predictor.cpython-39.pyc +0 -0
- spacr/resources/MEDIAR/core/Baseline/__pycache__/Trainer.cpython-39.pyc +0 -0
- spacr/resources/MEDIAR/core/Baseline/__pycache__/__init__.cpython-39.pyc +0 -0
- spacr/resources/MEDIAR/core/Baseline/__pycache__/utils.cpython-39.pyc +0 -0
- spacr/resources/MEDIAR/core/MEDIAR/__pycache__/EnsemblePredictor.cpython-39.pyc +0 -0
- spacr/resources/MEDIAR/core/MEDIAR/__pycache__/Predictor.cpython-39.pyc +0 -0
- spacr/resources/MEDIAR/core/MEDIAR/__pycache__/Trainer.cpython-39.pyc +0 -0
- spacr/resources/MEDIAR/core/MEDIAR/__pycache__/__init__.cpython-39.pyc +0 -0
- spacr/resources/MEDIAR/core/MEDIAR/__pycache__/utils.cpython-39.pyc +0 -0
- spacr/resources/MEDIAR/core/__pycache__/BasePredictor.cpython-39.pyc +0 -0
- spacr/resources/MEDIAR/core/__pycache__/BaseTrainer.cpython-39.pyc +0 -0
- spacr/resources/MEDIAR/core/__pycache__/__init__.cpython-39.pyc +0 -0
- spacr/resources/MEDIAR/core/__pycache__/utils.cpython-39.pyc +0 -0
- spacr/resources/MEDIAR/train_tools/__pycache__/__init__.cpython-39.pyc +0 -0
- spacr/resources/MEDIAR/train_tools/__pycache__/measures.cpython-39.pyc +0 -0
- spacr/resources/MEDIAR/train_tools/__pycache__/utils.cpython-39.pyc +0 -0
- spacr/resources/MEDIAR/train_tools/data_utils/__pycache__/__init__.cpython-39.pyc +0 -0
- spacr/resources/MEDIAR/train_tools/data_utils/__pycache__/datasetter.cpython-39.pyc +0 -0
- spacr/resources/MEDIAR/train_tools/data_utils/__pycache__/transforms.cpython-39.pyc +0 -0
- spacr/resources/MEDIAR/train_tools/data_utils/__pycache__/utils.cpython-39.pyc +0 -0
- spacr/resources/MEDIAR/train_tools/data_utils/custom/__pycache__/CellAware.cpython-39.pyc +0 -0
- spacr/resources/MEDIAR/train_tools/data_utils/custom/__pycache__/LoadImage.cpython-39.pyc +0 -0
- spacr/resources/MEDIAR/train_tools/data_utils/custom/__pycache__/NormalizeImage.cpython-39.pyc +0 -0
- spacr/resources/MEDIAR/train_tools/data_utils/custom/__pycache__/__init__.cpython-39.pyc +0 -0
- spacr/resources/MEDIAR/train_tools/models/__pycache__/MEDIARFormer.cpython-39.pyc +0 -0
- spacr/resources/MEDIAR/train_tools/models/__pycache__/__init__.cpython-39.pyc +0 -0
- spacr/sequencing.py +73 -38
- spacr/settings.py +161 -135
- spacr/submodules.py +618 -215
- spacr/timelapse.py +197 -29
- spacr/toxo.py +23 -23
- spacr/utils.py +186 -128
- {spacr-0.4.15.dist-info → spacr-0.5.0.dist-info}/METADATA +5 -2
- {spacr-0.4.15.dist-info → spacr-0.5.0.dist-info}/RECORD +53 -24
- spacr/stats.py +0 -221
- /spacr/{cellpose.py → spacr_cellpose.py} +0 -0
- {spacr-0.4.15.dist-info → spacr-0.5.0.dist-info}/LICENSE +0 -0
- {spacr-0.4.15.dist-info → spacr-0.5.0.dist-info}/WHEEL +0 -0
- {spacr-0.4.15.dist-info → spacr-0.5.0.dist-info}/entry_points.txt +0 -0
- {spacr-0.4.15.dist-info → spacr-0.5.0.dist-info}/top_level.txt +0 -0
spacr/gui_elements.py
CHANGED
@@ -726,8 +726,8 @@ class spacrProgressBar(ttk.Progressbar):
|
|
726
726
|
|
727
727
|
def set_label_position(self):
|
728
728
|
if self.label and self.progress_label:
|
729
|
-
row_info = self.grid_info().get('
|
730
|
-
col_info = self.grid_info().get('
|
729
|
+
row_info = self.grid_info().get('rowID', 0)
|
730
|
+
col_info = self.grid_info().get('columnID', 0)
|
731
731
|
col_span = self.grid_info().get('columnspan', 1)
|
732
732
|
self.progress_label.grid(row=row_info + 1, column=col_info, columnspan=col_span, pady=5, padx=5, sticky='ew')
|
733
733
|
|
@@ -2285,6 +2285,9 @@ class AnnotateApp:
|
|
2285
2285
|
|
2286
2286
|
self.train_button = Button(self.button_frame,text="orig.",command=self.swich_back_annotation_column,bg=self.bg_color,fg=self.fg_color,highlightbackground=self.fg_color,highlightcolor=self.fg_color,highlightthickness=1)
|
2287
2287
|
self.train_button.pack(side="right", padx=5)
|
2288
|
+
|
2289
|
+
self.settings_button = Button(self.button_frame, text="Settings", command=self.open_settings_window, bg=self.bg_color, fg=self.fg_color, highlightbackground=self.fg_color,highlightcolor=self.fg_color,highlightthickness=1)
|
2290
|
+
self.settings_button.pack(side="right", padx=5)
|
2288
2291
|
|
2289
2292
|
# Calculate grid rows and columns based on the root window size and image size
|
2290
2293
|
self.calculate_grid_dimensions()
|
@@ -2308,6 +2311,134 @@ class AnnotateApp:
|
|
2308
2311
|
for col in range(self.grid_cols):
|
2309
2312
|
self.grid_frame.grid_columnconfigure(col, weight=1)
|
2310
2313
|
|
2314
|
+
def open_settings_window(self):
|
2315
|
+
from .gui_utils import generate_annotate_fields, convert_to_number
|
2316
|
+
|
2317
|
+
# Create settings window
|
2318
|
+
settings_window = tk.Toplevel(self.root)
|
2319
|
+
settings_window.title("Modify Annotation Settings")
|
2320
|
+
|
2321
|
+
style_out = set_dark_style(ttk.Style())
|
2322
|
+
settings_window.configure(bg=style_out['bg_color'])
|
2323
|
+
|
2324
|
+
settings_frame = tk.Frame(settings_window, bg=style_out['bg_color'])
|
2325
|
+
settings_frame.pack(fill=tk.BOTH, expand=True)
|
2326
|
+
|
2327
|
+
# Generate fields with current settings pre-filled
|
2328
|
+
vars_dict = generate_annotate_fields(settings_frame)
|
2329
|
+
|
2330
|
+
# Pre-fill the current settings into vars_dict
|
2331
|
+
current_settings = {
|
2332
|
+
'image_type': self.image_type or '',
|
2333
|
+
'channels': ','.join(self.channels) if self.channels else '',
|
2334
|
+
'img_size': f"{self.image_size[0]},{self.image_size[1]}",
|
2335
|
+
'annotation_column': self.annotation_column or '',
|
2336
|
+
'normalize': str(self.normalize),
|
2337
|
+
'percentiles': ','.join(map(str, self.percentiles)),
|
2338
|
+
'measurement': ','.join(self.measurement) if self.measurement else '',
|
2339
|
+
'threshold': str(self.threshold) if self.threshold is not None else '',
|
2340
|
+
'normalize_channels': ','.join(self.normalize_channels) if self.normalize_channels else ''
|
2341
|
+
}
|
2342
|
+
|
2343
|
+
for key, data in vars_dict.items():
|
2344
|
+
if key in current_settings:
|
2345
|
+
data['entry'].delete(0, tk.END)
|
2346
|
+
data['entry'].insert(0, current_settings[key])
|
2347
|
+
|
2348
|
+
def apply_new_settings():
|
2349
|
+
settings = {key: data['entry'].get() for key, data in vars_dict.items()}
|
2350
|
+
|
2351
|
+
# Process settings exactly as your original initiation function does
|
2352
|
+
settings['channels'] = settings['channels'].split(',') if settings['channels'] else None
|
2353
|
+
settings['img_size'] = list(map(int, settings['img_size'].split(',')))
|
2354
|
+
settings['percentiles'] = list(map(convert_to_number, settings['percentiles'].split(','))) if settings['percentiles'] else [1, 99]
|
2355
|
+
settings['normalize'] = settings['normalize'].lower() == 'true'
|
2356
|
+
settings['normalize_channels'] = settings['normalize_channels'].split(',') if settings['normalize_channels'] else None
|
2357
|
+
|
2358
|
+
try:
|
2359
|
+
settings['measurement'] = settings['measurement'].split(',') if settings['measurement'] else None
|
2360
|
+
settings['threshold'] = None if settings['threshold'].lower() == 'none' else int(settings['threshold'])
|
2361
|
+
except:
|
2362
|
+
settings['measurement'] = None
|
2363
|
+
settings['threshold'] = None
|
2364
|
+
|
2365
|
+
# Convert empty strings to None
|
2366
|
+
for key, value in settings.items():
|
2367
|
+
if isinstance(value, list):
|
2368
|
+
settings[key] = [v if v != '' else None for v in value]
|
2369
|
+
elif value == '':
|
2370
|
+
settings[key] = None
|
2371
|
+
|
2372
|
+
# Apply these settings dynamically using update_settings method
|
2373
|
+
self.update_settings(**{
|
2374
|
+
'image_type': settings.get('image_type'),
|
2375
|
+
'channels': settings.get('channels'),
|
2376
|
+
'image_size': settings.get('img_size'),
|
2377
|
+
'annotation_column': settings.get('annotation_column'),
|
2378
|
+
'normalize': settings.get('normalize'),
|
2379
|
+
'percentiles': settings.get('percentiles'),
|
2380
|
+
'measurement': settings.get('measurement'),
|
2381
|
+
'threshold': settings.get('threshold'),
|
2382
|
+
'normalize_channels': settings.get('normalize_channels')
|
2383
|
+
})
|
2384
|
+
|
2385
|
+
settings_window.destroy()
|
2386
|
+
|
2387
|
+
apply_button = spacrButton(settings_window, text="Apply Settings", command=apply_new_settings,show_text=False)
|
2388
|
+
apply_button.pack(pady=10)
|
2389
|
+
|
2390
|
+
def update_settings(self, **kwargs):
|
2391
|
+
allowed_attributes = {
|
2392
|
+
'image_type', 'channels', 'image_size', 'annotation_column',
|
2393
|
+
'normalize', 'percentiles', 'measurement', 'threshold', 'normalize_channels'
|
2394
|
+
}
|
2395
|
+
|
2396
|
+
updated = False
|
2397
|
+
|
2398
|
+
for attr, value in kwargs.items():
|
2399
|
+
if attr in allowed_attributes and value is not None:
|
2400
|
+
setattr(self, attr, value)
|
2401
|
+
updated = True
|
2402
|
+
|
2403
|
+
if 'image_size' in kwargs:
|
2404
|
+
if isinstance(self.image_size, list):
|
2405
|
+
self.image_size = (int(self.image_size[0]), int(self.image_size[0]))
|
2406
|
+
elif isinstance(self.image_size, int):
|
2407
|
+
self.image_size = (self.image_size, self.image_size)
|
2408
|
+
else:
|
2409
|
+
raise ValueError("Invalid image size")
|
2410
|
+
|
2411
|
+
self.calculate_grid_dimensions()
|
2412
|
+
self.recreate_image_grid()
|
2413
|
+
|
2414
|
+
if updated:
|
2415
|
+
current_index = self.index # Retain current index
|
2416
|
+
self.prefilter_paths_annotations()
|
2417
|
+
|
2418
|
+
# Ensure the retained index is still valid (not out of bounds)
|
2419
|
+
max_index = len(self.filtered_paths_annotations) - 1
|
2420
|
+
self.index = min(current_index, max_index := max(0, max(0, max(len(self.filtered_paths_annotations) - self.grid_rows * self.grid_cols, 0))))
|
2421
|
+
self.load_images()
|
2422
|
+
|
2423
|
+
def recreate_image_grid(self):
|
2424
|
+
# Remove current labels
|
2425
|
+
for label in self.labels:
|
2426
|
+
label.destroy()
|
2427
|
+
self.labels.clear()
|
2428
|
+
|
2429
|
+
# Recreate the labels grid with updated dimensions
|
2430
|
+
for i in range(self.grid_rows * self.grid_cols):
|
2431
|
+
label = Label(self.grid_frame, bg=self.root.cget('bg'))
|
2432
|
+
label.grid(row=i // self.grid_cols, column=i % self.grid_cols, padx=2, pady=2, sticky="nsew")
|
2433
|
+
self.labels.append(label)
|
2434
|
+
|
2435
|
+
# Reconfigure grid weights
|
2436
|
+
for row in range(self.grid_rows):
|
2437
|
+
self.grid_frame.grid_rowconfigure(row, weight=1)
|
2438
|
+
for col in range(self.grid_cols):
|
2439
|
+
self.grid_frame.grid_columnconfigure(col, weight=1)
|
2440
|
+
|
2441
|
+
|
2311
2442
|
def swich_back_annotation_column(self):
|
2312
2443
|
self.annotation_column = self.orig_annotation_columns
|
2313
2444
|
self.prefilter_paths_annotations()
|
spacr/gui_utils.py
CHANGED
@@ -370,31 +370,32 @@ def convert_settings_dict_for_gui(settings):
|
|
370
370
|
chans_v4 = [0, 1, 2, 3, None]
|
371
371
|
variables = {}
|
372
372
|
special_cases = {
|
373
|
-
'metadata_type': ('combo', ['cellvoyager', 'cq1', '
|
373
|
+
'metadata_type': ('combo', ['cellvoyager', 'cq1', 'auto', 'custom'], 'cellvoyager'),
|
374
374
|
'channels': ('combo', chan_list, '[0,1,2,3]'),
|
375
375
|
'train_channels': ('combo', ["['r','g','b']", "['r','g']", "['r','b']", "['g','b']", "['r']", "['g']", "['b']"], "['r','g','b']"),
|
376
376
|
'channel_dims': ('combo', chan_list, '[0,1,2,3]'),
|
377
377
|
'dataset_mode': ('combo', ['annotation', 'metadata', 'recruitment'], 'metadata'),
|
378
378
|
'cov_type': ('combo', ['HC0', 'HC1', 'HC2', 'HC3', None], None),
|
379
|
-
'cell_mask_dim': ('combo',
|
380
|
-
'cell_chann_dim': ('combo',
|
381
|
-
'nucleus_mask_dim': ('combo',
|
382
|
-
'nucleus_chann_dim': ('combo',
|
383
|
-
'pathogen_mask_dim': ('combo',
|
384
|
-
'pathogen_chann_dim': ('combo',
|
379
|
+
#'cell_mask_dim': ('combo', chans_v3, None),
|
380
|
+
#'cell_chann_dim': ('combo', chans_v3, None),
|
381
|
+
#'nucleus_mask_dim': ('combo', chans_v3, None),
|
382
|
+
#'nucleus_chann_dim': ('combo', chans_v3, None),
|
383
|
+
#'pathogen_mask_dim': ('combo', chans_v3, None),
|
384
|
+
#'pathogen_chann_dim': ('combo', chans_v3, None),
|
385
385
|
'crop_mode': ('combo', ["['cell']", "['nucleus']", "['pathogen']", "['cell', 'nucleus']", "['cell', 'pathogen']", "['nucleus', 'pathogen']", "['cell', 'nucleus', 'pathogen']"], "['cell']"),
|
386
386
|
#'magnification': ('combo', [20, 40, 60], 20),
|
387
|
-
'nucleus_channel': ('combo', chans_v3, None),
|
388
|
-
'cell_channel': ('combo', chans_v3, None),
|
389
|
-
'channel_of_interest': ('combo', chans_v3, None),
|
390
|
-
'pathogen_channel': ('combo', chans_v3, None),
|
387
|
+
#'nucleus_channel': ('combo', chans_v3, None),
|
388
|
+
#'cell_channel': ('combo', chans_v3, None),
|
389
|
+
#'channel_of_interest': ('combo', chans_v3, None),
|
390
|
+
#'pathogen_channel': ('combo', chans_v3, None),
|
391
391
|
'timelapse_mode': ('combo', ['trackpy', 'btrack'], 'trackpy'),
|
392
392
|
'train_mode': ('combo', ['erm', 'irm'], 'erm'),
|
393
393
|
'clustering': ('combo', ['dbscan', 'kmean'], 'dbscan'),
|
394
394
|
'reduction_method': ('combo', ['umap', 'tsne'], 'umap'),
|
395
395
|
'model_name': ('combo', ['cyto', 'cyto_2', 'cyto_3', 'nuclei'], 'cyto'),
|
396
396
|
'regression_type': ('combo', ['ols','gls','wls','rlm','glm','mixed','quantile','logit','probit','poisson','lasso','ridge'], 'ols'),
|
397
|
-
'timelapse_objects': ('combo', ['cell', 'nucleus', 'pathogen', '
|
397
|
+
'timelapse_objects': ('combo', ["['cell']", "['nucleus']", "['pathogen']", "['cell', 'nucleus']", "['cell', 'pathogen']", "['nucleus', 'pathogen']", "['cell', 'nucleus', 'pathogen']", None], None),
|
398
|
+
#'timelapse_objects': ('combo', '[cell]', '[nucleus]', '[pathogen]', '[cytoplasm]', None, None),
|
398
399
|
'model_type': ('combo', torchvision_models, 'resnet50'),
|
399
400
|
'optimizer_type': ('combo', ['adamw', 'adam'], 'adamw'),
|
400
401
|
'schedule': ('combo', ['reduce_lr_on_plateau', 'step_lr'], 'reduce_lr_on_plateau'),
|
@@ -464,12 +465,13 @@ def function_gui_wrapper(function=None, settings={}, q=None, fig_queue=None, imp
|
|
464
465
|
finally:
|
465
466
|
# Restore the original plt.show function
|
466
467
|
plt.show = original_show
|
468
|
+
|
467
469
|
|
470
|
+
|
468
471
|
def run_function_gui(settings_type, settings, q, fig_queue, stop_requested):
|
469
472
|
|
470
|
-
from .gui_utils import process_stdout_stderr
|
471
473
|
from .core import generate_image_umap, preprocess_generate_masks
|
472
|
-
from .
|
474
|
+
from .spacr_cellpose import identify_masks_finetune, check_cellpose_models, compare_cellpose_masks
|
473
475
|
from .submodules import analyze_recruitment
|
474
476
|
from .ml import generate_ml_scores, perform_regression
|
475
477
|
from .submodules import train_cellpose, analyze_plaques
|
@@ -478,9 +480,10 @@ def run_function_gui(settings_type, settings, q, fig_queue, stop_requested):
|
|
478
480
|
from .sim import run_multiple_simulations
|
479
481
|
from .deep_spacr import deep_spacr, apply_model_to_tar
|
480
482
|
from .sequencing import generate_barecode_mapping
|
483
|
+
|
481
484
|
process_stdout_stderr(q)
|
482
|
-
|
483
|
-
print(f'run_function_gui settings_type: {settings_type}')
|
485
|
+
|
486
|
+
print(f'run_function_gui settings_type: {settings_type}')
|
484
487
|
|
485
488
|
if settings_type == 'mask':
|
486
489
|
function = preprocess_generate_masks
|
@@ -525,7 +528,7 @@ def run_function_gui(settings_type, settings, q, fig_queue, stop_requested):
|
|
525
528
|
function = process_non_tif_non_2D_images
|
526
529
|
imports = 1
|
527
530
|
else:
|
528
|
-
raise ValueError(f"Invalid settings type: {settings_type}")
|
531
|
+
raise ValueError(f"Error: Invalid settings type: {settings_type}")
|
529
532
|
try:
|
530
533
|
function_gui_wrapper(function, settings, q, fig_queue, imports)
|
531
534
|
except Exception as e:
|
@@ -937,8 +940,10 @@ def convert_to_number(value):
|
|
937
940
|
|
938
941
|
"""
|
939
942
|
Converts a string value to an integer if possible, otherwise converts to a float.
|
943
|
+
|
940
944
|
Args:
|
941
945
|
value (str): The string representation of the number.
|
946
|
+
|
942
947
|
Returns:
|
943
948
|
int or float: The converted number.
|
944
949
|
"""
|