spacr 0.1.7__py3-none-any.whl → 0.1.8__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/gui_core.py CHANGED
@@ -1,29 +1,24 @@
1
- import os, traceback, ctypes, matplotlib, requests, csv, re
1
+ import os, traceback, ctypes, matplotlib, requests, csv, matplotlib, time, requests
2
+ import matplotlib.pyplot as plt
2
3
  matplotlib.use('Agg')
3
4
  import tkinter as tk
4
5
  from tkinter import ttk
5
- import tkinter.font as tkFont
6
6
  from tkinter import filedialog
7
- from tkinter import font as tkFont
8
- from multiprocessing import Process, Value, Queue
7
+ from multiprocessing import Process, Value, Queue, set_start_method
9
8
  from multiprocessing.sharedctypes import Synchronized
10
- from multiprocessing import set_start_method
11
9
  from tkinter import ttk, scrolledtext
12
10
  from matplotlib.figure import Figure
13
11
  from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
14
- import time
15
- import requests
16
12
  from huggingface_hub import list_repo_files
17
13
 
18
- from .settings import set_default_train_test_model, get_measure_crop_settings, set_default_settings_preprocess_generate_masks, get_analyze_reads_default_settings, set_default_umap_image_settings
19
- from .gui_elements import create_menu_bar, spacrButton, spacrLabel, spacrFrame, spacrCheckbutton, spacrDropdownMenu ,set_dark_style, set_default_font
20
- from . gui_run import run_mask_gui, run_measure_gui, run_classify_gui, run_sequencing_gui, run_umap_gui
21
-
22
14
  try:
23
15
  ctypes.windll.shcore.SetProcessDpiAwareness(True)
24
16
  except AttributeError:
25
17
  pass
26
18
 
19
+ from .settings import set_default_train_test_model, get_measure_crop_settings, set_default_settings_preprocess_generate_masks, get_analyze_reads_default_settings, set_default_umap_image_settings
20
+ from .gui_elements import create_menu_bar, spacrButton, spacrLabel, spacrFrame, spacrDropdownMenu ,set_dark_style, set_default_font
21
+
27
22
  # Define global variables
28
23
  q = None
29
24
  console_output = None
@@ -46,26 +41,116 @@ def initiate_abort():
46
41
  thread_control["run_thread"].join()
47
42
  thread_control["run_thread"] = None
48
43
 
49
- def start_process_v1(q, fig_queue, settings_type='mask'):
50
- global thread_control, vars_dict
51
- from .settings import check_settings, expected_types
44
+ def spacrFigShow(fig_queue=None):
45
+ """
46
+ Replacement for plt.show() that queues figures instead of displaying them.
47
+ """
48
+ fig = plt.gcf()
49
+ if fig_queue:
50
+ fig_queue.put(fig)
51
+ else:
52
+ fig.show()
53
+ plt.close(fig)
52
54
 
53
- settings = check_settings(vars_dict, expected_types, q)
54
- if thread_control.get("run_thread") is not None:
55
- initiate_abort()
56
- stop_requested = Value('i', 0) # multiprocessing shared value for inter-process communication
57
- thread_control["stop_requested"] = stop_requested
55
+ def function_gui_wrapper(function=None, settings={}, q=None, fig_queue=None, imports=1):
56
+
57
+ """
58
+ Wraps the run_multiple_simulations function to integrate with GUI processes.
59
+
60
+ Parameters:
61
+ - settings: dict, The settings for the run_multiple_simulations function.
62
+ - q: multiprocessing.Queue, Queue for logging messages to the GUI.
63
+ - fig_queue: multiprocessing.Queue, Queue for sending figures to the GUI.
64
+ """
65
+
66
+ # Temporarily override plt.show
67
+ original_show = plt.show
68
+ plt.show = lambda: spacrFigShow(fig_queue)
69
+
70
+ try:
71
+ if imports == 1:
72
+ function(settings=settings)
73
+ elif imports == 2:
74
+ function(src=settings['src'], settings=settings)
75
+ except Exception as e:
76
+ # Send the error message to the GUI via the queue
77
+ errorMessage = f"Error during processing: {e}"
78
+ q.put(errorMessage)
79
+ traceback.print_exc()
80
+ finally:
81
+ # Restore the original plt.show function
82
+ plt.show = original_show
83
+
84
+ def run_function_gui(settings_type, settings, q, fig_queue, stop_requested):
85
+ from .gui_utils import process_stdout_stderr
86
+ 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
87
+ from .io import generate_cellpose_train_test
88
+ from .measure import measure_crop
89
+ from .sim import run_multiple_simulations
90
+ from .deep_spacr import train_test_model
91
+ from .sequencing import analyze_reads, map_barcodes_folder, perform_regression
92
+ process_stdout_stderr(q)
93
+
58
94
  if settings_type == 'mask':
