spacr 0.2.53__py3-none-any.whl → 0.2.56__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/core.py +282 -10
- spacr/deep_spacr.py +101 -41
- spacr/gui.py +1 -1
- spacr/gui_core.py +8 -10
- spacr/gui_elements.py +70 -0
- spacr/gui_utils.py +30 -10
- spacr/io.py +12 -4
- spacr/sequencing.py +443 -643
- spacr/settings.py +176 -44
- spacr/utils.py +13 -5
- {spacr-0.2.53.dist-info → spacr-0.2.56.dist-info}/METADATA +2 -1
- {spacr-0.2.53.dist-info → spacr-0.2.56.dist-info}/RECORD +16 -16
- {spacr-0.2.53.dist-info → spacr-0.2.56.dist-info}/LICENSE +0 -0
- {spacr-0.2.53.dist-info → spacr-0.2.56.dist-info}/WHEEL +0 -0
- {spacr-0.2.53.dist-info → spacr-0.2.56.dist-info}/entry_points.txt +0 -0
- {spacr-0.2.53.dist-info → spacr-0.2.56.dist-info}/top_level.txt +0 -0
spacr/gui_core.py
CHANGED
@@ -15,7 +15,7 @@ try:
|
|
15
15
|
except AttributeError:
|
16
16
|
pass
|
17
17
|
|
18
|
-
from .settings import set_default_train_test_model, get_measure_crop_settings, set_default_settings_preprocess_generate_masks,
|
18
|
+
from .settings import set_default_train_test_model, get_measure_crop_settings, set_default_settings_preprocess_generate_masks, set_default_generate_barecode_mapping, set_default_umap_image_settings
|
19
19
|
from .gui_elements import spacrProgressBar, spacrButton, spacrLabel, spacrFrame, spacrDropdownMenu ,set_dark_style
|
20
20
|
|
21
21
|
# Define global variables
|
@@ -122,7 +122,7 @@ def set_globals(thread_control_var, q_var, console_output_var, parent_frame_var,
|
|
122
122
|
def import_settings(settings_type='mask'):
|
123
123
|
from .gui_utils import convert_settings_dict_for_gui, hide_all_settings
|
124
124
|
global vars_dict, scrollable_frame, button_scrollable_frame
|
125
|
-
from .settings import generate_fields
|
125
|
+
from .settings import generate_fields, set_default_settings_preprocess_generate_masks, get_measure_crop_settings, set_default_train_test_model, set_default_generate_barecode_mapping, set_default_umap_image_settings
|
126
126
|
|
127
127
|
def read_settings_from_csv(csv_file_path):
|
128
128
|
settings = {}
|
@@ -158,7 +158,7 @@ def import_settings(settings_type='mask'):
|
|
158
158
|
elif settings_type == 'classify':
|
159
159
|
settings = set_default_train_test_model(settings={})
|
160
160
|
elif settings_type == 'sequencing':
|
161
|
-
settings =
|
161
|
+
settings = set_default_generate_barecode_mapping(settings={})
|
162
162
|
elif settings_type == 'umap':
|
163
163
|
settings = set_default_umap_image_settings(settings={})
|
164
164
|
else:
|
@@ -171,7 +171,7 @@ def import_settings(settings_type='mask'):
|
|
171
171
|
|
172
172
|
def setup_settings_panel(vertical_container, settings_type='mask'):
|
173
173
|
global vars_dict, scrollable_frame
|
174
|
-
from .settings import get_identify_masks_finetune_default_settings, set_default_analyze_screen, set_default_settings_preprocess_generate_masks, get_measure_crop_settings,
|
174
|
+
from .settings import get_identify_masks_finetune_default_settings, set_default_analyze_screen, set_default_settings_preprocess_generate_masks, get_measure_crop_settings, deep_spacr_defaults, set_default_generate_barecode_mapping, set_default_umap_image_settings, generate_fields, get_perform_regression_default_settings, get_train_cellpose_default_settings, get_map_barcodes_default_settings, get_analyze_recruitment_default_settings, get_check_cellpose_models_default_settings
|
175
175
|
from .gui_utils import convert_settings_dict_for_gui
|
176
176
|
from .gui_elements import set_element_size
|
177
177
|
|
@@ -197,9 +197,7 @@ def setup_settings_panel(vertical_container, settings_type='mask'):
|
|
197
197
|
elif settings_type == 'measure':
|
198
198
|
settings = get_measure_crop_settings(settings={})
|
199
199
|
elif settings_type == 'classify':
|
200
|
-
settings =
|
201
|
-
elif settings_type == 'sequencing':
|
202
|
-
settings = get_analyze_reads_default_settings(settings={})
|
200
|
+
settings = deep_spacr_defaults(settings={})
|
203
201
|
elif settings_type == 'umap':
|
204
202
|
settings = set_default_umap_image_settings(settings={})
|
205
203
|
elif settings_type == 'train_cellpose':
|
@@ -211,7 +209,7 @@ def setup_settings_panel(vertical_container, settings_type='mask'):
|
|
211
209
|
elif settings_type == 'cellpose_all':
|
212
210
|
settings = get_check_cellpose_models_default_settings(settings={})
|
213
211
|
elif settings_type == 'map_barcodes':
|
214
|
-
settings =
|
212
|
+
settings = set_default_generate_barecode_mapping(settings={})
|
215
213
|
elif settings_type == 'regression':
|
216
214
|
settings = get_perform_regression_default_settings(settings={})
|
217
215
|
elif settings_type == 'recruitment':
|
@@ -350,7 +348,7 @@ def setup_button_section(horizontal_container, settings_type='mask', run=True, a
|
|
350
348
|
widgets.append(run_button)
|
351
349
|
btn_col += 1
|
352
350
|
|
353
|
-
if abort and settings_type in ['mask', 'measure', 'classify', 'sequencing', 'umap']:
|
351
|
+
if abort and settings_type in ['mask', 'measure', 'classify', 'sequencing', 'umap', 'map_barcodes']:
|
354
352
|
abort_button = spacrButton(button_scrollable_frame.scrollable_frame, text="abort", command=lambda: initiate_abort(), show_text=False, size=size_dict['btn_size'], animation=False)
|
355
353
|
abort_button.grid(row=btn_row, column=btn_col, pady=5, padx=5, sticky='ew')
|
356
354
|
widgets.append(abort_button)
|
@@ -551,7 +549,7 @@ def start_process(q=None, fig_queue=None, settings_type='mask'):
|
|
551
549
|
|
552
550
|
process_args = (settings_type, settings, q, fig_queue, stop_requested)
|
553
551
|
if settings_type in [
|
554
|
-
'mask', 'measure', 'simulation', 'sequencing', 'classify', 'cellpose_dataset',
|
552
|
+
'mask', 'umap', 'measure', 'simulation', 'sequencing', 'classify', 'cellpose_dataset',
|
555
553
|
'train_cellpose', 'ml_analyze', 'cellpose_masks', 'cellpose_all', 'map_barcodes',
|
556
554
|
'regression', 'recruitment', 'plaques', 'cellpose_compare', 'vision_scores',
|
557
555
|
'vision_dataset'
|
spacr/gui_elements.py
CHANGED
@@ -603,6 +603,76 @@ class spacrCheckbutton(ttk.Checkbutton):
|
|
603
603
|
_ = set_dark_style(style, widgets=[self])
|
604
604
|
|
605
605
|
class spacrProgressBar(ttk.Progressbar):
|
606
|
+
def __init__(self, parent, label=True, *args, **kwargs):
|
607
|
+
super().__init__(parent, *args, **kwargs)
|
608
|
+
|
609
|
+
# Get the style colors
|
610
|
+
style_out = set_dark_style(ttk.Style())
|
611
|
+
|
612
|
+
self.fg_color = style_out['fg_color']
|
613
|
+
self.bg_color = style_out['bg_color']
|
614
|
+
self.active_color = style_out['active_color']
|
615
|
+
self.inactive_color = style_out['inactive_color']
|
616
|
+
|
617
|
+
# Configure the style for the progress bar
|
618
|
+
self.style = ttk.Style()
|
619
|
+
self.style.configure(
|
620
|
+
"spacr.Horizontal.TProgressbar",
|
621
|
+
troughcolor=self.bg_color,
|
622
|
+
background=self.active_color,
|
623
|
+
thickness=20,
|
624
|
+
troughrelief='flat',
|
625
|
+
borderwidth=0
|
626
|
+
)
|
627
|
+
self.configure(style="spacr.Horizontal.TProgressbar")
|
628
|
+
|
629
|
+
# Set initial value to 0
|
630
|
+
self['value'] = 0
|
631
|
+
|
632
|
+
# Track whether to show the progress label
|
633
|
+
self.label = label
|
634
|
+
|
635
|
+
# Create the progress label with text wrapping
|
636
|
+
if self.label:
|
637
|
+
self.progress_label = tk.Label(
|
638
|
+
parent,
|
639
|
+
text="Processing: 0/0",
|
640
|
+
anchor='w',
|
641
|
+
justify='left',
|
642
|
+
bg=self.inactive_color,
|
643
|
+
fg=self.fg_color,
|
644
|
+
wraplength=300 # Adjust the wraplength as needed
|
645
|
+
)
|
646
|
+
self.progress_label.grid_forget() # Temporarily hide it
|
647
|
+
|
648
|
+
# Initialize attributes for time and operation
|
649
|
+
self.operation_type = None
|
650
|
+
self.time_image = None
|
651
|
+
self.time_batch = None
|
652
|
+
self.time_left = None
|
653
|
+
|
654
|
+
def set_label_position(self):
|
655
|
+
if self.label and self.progress_label:
|
656
|
+
row_info = self.grid_info().get('row', 0)
|
657
|
+
col_info = self.grid_info().get('column', 0)
|
658
|
+
col_span = self.grid_info().get('columnspan', 1)
|
659
|
+
self.progress_label.grid(row=row_info + 1, column=col_info, columnspan=col_span, pady=5, padx=5, sticky='ew')
|
660
|
+
|
661
|
+
def update_label(self):
|
662
|
+
if self.label and self.progress_label:
|
663
|
+
# Update the progress label with current progress and additional info
|
664
|
+
label_text = f"Processing: {self['value']}/{self['maximum']}"
|
665
|
+
if self.operation_type:
|
666
|
+
label_text += f", {self.operation_type}"
|
667
|
+
if self.time_image:
|
668
|
+
label_text += f", Time/image: {self.time_image:.3f} sec"
|
669
|
+
if self.time_batch:
|
670
|
+
label_text += f", Time/batch: {self.time_batch:.3f} sec"
|
671
|
+
if self.time_left:
|
672
|
+
label_text += f", Time_left: {self.time_left:.3f} min"
|
673
|
+
self.progress_label.config(text=label_text)
|
674
|
+
|
675
|
+
class spacrProgressBar_v1(ttk.Progressbar):
|
606
676
|
def __init__(self, parent, label=True, *args, **kwargs):
|
607
677
|
super().__init__(parent, *args, **kwargs)
|
608
678
|
|
spacr/gui_utils.py
CHANGED
@@ -44,7 +44,7 @@ def load_app(root, app_name, app_func):
|
|
44
44
|
else:
|
45
45
|
proceed_with_app(root, app_name, app_func)
|
46
46
|
|
47
|
-
def
|
47
|
+
def parse_list_v1(value):
|
48
48
|
try:
|
49
49
|
parsed_value = ast.literal_eval(value)
|
50
50
|
if isinstance(parsed_value, list):
|
@@ -54,6 +54,22 @@ def parse_list(value):
|
|
54
54
|
except (ValueError, SyntaxError) as e:
|
55
55
|
raise ValueError(f"Invalid format for list: {value}. Error: {e}")
|
56
56
|
|
57
|
+
def parse_list(value):
|
58
|
+
try:
|
59
|
+
parsed_value = ast.literal_eval(value)
|
60
|
+
if isinstance(parsed_value, list):
|
61
|
+
# Check if the list elements are homogeneous (all int or all str)
|
62
|
+
if all(isinstance(item, int) for item in parsed_value):
|
63
|
+
return parsed_value
|
64
|
+
elif all(isinstance(item, str) for item in parsed_value):
|
65
|
+
return parsed_value
|
66
|
+
else:
|
67
|
+
raise ValueError("List contains mixed types or unsupported types")
|
68
|
+
else:
|
69
|
+
raise ValueError(f"Expected a list but got {type(parsed_value).__name__}")
|
70
|
+
except (ValueError, SyntaxError) as e:
|
71
|
+
raise ValueError(f"Invalid format for list: {value}. Error: {e}")
|
72
|
+
|
57
73
|
# Usage example in your create_input_field function
|
58
74
|
def create_input_field(frame, label_text, row, var_type='entry', options=None, default_value=None):
|
59
75
|
from .gui_elements import set_dark_style, set_element_size
|
@@ -323,7 +339,9 @@ def convert_settings_dict_for_gui(settings):
|
|
323
339
|
special_cases = {
|
324
340
|
'metadata_type': ('combo', ['cellvoyager', 'cq1', 'nikon', 'zeis', 'custom'], 'cellvoyager'),
|
325
341
|
'channels': ('combo', ['[0,1,2,3]', '[0,1,2]', '[0,1]', '[0]'], '[0,1,2,3]'),
|
342
|
+
'train_channels': ('combo', ["['r','g','b']", "['r','g']", "['r','b']", "['g','b']", "['r']", "['g']", "['b']"], "['r','g','b']"),
|
326
343
|
'channel_dims': ('combo', ['[0,1,2,3]', '[0,1,2]', '[0,1]', '[0]'], '[0,1,2,3]'),
|
344
|
+
'dataset_mode': ('combo', ['annotation', 'metadata', 'recruitment'], 'annotate'),
|
327
345
|
'cell_mask_dim': ('combo', chans, None),
|
328
346
|
'cell_chann_dim': ('combo', chans, None),
|
329
347
|
'nucleus_mask_dim': ('combo', chans, None),
|
@@ -369,6 +387,7 @@ def convert_settings_dict_for_gui(settings):
|
|
369
387
|
variables[key] = ('entry', None, str(value))
|
370
388
|
else:
|
371
389
|
variables[key] = ('entry', None, str(value))
|
390
|
+
|
372
391
|
return variables
|
373
392
|
|
374
393
|
|
@@ -413,13 +432,14 @@ def function_gui_wrapper(function=None, settings={}, q=None, fig_queue=None, imp
|
|
413
432
|
plt.show = original_show
|
414
433
|
|
415
434
|
def run_function_gui(settings_type, settings, q, fig_queue, stop_requested):
|
435
|
+
|
416
436
|
from .gui_utils import process_stdout_stderr
|
417
|
-
from .core import preprocess_generate_masks, generate_ml_scores, identify_masks_finetune, check_cellpose_models, analyze_recruitment, train_cellpose, compare_cellpose_masks, analyze_plaques, generate_dataset, apply_model_to_tar
|
437
|
+
from .core import generate_image_umap, preprocess_generate_masks, generate_ml_scores, identify_masks_finetune, check_cellpose_models, analyze_recruitment, train_cellpose, compare_cellpose_masks, analyze_plaques, generate_dataset, apply_model_to_tar
|
418
438
|
from .io import generate_cellpose_train_test
|
419
439
|
from .measure import measure_crop
|
420
440
|
from .sim import run_multiple_simulations
|
421
|
-
from .deep_spacr import
|
422
|
-
from .sequencing import
|
441
|
+
from .deep_spacr import deep_spacr
|
442
|
+
from .sequencing import generate_barecode_mapping, perform_regression
|
423
443
|
process_stdout_stderr(q)
|
424
444
|
|
425
445
|
print(f'run_function_gui settings_type: {settings_type}')
|
@@ -433,12 +453,9 @@ def run_function_gui(settings_type, settings, q, fig_queue, stop_requested):
|
|
433
453
|
elif settings_type == 'simulation':
|
434
454
|
function = run_multiple_simulations
|
435
455
|
imports = 1
|
436
|
-
elif settings_type == 'sequencing':
|
437
|
-
function = analyze_reads
|
438
|
-
imports = 1
|
439
456
|
elif settings_type == 'classify':
|
440
|
-
function =
|
441
|
-
imports =
|
457
|
+
function = deep_spacr
|
458
|
+
imports = 1
|
442
459
|
elif settings_type == 'train_cellpose':
|
443
460
|
function = train_cellpose
|
444
461
|
imports = 1
|
@@ -452,7 +469,7 @@ def run_function_gui(settings_type, settings, q, fig_queue, stop_requested):
|
|
452
469
|
function = check_cellpose_models
|
453
470
|
imports = 1
|
454
471
|
elif settings_type == 'map_barcodes':
|
455
|
-
function =
|
472
|
+
function = generate_barecode_mapping
|
456
473
|
imports = 1
|
457
474
|
elif settings_type == 'regression':
|
458
475
|
function = perform_regression
|
@@ -460,6 +477,9 @@ def run_function_gui(settings_type, settings, q, fig_queue, stop_requested):
|
|
460
477
|
elif settings_type == 'recruitment':
|
461
478
|
function = analyze_recruitment
|
462
479
|
imports = 2
|
480
|
+
elif settings_type == 'umap':
|
481
|
+
function = generate_image_umap
|
482
|
+
imports = 1
|
463
483
|
else:
|
464
484
|
raise ValueError(f"Invalid settings type: {settings_type}")
|
465
485
|
try:
|
spacr/io.py
CHANGED
@@ -2293,15 +2293,23 @@ def _save_model(model, model_type, results_df, dst, epoch, epochs, intermedeate_
|
|
2293
2293
|
def save_model_at_threshold(threshold, epoch, suffix=""):
|
2294
2294
|
percentile = str(threshold * 100)
|
2295
2295
|
print(f'\rfound: {percentile}% accurate model')#, end='\r', flush=True)
|
2296
|
-
|
2296
|
+
model_path = f'{dst}/{model_type}_epoch_{str(epoch)}{suffix}_acc_{percentile}_channels_{channels_str}.pth'
|
2297
|
+
torch.save(model, model_path)
|
2298
|
+
return model_path
|
2297
2299
|
|
2298
2300
|
if epoch % 100 == 0 or epoch == epochs:
|
2299
|
-
|
2301
|
+
model_path = f'{dst}/{model_type}_epoch_{str(epoch)}_channels_{channels_str}.pth'
|
2302
|
+
torch.save(model, model_path)
|
2303
|
+
return model_path
|
2300
2304
|
|
2301
2305
|
for threshold in intermedeate_save:
|
2302
2306
|
if results_df['neg_accuracy'].dropna().mean() >= threshold and results_df['pos_accuracy'].dropna().mean() >= threshold:
|
2303
|
-
save_model_at_threshold(threshold, epoch)
|
2304
|
-
break
|
2307
|
+
model_path = save_model_at_threshold(threshold, epoch)
|
2308
|
+
break
|
2309
|
+
else:
|
2310
|
+
model_path = None
|
2311
|
+
|
2312
|
+
return model_path
|
2305
2313
|
|
2306
2314
|
def _save_progress(dst, results_df, train_metrics_df, epoch, epochs):
|
2307
2315
|
"""
|