spacr 0.1.77__py3-none-any.whl → 0.1.85__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.py CHANGED
@@ -11,72 +11,112 @@ class MainApp(tk.Tk):
11
11
  super().__init__()
12
12
  width = self.winfo_screenwidth()
13
13
  height = self.winfo_screenheight()
14
- self.geometry(f"{width}x{height}")
14
+ self.geometry(f"{width}x{height}")
15
15
  self.title("SpaCr GUI Collection")
16
- self.configure(bg="black")
16
+
17
+ # Initialize style and apply dark style to the main window
17
18
  style = ttk.Style()
18
- set_dark_style(style)
19
+ self.color_settings = set_dark_style(style, parent_frame=self)
19
20
 
20
- self.gui_apps = {
21
+ self.main_gui_apps = {
21
22
  "Mask": (lambda frame: initiate_root(frame, 'mask'), "Generate cellpose masks for cells, nuclei and pathogen images."),
22
23
  "Measure": (lambda frame: initiate_root(frame, 'measure'), "Measure single object intensity and morphological feature. Crop and save single object image"),
23
24
  "Annotate": (lambda frame: initiate_root(frame, 'annotate'), "Annotation single object images on a grid. Annotations are saved to database."),
24
- "Make Masks": (lambda frame: initiate_root(frame, 'make_masks'),"Adjust pre-existing Cellpose models to your specific dataset for improved performance"),
25
+ "Make Masks": (lambda frame: initiate_root(frame, 'make_masks'), "Adjust pre-existing Cellpose models to your specific dataset for improved performance"),
25
26
  "Classify": (lambda frame: initiate_root(frame, 'classify'), "Train Torch Convolutional Neural Networks (CNNs) or Transformers to classify single object images."),
26
- "Sequencing": (lambda frame: initiate_root(frame, 'sequencing'), "Analyze sequensing data."),
27
- "Umap": (lambda frame: initiate_root(frame, 'umap'), "Generate UMAP embedings with datapoints represented as images.")
27
+ }
28
+
29
+ self.additional_gui_apps = {
30
+ "Sequencing": (lambda frame: initiate_root(frame, 'sequencing'), "Analyze sequencing data."),
31
+ "Umap": (lambda frame: initiate_root(frame, 'umap'), "Generate UMAP embeddings with datapoints represented as images."),
32
+ "Train Cellpose": (lambda frame: initiate_root(frame, 'train_cellpose'), "Train custom Cellpose models."),
33
+ "ML Analyze": (lambda frame: initiate_root(frame, 'ml_analyze'), "Machine learning analysis of data."),
34
+ "Cellpose Masks": (lambda frame: initiate_root(frame, 'cellpose_masks'), "Generate Cellpose masks."),
35
+ "Cellpose All": (lambda frame: initiate_root(frame, 'cellpose_all'), "Run Cellpose on all images."),
36
+ "Map Barcodes": (lambda frame: initiate_root(frame, 'map_barcodes'), "Map barcodes to data."),
37
+ "Regression": (lambda frame: initiate_root(frame, 'regression'), "Perform regression analysis."),
38
+ "Recruitment": (lambda frame: initiate_root(frame, 'recruitment'), "Analyze recruitment data.")
28
39
  }
29
40
 
30
41
  self.selected_app = tk.StringVar()
31
42
  self.create_widgets()
32
43
 
33
- if default_app in self.gui_apps:
34
- self.load_app(default_app, self.gui_apps[default_app][0])
44
+ if default_app in self.main_gui_apps:
45
+ self.load_app(default_app, self.main_gui_apps[default_app][0])
46
+ elif default_app in self.additional_gui_apps:
47
+ self.load_app(default_app, self.additional_gui_apps[default_app][0])
35
48
 
36
49
  def create_widgets(self):
37
50
  # Create the menu bar
38
51
  create_menu_bar(self)
39
52
 
40
53
  # Create a canvas to hold the selected app and other elements
41
- self.canvas = tk.Canvas(self, bg="black", highlightthickness=0)
54
+ self.canvas = tk.Canvas(self, highlightthickness=0)
42
55
  self.canvas.grid(row=0, column=0, sticky="nsew")
43
56
  self.grid_rowconfigure(0, weight=1)
44
57
  self.grid_columnconfigure(0, weight=1)
45
58
 
46
59
  # Create a frame inside the canvas to hold the main content
47
- self.content_frame = tk.Frame(self.canvas, bg="black")
60
+ self.content_frame = tk.Frame(self.canvas)
48
61
  self.content_frame.pack(fill=tk.BOTH, expand=True)
49
62
 
50
- # Create startup screen with buttons for each GUI app
63
+ # Apply dark style to canvas and content_frame
64
+ set_dark_style(ttk.Style(), containers=[self.canvas, self.content_frame])
65
+
66
+ # Create startup screen with buttons for each main GUI app and drop-down for additional apps
51
67
  self.create_startup_screen()
52
68
 
53
69
  def create_startup_screen(self):
54
70
  self.clear_frame(self.content_frame)
55
71
 
56
72
  # Create a frame for the logo and description
57
- logo_frame = tk.Frame(self.content_frame, bg="black")
73
+ logo_frame = tk.Frame(self.content_frame)
58
74
  logo_frame.pack(pady=20, expand=True)
75
+ set_dark_style(ttk.Style(), containers=[logo_frame])
59
76
 
60
77
  # Load the logo image
61
78
  if not self.load_logo(logo_frame):
62
- tk.Label(logo_frame, text="Logo not found", bg="black", fg="white", font=('Helvetica', 24)).pack(padx=10, pady=10)
79
+ logo_not_found = tk.Label(logo_frame, text="Logo not found", font=('Helvetica', 24))
80
+ logo_not_found.pack(padx=10, pady=10)
81
+ set_dark_style(ttk.Style(), widgets=[logo_not_found])
63
82
 
64
83
  # Add SpaCr text below the logo with padding for sharper text
65
- tk.Label(logo_frame, text="SpaCr", bg="black", fg="#008080", font=('Helvetica', 24)).pack(padx=10, pady=10)
84
+ spacr_label = tk.Label(logo_frame, text="SpaCr", fg=self.color_settings['active_color'], font=('Helvetica', 24))
85
+ spacr_label.pack(padx=10, pady=10)
86
+ set_dark_style(ttk.Style(), widgets=[spacr_label])
66
87
 
67
88
  # Create a frame for the buttons and descriptions
68
- buttons_frame = tk.Frame(self.content_frame, bg="black")
89
+ buttons_frame = tk.Frame(self.content_frame)
69
90
  buttons_frame.pack(pady=10, expand=True, padx=10)
91
+ set_dark_style(ttk.Style(), containers=[buttons_frame])
70
92
 
71
- for i, (app_name, app_data) in enumerate(self.gui_apps.items()):
93
+ for i, (app_name, app_data) in enumerate(self.main_gui_apps.items()):
72
94
  app_func, app_desc = app_data
73
95
 
74
96
  # Create custom button with text
75
97
  button = spacrButton(buttons_frame, text=app_name, command=lambda app_name=app_name, app_func=app_func: self.load_app(app_name, app_func), font=('Helvetica', 12))
76
98
  button.grid(row=i, column=0, pady=10, padx=10, sticky="w")
77
99
 
78
- description_label = tk.Label(buttons_frame, text=app_desc, bg="black", fg="white", wraplength=800, justify="left", font=('Helvetica', 12))
100
+ description_label = tk.Label(buttons_frame, text=app_desc, wraplength=800, justify="left", font=('Helvetica', 12))
79
101
  description_label.grid(row=i, column=1, pady=10, padx=10, sticky="w")
102
+ set_dark_style(ttk.Style(), widgets=[description_label])
103
+
104
+ # Add drop-down menu for additional apps
105
+ dropdown_frame = tk.Frame(buttons_frame)
106
+ dropdown_frame.grid(row=len(self.main_gui_apps), column=0, columnspan=2, pady=20)
107
+ set_dark_style(ttk.Style(), containers=[dropdown_frame])
108
+
109
+ additional_apps_label = tk.Label(dropdown_frame, text="Additional Apps", font=('Helvetica', 12))
110
+ additional_apps_label.pack(side=tk.LEFT, padx=5)
111
+ set_dark_style(ttk.Style(), widgets=[additional_apps_label])
112
+
113
+ self.additional_apps_var = tk.StringVar(value="Select an app")
114
+ dropdown = ttk.Combobox(dropdown_frame, textvariable=self.additional_apps_var, values=list(self.additional_gui_apps.keys()))
115
+ dropdown.pack(side=tk.LEFT, padx=5)
116
+ set_dark_style(ttk.Style(), widgets=[dropdown])
117
+
118
+ load_button = spacrButton(dropdown_frame, text="Load", command=self.load_additional_app, font=('Helvetica', 12))
119
+ load_button.pack(side=tk.LEFT, padx=5)
80
120
 
81
121
  # Ensure buttons have a fixed width
82
122
  buttons_frame.grid_columnconfigure(0, minsize=150)
@@ -118,9 +158,10 @@ class MainApp(tk.Tk):
118
158
  new_height = int(screen_height // 4)
119
159
  logo_image = logo_image.resize((new_height, new_height), Image.Resampling.LANCZOS)
120
160
  logo_photo = ImageTk.PhotoImage(logo_image)
121
- logo_label = tk.Label(frame, image=logo_photo, bg="black")
161
+ logo_label = tk.Label(frame, image=logo_photo)
122
162
  logo_label.image = logo_photo # Keep a reference to avoid garbage collection
123
163
  logo_label.pack()
164
+ set_dark_style(ttk.Style(), widgets=[logo_label])
124
165
  return True
125
166
  except Exception as e:
126
167
  print(f"An error occurred while processing the logo image: {e}")
@@ -131,10 +172,16 @@ class MainApp(tk.Tk):
131
172
  self.clear_frame(self.content_frame)
132
173
 
133
174
  # Initialize the selected app
134
- app_frame = tk.Frame(self.content_frame, bg="black")
175
+ app_frame = tk.Frame(self.content_frame)
135
176
  app_frame.pack(fill=tk.BOTH, expand=True)
177
+ set_dark_style(ttk.Style(), containers=[app_frame])
136
178
  app_func(app_frame)
137
179
 
180
+ def load_additional_app(self):
181
+ selected_app = self.additional_apps_var.get()
182
+ if selected_app in self.additional_gui_apps:
183
+ self.load_app(selected_app, self.additional_gui_apps[selected_app][0])
184
+
138
185
  def clear_frame(self, frame):
139
186
  for widget in frame.winfo_children():
140
187
  widget.destroy()
spacr/gui_core.py CHANGED
@@ -1,27 +1,24 @@
1
- import os, traceback, ctypes, matplotlib, requests, csv
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
6
  from tkinter import filedialog
6
- from multiprocessing import Process, Value, Queue
7
+ from multiprocessing import Process, Value, Queue, set_start_method
7
8
  from multiprocessing.sharedctypes import Synchronized
8
- from multiprocessing import set_start_method
9
9
  from tkinter import ttk, scrolledtext
10
10
  from matplotlib.figure import Figure
11
11
  from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
12
- import time
13
- import requests
14
12
  from huggingface_hub import list_repo_files
15
13
 
16
- 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
17
- from .gui_elements import create_menu_bar, spacrButton, spacrLabel, spacrFrame, spacrDropdownMenu ,set_dark_style, set_default_font
18
- from . gui_run import run_mask_gui, run_measure_gui, run_classify_gui, run_sequencing_gui, run_umap_gui
19
-
20
14
  try:
21
15
  ctypes.windll.shcore.SetProcessDpiAwareness(True)
22
16
  except AttributeError:
23
17
  pass
24
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 spacrButton, spacrLabel, spacrFrame, spacrDropdownMenu ,set_dark_style, set_default_font
21
+
25
22
  # Define global variables
26
23
  q = None
27
24
  console_output = None
@@ -44,26 +41,116 @@ def initiate_abort():
44
41
  thread_control["run_thread"].join()
45
42
  thread_control["run_thread"] = None
46
43
 
47
- def start_process_v1(q, fig_queue, settings_type='mask'):
48
- global thread_control, vars_dict
49
- 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)
50
54
 
51
- settings = check_settings(vars_dict, expected_types, q)
52
- if thread_control.get("run_thread") is not None:
53
- initiate_abort()
54
- stop_requested = Value('i', 0) # multiprocessing shared value for inter-process communication
55
- 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
+
56
94
  if settings_type == 'mask':
57
- thread_control["run_thread"] = Process(target=run_mask_gui, args=(settings, q, fig_queue, stop_requested))
95
+ function = preprocess_generate_masks
96
+ imports = 2
58
97
  elif settings_type == 'measure':
59
- thread_control["run_thread"] = Process(target=run_measure_gui, args=(settings, q, fig_queue, stop_requested))
60
- elif settings_type == 'classify':
61
- 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
62
103
  elif settings_type == 'sequencing':
63
- thread_control["run_thread"] = Process(target=run_sequencing_gui, args=(settings, q, fig_queue, stop_requested))
64
- elif settings_type == 'umap':
65
- thread_control["run_thread"] = Process(target=run_umap_gui, args=(settings, q, fig_queue, stop_requested))
66
- 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
67
154
 
68
155
  def start_process(q=None, fig_queue=None, settings_type='mask'):
69
156
  global thread_control, vars_dict
@@ -83,25 +170,15 @@ def start_process(q=None, fig_queue=None, settings_type='mask'):
83
170
  if thread_control.get("run_thread") is not None:
84
171
  initiate_abort()
85
172
 
86
- stop_requested = Value('i', 0) # multiprocessing shared value for inter-process communication
173
+ stop_requested = Value('i', 0)
87
174
  thread_control["stop_requested"] = stop_requested
88
175
 
89
- process_args = (settings, q, fig_queue, stop_requested)
90
-
91
- if settings_type == 'mask':
92
- thread_control["run_thread"] = Process(target=run_mask_gui, args=process_args)
93
- elif settings_type == 'measure':
94
- thread_control["run_thread"] = Process(target=run_measure_gui, args=process_args)
95
- elif settings_type == 'classify':
96
- thread_control["run_thread"] = Process(target=run_classify_gui, args=process_args)
97
- elif settings_type == 'sequencing':
98
- thread_control["run_thread"] = Process(target=run_sequencing_gui, args=process_args)
99
- elif settings_type == 'umap':
100
- 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)
101
179
  else:
102
180
  q.put(f"Error: Unknown settings type '{settings_type}'")
103
181
  return
104
-
105
182
  thread_control["run_thread"].start()
106
183
 
107
184
  def import_settings(settings_type='mask'):
@@ -194,17 +271,16 @@ def convert_settings_dict_for_gui(settings):
194
271
 
195
272
  def setup_settings_panel(vertical_container, settings_type='mask', window_dimensions=[500, 1000]):
196
273
  global vars_dict, scrollable_frame
197
- 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, descriptions
274
+ from .settings import 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
198
275
 
199
- width = (window_dimensions[0])//6
276
+ width = (window_dimensions[0]) // 6
200
277
  height = window_dimensions[1]
201
278
 
202
- # Settings Frame
203
- settings_frame = tk.Frame(vertical_container, bg='black', height=height, width=width)
279
+ settings_frame = tk.Frame(vertical_container)
204
280
  vertical_container.add(settings_frame, stretch="always")
205
- settings_label = spacrLabel(settings_frame, text="Settings", background="black", foreground="white", anchor='center', justify='center', align="center")
281
+ settings_label = spacrLabel(settings_frame, text="Settings", anchor='center', justify='center', align="center")
206
282
  settings_label.grid(row=0, column=0, pady=10, padx=10)
207
- scrollable_frame = spacrFrame(settings_frame, bg='black', width=width)
283
+ scrollable_frame = spacrFrame(settings_frame)
208
284
  scrollable_frame.grid(row=1, column=0, sticky="nsew")