59
- thread_control["run_thread"] = Process(target=run_mask_gui, args=(settings, q, fig_queue, stop_requested))
95
+ function = preprocess_generate_masks
96
+ imports = 2
60
97
  elif settings_type == 'measure':
61
- thread_control["run_thread"] = Process(target=run_measure_gui, args=(settings, q, fig_queue, stop_requested))
62
- elif settings_type == 'classify':
63
- thread_control["run_thread"] = Process(target=run_classify_gui, args=(settings, q, fig_queue, stop_requested))
98
+ function = measure_crop
99
+ imports = 1
100
+ elif settings_type == 'simulation':
101
+ function = run_multiple_simulations
102
+ imports = 1
64
103
  elif settings_type == 'sequencing':
65
- thread_control["run_thread"] = Process(target=run_sequencing_gui, args=(settings, q, fig_queue, stop_requested))
66
- elif settings_type == 'umap':
67
- thread_control["run_thread"] = Process(target=run_umap_gui, args=(settings, q, fig_queue, stop_requested))
68
- thread_control["run_thread"].start()
104
+ function = analyze_reads
105
+ imports = 1
106
+ elif settings_type == 'classify':
107
+ function = train_test_model
108
+ imports = 2
109
+ elif settings_type == 'train_cellpose':
110
+ function = train_cellpose
111
+ imports = 1
112
+ elif settings_type == 'ml_analyze':
113
+ function = generate_ml_scores
114
+ imports = 2
115
+ elif settings_type == 'cellpose_masks':
116
+ function = identify_masks_finetune
117
+ imports = 1
118
+ elif settings_type == 'cellpose_all':
119
+ function = check_cellpose_models
120
+ imports = 1
121
+ elif settings_type == 'map_barcodes':
122
+ function = map_barcodes_folder
123
+ imports = 2
124
+ elif settings_type == 'regression':
125
+ function = perform_regression
126
+ imports = 2
127
+ elif settings_type == 'recruitment':
128
+ function = analyze_recruitment
129
+ imports = 2
130
+ #elif settings_type == 'cellpose_dataset':
131
+ # function = generate_cellpose_train_test
132
+ # imports = 1
133
+ #elif settings_type == 'plaques':
134
+ # function = analyze_plaques
135
+ # imports = 1
136
+ #elif settings_type == 'cellpose_compare':
137
+ # function = compare_cellpose_masks
138
+ # imports = 1
139
+ #elif settings_type == 'vision_scores':
140
+ # function = apply_model_to_tar
141
+ # imports = 1
142
+ #elif settings_type == 'vision_dataset':
143
+ # function = generate_dataset
144
+ # imports = 1
145
+ else:
146
+ raise ValueError(f"Invalid settings type: {settings_type}")
147
+ try:
148
+ function_gui_wrapper(function, settings, q, fig_queue, imports)
149
+ except Exception as e:
150
+ q.put(f"Error during processing: {e}")
151
+ traceback.print_exc()
152
+ finally:
153
+ stop_requested.value = 1
69
154
 
70
155
  def start_process(q=None, fig_queue=None, settings_type='mask'):
71
156
  global thread_control, vars_dict
@@ -85,25 +170,15 @@ def start_process(q=None, fig_queue=None, settings_type='mask'):
85
170
  if thread_control.get("run_thread") is not None:
86
171
  initiate_abort()
87
172
 
88
- stop_requested = Value('i', 0) # multiprocessing shared value for inter-process communication
173
+ stop_requested = Value('i', 0)
89
174
  thread_control["stop_requested"] = stop_requested
90
175
 
91
- process_args = (settings, q, fig_queue, stop_requested)
92
-
93
- if settings_type == 'mask':
94
- thread_control["run_thread"] = Process(target=run_mask_gui, args=process_args)
95
- elif settings_type == 'measure':
96
- thread_control["run_thread"] = Process(target=run_measure_gui, args=process_args)
97
- elif settings_type == 'classify':
98
- thread_control["run_thread"] = Process(target=run_classify_gui, args=process_args)
99
- elif settings_type == 'sequencing':
100
- thread_control["run_thread"] = Process(target=run_sequencing_gui, args=process_args)
101
- elif settings_type == 'umap':
102
- thread_control["run_thread"] = Process(target=run_umap_gui, args=process_args)
176
+ process_args = (settings_type, settings, q, fig_queue, stop_requested)
177
+ if settings_type in ['mask','measure','simulation','sequencing','classify','cellpose_dataset','train_cellpose','ml_analyze','cellpose_masks','cellpose_all','map_barcodes','regression','recruitment','plaques','cellpose_compare','vision_scores','vision_dataset']:
178
+ thread_control["run_thread"] = Process(target=run_function_gui, args=process_args)
103
179
  else:
104
180
  q.put(f"Error: Unknown settings type '{settings_type}'")
105
181
  return
106
-
107
182
  thread_control["run_thread"].start()
108
183
 
109
184
  def import_settings(settings_type='mask'):
@@ -194,15 +269,19 @@ def convert_settings_dict_for_gui(settings):
194
269
  variables[key] = ('entry', None, str(value))
195
270
  return variables
196
271
 
197
- def setup_settings_panel(vertical_container, settings_type='mask', frame_height=500, frame_width=1000):
272
+ def setup_settings_panel(vertical_container, settings_type='mask', window_dimensions=[500, 1000]):
198
273
  global vars_dict, scrollable_frame
199
- from .settings import set_default_settings_preprocess_generate_masks, get_measure_crop_settings, set_default_train_test_model, get_analyze_reads_default_settings, set_default_umap_image_settings, generate_fields
274
+ from .settings import descriptions, get_identify_masks_finetune_default_settings, set_default_analyze_screen, set_default_settings_preprocess_generate_masks, get_measure_crop_settings, set_default_train_test_model, get_analyze_reads_default_settings, 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
275
+
276
+ width = (window_dimensions[0])//6
277
+ height = window_dimensions[1]
200
278
 
201
- settings_frame = tk.Frame(vertical_container, bg='black', height=frame_height, width=frame_width)
279
+ # Settings Frame
280
+ settings_frame = tk.Frame(vertical_container, bg='black', height=height, width=width)
202
281
  vertical_container.add(settings_frame, stretch="always")
203
282
  settings_label = spacrLabel(settings_frame, text="Settings", background="black", foreground="white", anchor='center', justify='center', align="center")
204
283
  settings_label.grid(row=0, column=0, pady=10, padx=10)
205
- scrollable_frame = spacrFrame(settings_frame, bg='black', width=frame_width)
284
+ scrollable_frame = spacrFrame(settings_frame, bg='black', width=width)
206
285
  scrollable_frame.grid(row=1, column=0, sticky="nsew")
207
286
  settings_frame.grid_rowconfigure(1, weight=1)
208
287
  settings_frame.grid_columnconfigure(0, weight=1)