209
285
  settings_frame.grid_rowconfigure(1, weight=1)
210
286
  settings_frame.grid_columnconfigure(0, weight=1)
@@ -219,11 +295,32 @@ def setup_settings_panel(vertical_container, settings_type='mask', window_dimens
219
295
  settings = get_analyze_reads_default_settings(settings={})
220
296
  elif settings_type == 'umap':
221
297
  settings = set_default_umap_image_settings(settings={})
298
+ elif settings_type == 'train_cellpose':
299
+ settings = get_train_cellpose_default_settings(settings={})
300
+ elif settings_type == 'ml_analyze':
301
+ settings = set_default_analyze_screen(settings={})
302
+ elif settings_type == 'cellpose_masks':
303
+ settings = get_identify_masks_finetune_default_settings(settings={})
304
+ elif settings_type == 'cellpose_all':
305
+ settings = get_check_cellpose_models_default_settings(settings={})
306
+ elif settings_type == 'map_barcodes':
307
+ settings = get_map_barcodes_default_settings(settings={})
308
+ elif settings_type == 'regression':
309
+ settings = get_perform_regression_default_settings(settings={})
310
+ elif settings_type == 'recruitment':
311
+ settings = get_analyze_recruitment_default_settings(settings={})
222
312
  else:
223
313
  raise ValueError(f"Invalid settings type: {settings_type}")
224
314
 
225
315
  variables = convert_settings_dict_for_gui(settings)
226
316
  vars_dict = generate_fields(variables, scrollable_frame)
317
+
318
+ containers = [settings_frame]
319
+ widgets = [settings_label, scrollable_frame]
320
+
321
+ style = ttk.Style(vertical_container)
322
+ _ = set_dark_style(style, containers=containers, widgets=widgets)
323
+
227
324
  print("Settings panel setup complete")
228
325
  return scrollable_frame, vars_dict
229
326
 
@@ -231,45 +328,57 @@ def setup_plot_section(vertical_container):
231
328
  global canvas, canvas_widget
232
329
  plot_frame = tk.PanedWindow(vertical_container, orient=tk.VERTICAL)
233
330
  vertical_container.add(plot_frame, stretch="always")
234
- figure = Figure(figsize=(30, 4), dpi=100, facecolor='black')
331
+ figure = Figure(figsize=(30, 4), dpi=100)
235
332
  plot = figure.add_subplot(111)
236
333
  plot.plot([], []) # This creates an empty plot.
237
334
  plot.axis('off')
238
335
  canvas = FigureCanvasTkAgg(figure, master=plot_frame)
239
- canvas.get_tk_widget().configure(cursor='arrow', background='black', highlightthickness=0)
336
+ canvas.get_tk_widget().configure(cursor='arrow', highlightthickness=0)
240
337
  canvas_widget = canvas.get_tk_widget()
241
338
  plot_frame.add(canvas_widget, stretch="always")
242
339
  canvas.draw()
243
340
  canvas.figure = figure
341
+ # Set the figure and axes background to black
342
+ figure.patch.set_facecolor('black')
343
+ plot.set_facecolor('black')
344
+ containers = [plot_frame]
345
+ widgets = [canvas_widget]
346
+ style = ttk.Style(vertical_container)
347
+ _ = set_dark_style(style, containers=containers, widgets=widgets)
244
348
  return canvas, canvas_widget
245
349
 
246
350
  def setup_console(vertical_container):
247
351
  global console_output
248
- print("Setting up console frame")
249
- console_frame = tk.Frame(vertical_container, bg='black')
352
+ console_frame = tk.Frame(vertical_container)
250
353
  vertical_container.add(console_frame, stretch="always")
251
- console_label = spacrLabel(console_frame, text="Console", background="black", foreground="white", anchor='center', justify='center', align="center")
354
+ console_label = spacrLabel(console_frame, text="Console", anchor='center', justify='center', align="center")
252
355
  console_label.grid(row=0, column=0, pady=10, padx=10)
253
- console_output = scrolledtext.ScrolledText(console_frame, height=10, bg='black', fg='white', insertbackground='white')
356
+ console_output = scrolledtext.ScrolledText(console_frame, height=10)
254
357
  console_output.grid(row=1, column=0, sticky="nsew")
255
358
  console_frame.grid_rowconfigure(1, weight=1)
256
359
  console_frame.grid_columnconfigure(0, weight=1)
257
- print("Console setup complete")
360
+ containers = [console_frame]
361
+ widgets = [console_label, console_output]
362
+ style = ttk.Style(vertical_container)
363
+ _ = set_dark_style(style, containers=containers, widgets=widgets)
258
364
  return console_output
259
365
 
260
366
  def setup_progress_frame(vertical_container):
261
367
  global progress_output
262
- progress_frame = tk.Frame(vertical_container, bg='black')
368
+ progress_frame = tk.Frame(vertical_container)
263
369
  vertical_container.add(progress_frame, stretch="always")
264
- label_frame = tk.Frame(progress_frame, bg='black')
370
+ label_frame = tk.Frame(progress_frame)
265
371
  label_frame.grid(row=0, column=0, sticky="ew", pady=(5, 0), padx=10)
266
- progress_label = spacrLabel(label_frame, text="Processing: 0%", background="black", foreground="white", font=('Helvetica', 12), anchor='w', justify='left', align="left")
372
+ progress_label = spacrLabel(label_frame, text="Processing: 0%", font=('Helvetica', 12), anchor='w', justify='left', align="left")
267
373
  progress_label.grid(row=0, column=0, sticky="w")
268
- progress_output = scrolledtext.ScrolledText(progress_frame, height=10, bg='black', fg='white', insertbackground='white')
374
+ progress_output = scrolledtext.ScrolledText(progress_frame, height=10)
269
375
  progress_output.grid(row=1, column=0, sticky="nsew")
270
376
  progress_frame.grid_rowconfigure(1, weight=1)
271
377
  progress_frame.grid_columnconfigure(0, weight=1)
272
- print("Progress frame setup complete")
378
+ containers = [progress_frame, label_frame]
379
+ widgets = [progress_label, progress_output]
380
+ style = ttk.Style(vertical_container)
381
+ _ = set_dark_style(style, containers=containers, widgets=widgets)
273
382
  return progress_output
274
383
 
275
384
  def download_hug_dataset():
@@ -355,59 +464,70 @@ def download_dataset(repo_id, subfolder, local_dir=None, retries=5, delay=5):
355
464
 
356
465
  raise Exception("Failed to download files after multiple attempts.")
357
466
 
358
- def setup_button_section(horizontal_container, settings_type='mask', window_dimensions=[500, 1000], run=True, abort=True, download=True, import_btn=True):
467
+ def setup_button_section(horizontal_container, settings_type='mask', window_dimensions=[500, 1000], run=True, abort=True, download=True, import_btn=True):
359
468
  global button_frame, button_scrollable_frame, run_button, abort_button, download_dataset_button, import_button, q, fig_queue, vars_dict
360
469
  from .settings import descriptions
361
470
 
362
- width = (window_dimensions[0])//8
471
+ width = (window_dimensions[0]) // 8
363
472
  height = window_dimensions[1]
364
473
 
365
- button_frame = tk.Frame(horizontal_container, bg='black', height=height, width=width)
474
+ button_frame = tk.Frame(horizontal_container)
366
475
  horizontal_container.add(button_frame, stretch="always", sticky="nsew")
367
476
  button_frame.grid_rowconfigure(0, weight=0)
368
477
  button_frame.grid_rowconfigure(1, weight=1)
369
478
  button_frame.grid_columnconfigure(0, weight=1)
370
479
 
371
- categories_label = spacrLabel(button_frame, text="Categories", background="black", foreground="white", font=('Helvetica', 12), anchor='center', justify='center', align="center")
480
+ categories_label = spacrLabel(button_frame, text="Categories", anchor='center', justify='center', align="center")
372
481
  categories_label.grid(row=0, column=0, pady=10, padx=10)
373
- button_scrollable_frame = spacrFrame(button_frame, bg='black')
482
+ button_scrollable_frame = spacrFrame(button_frame)
374
483
  button_scrollable_frame.grid(row=1, column=0, sticky="nsew")
375
484
 
485
+ widgets = [categories_label, button_scrollable_frame.scrollable_frame]
486
+
376
487
  btn_col = 0
377
488
  btn_row = 1
378
-
489
+
379
490
  if run:
380
- run_button = spacrButton(button_scrollable_frame.scrollable_frame, text="Run", command=lambda: start_process(q, fig_queue, settings_type), font=('Helvetica', 12))
491
+ run_button = spacrButton(button_scrollable_frame.scrollable_frame, text="Run", command=lambda: start_process(q, fig_queue, settings_type))
381
492
  run_button.grid(row=btn_row, column=btn_col, pady=5, padx=5, sticky='ew')
493
+ widgets.append(run_button)
382
494
  btn_row += 1
383
495
 
384
496
  if abort and settings_type in ['mask', 'measure', 'classify', 'sequencing', 'umap']:
385
- abort_button = spacrButton(button_scrollable_frame.scrollable_frame, text="Abort", command=initiate_abort, font=('Helvetica', 12))
497
+ abort_button = spacrButton(button_scrollable_frame.scrollable_frame, text="Abort", command=initiate_abort)
386
498
  abort_button.grid(row=btn_row, column=btn_col, pady=5, padx=5, sticky='ew')
499
+ widgets.append(abort_button)
387
500
  btn_row += 1
388
501
 
389
502
  if download and settings_type in ['mask']:
390
- download_dataset_button = spacrButton(button_scrollable_frame.scrollable_frame, text="Download", command=download_hug_dataset, font=('Helvetica', 12))
503
+ download_dataset_button = spacrButton(button_scrollable_frame.scrollable_frame, text="Download", command=download_hug_dataset)
391
504
  download_dataset_button.grid(row=btn_row, column=btn_col, pady=5, padx=5, sticky='ew')
505
+ widgets.append(download_dataset_button)
392
506
  btn_row += 1
393
507
 
394
508
  if import_btn:
395
- import_button = spacrButton(button_scrollable_frame.scrollable_frame, text="Import", command=lambda: import_settings(settings_type), font=('Helvetica', 12))
509
+ import_button = spacrButton(button_scrollable_frame.scrollable_frame, text="Import", command=lambda: import_settings(settings_type))
396
510
  import_button.grid(row=btn_row, column=btn_col, pady=5, padx=5, sticky='ew')
511
+ widgets.append(import_button)
397
512
 
398
- # Call toggle_settings after vars_dict is initialized
399
513
  if vars_dict is not None:
400
514
  toggle_settings(button_scrollable_frame)
401
515
 
402
- # Description frame
403
- description_frame = tk.Frame(horizontal_container, bg='black', height=height, width=width)
516
+ description_frame = tk.Frame(horizontal_container)
404
517
  horizontal_container.add(description_frame, stretch="always", sticky="nsew")
405
- description_label = tk.Label(description_frame, text="Module Description", bg='black', fg='white', anchor='nw', justify='left', wraplength=width//2-100)
406
- description_label.pack(pady=10, padx=10)
518
+ description_frame.grid_columnconfigure(0, weight=1)
519
+ description_label = tk.Label(description_frame, text="Module Description", anchor='nw', justify='left', wraplength=width - 50)
520
+ description_label.grid(row=0, column=0, pady=50, padx=20, sticky='nsew')
407
521
  description_text = descriptions.get(settings_type, "No description available for this module.")
408
522
  description_label.config(text=description_text)
409
523
 
410
- return button_scrollable_frame
524
+ containers = [button_frame, description_frame]
525
+ widgets.extend([description_label])
526
+
527
+ style = ttk.Style(horizontal_container)
528
+ _ = set_dark_style(style, containers=containers, widgets=widgets)
529
+
530
+ return button_frame, button_scrollable_frame, description_frame, description_label
411
531
 
412
532
  def hide_all_settings(vars_dict, categories):
413
533
  """
@@ -456,7 +576,6 @@ def toggle_settings(button_scrollable_frame):
456
576
  def on_category_select(selected_category):
457
577
  if selected_category == "Select Category":
458
578
  return
459
- #print(f"Selected category: {selected_category}")
460
579
  if selected_category in categories:
461
580
  toggle_category(categories[selected_category])
462
581
  if selected_category in active_categories:
@@ -464,7 +583,7 @@ def toggle_settings(button_scrollable_frame):
464
583
  else:
465
584
  active_categories.add(selected_category)
466
585
  category_dropdown.update_styles(active_categories)
467
- category_var.set("Select Category") # Reset dropdown text to "Select Category"
586
+ category_var.set("Select Category")
468
587
 
469
588
  category_var = tk.StringVar()
470
589
  non_empty_categories = [category for category, settings in categories.items() if any(setting in vars_dict for setting in settings)]
@@ -522,24 +641,29 @@ def set_globals(q_var, console_output_var, parent_frame_var, vars_dict_var, canv
522
641
  progress_label = progress_label_var
523
642
  fig_queue = fig_queue_var
524
643
 
644
+ def create_containers(parent_frame):
645
+ vertical_container = tk.PanedWindow(parent_frame, orient=tk.VERTICAL)
646
+ horizontal_container = tk.PanedWindow(vertical_container, orient=tk.HORIZONTAL)
647
+ settings_frame = tk.Frame(horizontal_container)
648
+ return vertical_container, horizontal_container, settings_frame
649
+
525
650
  def setup_frame(parent_frame):
526
651
  style = ttk.Style(parent_frame)
527
- set_dark_style(style)
652
+ vertical_container, horizontal_container, settings_frame = create_containers(parent_frame)
653
+ containers = [vertical_container, horizontal_container, settings_frame]
654
+
655
+ set_dark_style(style, parent_frame, containers)
528
656
  set_default_font(parent_frame, font_name="Helvetica", size=8)
529
- parent_frame.configure(bg='black')
530
- parent_frame.grid_rowconfigure(0, weight=1)
531
- parent_frame.grid_columnconfigure(0, weight=1)
532
- vertical_container = tk.PanedWindow(parent_frame, orient=tk.VERTICAL, bg='black')
657
+
533
658
  vertical_container.grid(row=0, column=0, sticky=tk.NSEW)
534
- horizontal_container = tk.PanedWindow(vertical_container, orient=tk.HORIZONTAL, bg='black')
535
659
  vertical_container.add(horizontal_container, stretch="always")
536
660
  horizontal_container.grid_columnconfigure(0, weight=1)
537
661
  horizontal_container.grid_columnconfigure(1, weight=1)
538
- settings_frame = tk.Frame(horizontal_container, bg='black')
539
662
  settings_frame.grid_rowconfigure(0, weight=0)
540
663
  settings_frame.grid_rowconfigure(1, weight=1)
541
664
  settings_frame.grid_columnconfigure(0, weight=1)
542
665
  horizontal_container.add(settings_frame, stretch="always", sticky="nsew")
666
+
543
667
  return parent_frame, vertical_container, horizontal_container
544
668
 
545
669
  def initiate_root(parent, settings_type='mask'):