@@ -217,9 +296,36 @@ def setup_settings_panel(vertical_container, settings_type='mask', frame_height=
217
296
  settings = get_analyze_reads_default_settings(settings={})
218
297
  elif settings_type == 'umap':
219
298
  settings = set_default_umap_image_settings(settings={})
299
+ elif settings_type == 'train_cellpose':
300
+ settings = get_train_cellpose_default_settings(settings={})
301
+ elif settings_type == 'ml_analyze':
302
+ settings = set_default_analyze_screen(settings={})
303
+ elif settings_type == 'cellpose_masks':
304
+ settings = get_identify_masks_finetune_default_settings(settings={})
305
+ elif settings_type == 'cellpose_all':
306
+ settings = get_check_cellpose_models_default_settings(settings={})
307
+ elif settings_type == 'map_barcodes':
308
+ settings = get_map_barcodes_default_settings(settings={})
309
+ elif settings_type == 'regression':
310
+ settings = get_perform_regression_default_settings(settings={})
311
+ elif settings_type == 'recruitment':
312
+ settings = get_analyze_recruitment_default_settings(settings={})
313
+ #elif settings_type == 'simulation':
314
+ # settings = set_default_
315
+ #elif settings_type == 'cellpose_dataset':
316
+ # settings = set_default_
317
+ #elif settings_type == 'plaques':
318
+ # settings = set_default_
319
+ #elif settings_type == 'cellpose_compare':
320
+ # settings = set_default_
321
+ #elif settings_type == 'vision_scores':
322
+ # settings = set_default_
323
+ #elif settings_type == 'vision_dataset':
324
+ # settings = set_default_
220
325
  else:
221
326
  raise ValueError(f"Invalid settings type: {settings_type}")
222
327
 
328
+
223
329
  variables = convert_settings_dict_for_gui(settings)
224
330
  vars_dict = generate_fields(variables, scrollable_frame)
225
331
  print("Settings panel setup complete")
@@ -353,18 +459,21 @@ def download_dataset(repo_id, subfolder, local_dir=None, retries=5, delay=5):
353
459
 
354
460
  raise Exception("Failed to download files after multiple attempts.")
355
461
 
356
- def setup_button_section(horizontal_container, settings_type='mask', settings_row=5, run=True, abort=True, download=True, import_btn=True):
462
+ def setup_button_section(horizontal_container, settings_type='mask', window_dimensions=[500, 1000], run=True, abort=True, download=True, import_btn=True):
357
463
  global button_frame, button_scrollable_frame, run_button, abort_button, download_dataset_button, import_button, q, fig_queue, vars_dict
464
+ from .settings import descriptions
465
+
466
+ width = (window_dimensions[0])//8
467
+ height = window_dimensions[1]
358
468
 
359
- button_frame = tk.Frame(horizontal_container, bg='black')
469
+ button_frame = tk.Frame(horizontal_container, bg='black', height=height, width=width)
360
470
  horizontal_container.add(button_frame, stretch="always", sticky="nsew")
361
471
  button_frame.grid_rowconfigure(0, weight=0)
362
472
  button_frame.grid_rowconfigure(1, weight=1)
363
473
  button_frame.grid_columnconfigure(0, weight=1)
364
474
 
365
- categories_label = spacrLabel(button_frame, text="Categories", background="black", foreground="white", font=('Helvetica', 12), anchor='center', justify='center', align="center") # Increase font size
475
+ categories_label = spacrLabel(button_frame, text="Categories", background="black", foreground="white", font=('Helvetica', 12), anchor='center', justify='center', align="center")
366
476
  categories_label.grid(row=0, column=0, pady=10, padx=10)
367
-
368
477
  button_scrollable_frame = spacrFrame(button_frame, bg='black')
369
478
  button_scrollable_frame.grid(row=1, column=0, sticky="nsew")
370
479
 
@@ -393,6 +502,16 @@ def setup_button_section(horizontal_container, settings_type='mask', settings_ro
393
502
  # Call toggle_settings after vars_dict is initialized
394
503
  if vars_dict is not None:
395
504
  toggle_settings(button_scrollable_frame)
505
+
506
+ # Description frame
507
+ description_frame = tk.Frame(horizontal_container, bg='black', height=height, width=width)
508
+ horizontal_container.add(description_frame, stretch="always", sticky="nsew")
509
+ description_frame.grid_columnconfigure(0, weight=1) # Make the column stretch
510
+ description_label = tk.Label(description_frame, text="Module Description", bg='black', fg='white', anchor='nw', justify='left', wraplength=width-50)
511
+ description_label.grid(row=0, column=0, pady=50, padx=20, sticky='nsew') # Use sticky='nsew' to stretch the label
512
+ description_text = descriptions.get(settings_type, "No description available for this module.")
513
+ description_label.config(text=description_text)
514
+
396
515
  return button_scrollable_frame
397
516
 
398
517
  def hide_all_settings(vars_dict, categories):
@@ -529,80 +648,55 @@ def setup_frame(parent_frame):
529
648
  return parent_frame, vertical_container, horizontal_container
530
649
 
531
650
  def initiate_root(parent, settings_type='mask'):
532
-
651
+ global q, fig_queue, parent_frame, scrollable_frame, button_frame, vars_dict, canvas, canvas_widget, progress_label, progress_output, button_scrollable_frame
652
+ from .gui_utils import main_thread_update_function
653
+ from .gui import gui_app
533
654
  set_start_method('spawn', force=True)
534
-
535
- def main_thread_update_function(root, q, fig_queue, canvas_widget, progress_label):
536
- try:
537
- ansi_escape_pattern = re.compile(r'\x1B\[[0-?]*[ -/]*[@-~]')
538
- while not q.empty():
539
- message = q.get_nowait()
540
- clean_message = ansi_escape_pattern.sub('', message)
541
- if clean_message.startswith("Progress"):
542
- progress_label.config(text=clean_message)
543
- if clean_message.startswith("\rProgress"):
544
- progress_label.config(text=clean_message)
545
- elif clean_message.startswith("Successfully"):
546
- progress_label.config(text=clean_message)
547
- elif clean_message.startswith("Processing"):
548
- progress_label.config(text=clean_message)
549
- elif clean_message.startswith("scale"):
550
- pass
551
- elif clean_message.startswith("plot_cropped_arrays"):
552
- pass
553
- elif clean_message == "" or clean_message == "\r" or clean_message.strip() == "":
554
- pass
555
- else:
556
- print(clean_message)
557
- except Exception as e:
558
- print(f"Error updating GUI canvas: {e}")
559
- finally:
560
- root.after(100, lambda: main_thread_update_function(root, q, fig_queue, canvas_widget, progress_label))
561
-
562
- global q, fig_queue, parent_frame, scrollable_frame, button_frame, vars_dict, canvas, canvas_widget, progress_label, button_scrollable_frame
563
655
  print("Initializing root with settings_type:", settings_type)
656
+
564
657
  parent_frame = parent
658
+ parent_frame.update_idletasks()
659
+ frame_width = int(parent_frame.winfo_width())
660
+ frame_height = int(parent_frame.winfo_height())
661
+ print(frame_width, frame_height)
662
+ dims = [frame_width, frame_height]
565
663
 
566
664
  if not hasattr(parent_frame, 'after_tasks'):
567
665
  parent_frame.after_tasks = []
568
666
 
667
+ # Clear previous content instead of destroying the root
569
668
  for widget in parent_frame.winfo_children():
570
- if widget.winfo_exists():
571
- try:
572
- widget.destroy()
573
- except tk.TclError as e:
574
- print(f"Error destroying widget: {e}")
669
+ try:
670
+ widget.destroy()
671
+ except tk.TclError as e:
672
+ print(f"Error destroying widget: {e}")
575
673
 
576
674
  q = Queue()
577
675
  fig_queue = Queue()
578
676
  parent_frame, vertical_container, horizontal_container = setup_frame(parent_frame)
579
- scrollable_frame, vars_dict = setup_settings_panel(horizontal_container, settings_type) # Adjust height and width as needed
580
- button_scrollable_frame = setup_button_section(horizontal_container, settings_type)
581
- canvas, canvas_widget = setup_plot_section(vertical_container)
582
- console_output = setup_console(vertical_container)
583
677
 
584
- if settings_type in ['mask', 'measure', 'classify', 'sequencing']:
585
- progress_output = setup_progress_frame(vertical_container)
678
+ if settings_type == 'annotate':
679
+ from .app_annotate import initiate_annotation_app
680
+ initiate_annotation_app(horizontal_container)
681
+ elif settings_type == 'make_masks':
682
+ from .app_make_masks import initiate_make_mask_app
683
+ initiate_make_mask_app(horizontal_container)
586
684
  else:
587
- progress_output = None
685
+ scrollable_frame, vars_dict = setup_settings_panel(horizontal_container, settings_type, window_dimensions=dims)
686
+ button_scrollable_frame = setup_button_section(horizontal_container, settings_type, window_dimensions=dims)
687
+ canvas, canvas_widget = setup_plot_section(vertical_container)
688
+ console_output = setup_console(vertical_container)
689
+
690
+ if settings_type in ['mask', 'measure', 'classify', 'sequencing']:
691
+ progress_output = setup_progress_frame(vertical_container)
692
+ else:
693
+ progress_output = None
694
+
695
+ set_globals(q, console_output, parent_frame, vars_dict, canvas, canvas_widget, scrollable_frame, progress_label, fig_queue)
696
+ process_console_queue()
697
+ process_fig_queue()
698
+ after_id = parent_frame.after(100, lambda: main_thread_update_function(parent_frame, q, fig_queue, canvas_widget, progress_label))
699
+ parent_frame.after_tasks.append(after_id)
588
700
 
589
- set_globals(q, console_output, parent_frame, vars_dict, canvas, canvas_widget, scrollable_frame, progress_label, fig_queue)
590
- process_console_queue()
591
- process_fig_queue()
592
- after_id = parent_frame.after(100, lambda: main_thread_update_function(parent_frame, q, fig_queue, canvas_widget, progress_label))
593
- parent_frame.after_tasks.append(after_id)
594
701
  print("Root initialization complete")
595
702
  return parent_frame, vars_dict
596
-
597
- def start_gui_app(settings_type='mask'):
598
- global q, fig_queue, parent_frame, scrollable_frame, vars_dict, canvas, canvas_widget, progress_label
599
- root = tk.Tk()
600
- width = root.winfo_screenwidth()
601
- height = root.winfo_screenheight()
602
- root.geometry(f"{width}x{height}")
603
- root.title(f"SpaCr: {settings_type.capitalize()}")
604
- root.content_frame = tk.Frame(root)
605
- print("Starting GUI app with settings_type:", settings_type)
606
- initiate_root(root.content_frame, settings_type)
607
- create_menu_bar(root)
608
- root.mainloop()