spacr 0.0.36__py3-none-any.whl → 0.0.62__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
@@ -1,5 +1,6 @@
1
1
  import tkinter as tk
2
2
  from tkinter import ttk
3
+ from tkinter import font as tkFont
3
4
  from PIL import Image, ImageTk
4
5
  import os
5
6
  import requests
@@ -17,7 +18,7 @@ class MainApp(tk.Tk):
17
18
  def __init__(self):
18
19
  super().__init__()
19
20
  self.title("SpaCr GUI Collection")
20
- self.geometry("1200x350")
21
+ self.geometry("1100x1500")
21
22
  self.configure(bg="black")
22
23
  #self.attributes('-fullscreen', True)
23
24
 
@@ -58,24 +59,24 @@ class MainApp(tk.Tk):
58
59
 
59
60
  # Load the logo image
60
61
  if not self.load_logo(logo_frame):
61
- tk.Label(logo_frame, text="Logo not found", bg="black", fg="white", font=('Open Sans', 24)).pack(padx=20, pady=20)
62
+ tk.Label(logo_frame, text="Logo not found", bg="black", fg="white", font=('Arial', 24, tkFont.NORMAL)).pack(padx=10, pady=10)
62
63
 
63
64
  # Add SpaCr text below the logo with padding for sharper text
64
- tk.Label(logo_frame, text="SpaCr", bg="black", fg="#008080", font=('Open Sans', 24)).pack(padx=20, pady=20)
65
+ tk.Label(logo_frame, text="SpaCr", bg="black", fg="#008080", font=('Arial', 24, tkFont.NORMAL)).pack(padx=10, pady=10)
65
66
 
66
67
  # Create a frame for the buttons and descriptions
67
68
  buttons_frame = tk.Frame(self.content_frame, bg="black")
68
- buttons_frame.pack(pady=20, expand=True, padx=20)
69
+ buttons_frame.pack(pady=10, expand=True, padx=10)
69
70
 
70
71
  for i, (app_name, app_data) in enumerate(self.gui_apps.items()):
71
72
  app_func, app_desc = app_data
72
73
 
73
74
  # Create custom button with text
74
75
  button = CustomButton(buttons_frame, text=app_name, command=lambda app_name=app_name: self.load_app(app_name))
75
- button.grid(row=i, column=0, pady=20, padx=20, sticky="w")
76
+ button.grid(row=i, column=0, pady=10, padx=10, sticky="w")
76
77
 
77
- description_label = tk.Label(buttons_frame, text=app_desc, bg="black", fg="white", wraplength=800, justify="left", font=('Open Sans', 12))
78
- description_label.grid(row=i, column=1, pady=20, padx=20, sticky="w")
78
+ description_label = tk.Label(buttons_frame, text=app_desc, bg="black", fg="white", wraplength=800, justify="left", font=('Arial', 10, tkFont.NORMAL))
79
+ description_label.grid(row=i, column=1, pady=10, padx=10, sticky="w")
79
80
 
80
81
  # Ensure buttons have a fixed width
81
82
  buttons_frame.grid_columnconfigure(0, minsize=150)
@@ -141,4 +142,4 @@ def gui_app():
141
142
  app.mainloop()
142
143
 
143
144
  if __name__ == "__main__":
144
- gui_app()
145
+ gui_app()
spacr/gui_2.py ADDED
@@ -0,0 +1,90 @@
1
+ import customtkinter as ctk
2
+ from PIL import Image, ImageTk
3
+ import os
4
+ import requests
5
+
6
+ class MainApp(ctk.CTk):
7
+ def __init__(self):
8
+ super().__init__()
9
+ self.title("SpaCr GUI Collection")
10
+ self.geometry("1200x800")
11
+ ctk.set_appearance_mode("dark") # Modes: "System" (standard), "Dark", "Light"
12
+ ctk.set_default_color_theme("dark-blue") # Themes: "blue" (standard), "green", "dark-blue")
13
+
14
+ # Set scaling factor for high DPI displays; use a floating-point value.
15
+ self.tk.call('tk', 'scaling', 1.5)
16
+
17
+ self.create_widgets()
18
+
19
+ def create_widgets(self):
20
+ self.content_frame = ctk.CTkFrame(self)
21
+ self.content_frame.pack(fill="both", expand=True, padx=20, pady=20)
22
+
23
+ logo_frame = ctk.CTkFrame(self.content_frame)
24
+ logo_frame.pack(pady=20, expand=True)
25
+
26
+ if not self.load_logo(logo_frame):
27
+ ctk.CTkLabel(logo_frame, text="Logo not found", text_color="white", font=('Helvetica', 24)).pack(padx=10, pady=10)
28
+
29
+ ctk.CTkLabel(logo_frame, text="SpaCr", text_color="#00BFFF", font=('Helvetica', 36, "bold")).pack(padx=10, pady=10)
30
+
31
+ button = ctk.CTkButton(
32
+ self.content_frame,
33
+ text="Mask",
34
+ command=self.load_mask_app,
35
+ width=250,
36
+ height=60,
37
+ corner_radius=20,
38
+ fg_color="#1E90FF",
39
+ hover_color="#4682B4",
40
+ text_color="white",
41
+ font=("Helvetica", 18, "bold")
42
+ )
43
+ button.pack(pady=20)
44
+
45
+ def load_logo(self, frame):
46
+ def download_image(url, save_path):
47
+ try:
48
+ response = requests.get(url, stream=True)
49
+ response.raise_for_status()
50
+ with open(save_path, 'wb') as f:
51
+ for chunk in response.iter_content(chunk_size=8192):
52
+ f.write(chunk)
53
+ return True
54
+ except requests.exceptions.RequestException as e:
55
+ print(f"Failed to download image from {url}: {e}")
56
+ return False
57
+
58
+ try:
59
+ img_path = os.path.join(os.path.dirname(__file__), 'logo_spacr.png')
60
+ logo_image = Image.open(img_path)
61
+ except (FileNotFoundError, Image.UnidentifiedImageError):
62
+ if download_image('https://raw.githubusercontent.com/EinarOlafsson/spacr/main/spacr/logo_spacr.png', img_path):
63
+ try:
64
+ logo_image = Image.open(img_path)
65
+ except Image.UnidentifiedImageError as e:
66
+ return False
67
+ else:
68
+ return False
69
+ except Exception as e:
70
+ return False
71
+
72
+ try:
73
+ logo_image = logo_image.resize((200, 200), Image.Resampling.LANCZOS)
74
+ logo_photo = ImageTk.PhotoImage(logo_image)
75
+ logo_label = ctk.CTkLabel(frame, image=logo_photo)
76
+ logo_label.image = logo_photo # Keep a reference to avoid garbage collection
77
+ logo_label.pack()
78
+ return True
79
+ except Exception as e:
80
+ return False
81
+
82
+ def load_mask_app(self):
83
+ print("Mask app loaded.") # Placeholder for mask app loading function
84
+
85
+ def gui_app():
86
+ app = MainApp()
87
+ app.mainloop()
88
+
89
+ if __name__ == "__main__":
90
+ gui_app()
spacr/gui_classify_app.py CHANGED
@@ -1,7 +1,6 @@
1
- import sys, ctypes, csv, matplotlib
1
+ import sys, ctypes, matplotlib
2
2
  import tkinter as tk
3
3
  from tkinter import ttk, scrolledtext
4
- from ttkthemes import ThemedTk
5
4
  from matplotlib.figure import Figure
6
5
  from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
7
6
  from matplotlib.figure import Figure
@@ -70,13 +69,13 @@ def import_settings(scrollable_frame):
70
69
  vars_dict = generate_fields(new_settings, scrollable_frame)
71
70
 
72
71
  #@log_function_call
73
- def initiate_classify_root(parent_frame, width, height):
72
+ def initiate_classify_root(parent_frame):#, width, height):
74
73
  global vars_dict, q, canvas, fig_queue, canvas_widget, thread_control
75
74
 
76
75
  style = ttk.Style(parent_frame)
77
76
  set_dark_style(style)
78
77
  style_text_boxes(style)
79
- set_default_font(parent_frame, font_name="Open Sans", size=8)
78
+ set_default_font(parent_frame, font_name="Arial", size=8)
80
79
 
81
80
  parent_frame.configure(bg='#333333')
82
81
  parent_frame.grid_rowconfigure(0, weight=1)
spacr/gui_mask_app.py CHANGED
@@ -1,7 +1,8 @@
1
+ #import customtkinter as ctk
2
+
1
3
  import sys, ctypes, matplotlib
2
4
  import tkinter as tk
3
5
  from tkinter import ttk, scrolledtext
4
- from ttkthemes import ThemedTk
5
6
  from matplotlib.figure import Figure
6
7
  from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
7
8
  matplotlib.use('Agg')
@@ -15,7 +16,7 @@ except AttributeError:
15
16
  pass
16
17
 
17
18
  from .logger import log_function_call
18
- from .gui_utils import ScrollableFrame, StdoutRedirector, ToggleSwitch, CustomButton
19
+ from .gui_utils import ScrollableFrame, StdoutRedirector, ToggleSwitch, CustomButton, ToolTip
19
20
  from .gui_utils import clear_canvas, main_thread_update_function, set_dark_style, generate_fields, process_stdout_stderr, set_default_font, style_text_boxes
20
21
  from .gui_utils import mask_variables, check_mask_gui_settings, preprocess_generate_masks_wrapper, read_settings_from_csv, update_settings_from_csv, create_menu_bar
21
22
 
@@ -102,7 +103,7 @@ def initiate_mask_root(parent_frame, width, height):
102
103
  style = ttk.Style(parent_frame)
103
104
  set_dark_style(style)
104
105
  style_text_boxes(style)
105
- set_default_font(parent_frame, font_name="Open Sans", size=8)
106
+ set_default_font(parent_frame, font_name="Arial", size=8)
106
107
  parent_frame.configure(bg='black')
107
108
  parent_frame.grid_rowconfigure(0, weight=1)
108
109
  parent_frame.grid_columnconfigure(0, weight=1)
@@ -165,12 +166,12 @@ def initiate_mask_root(parent_frame, width, height):
165
166
  # Button section
166
167
  test_mode_button = CustomButton(scrollable_frame.scrollable_frame, text="Test Mode", command=toggle_test_mode)
167
168
  test_mode_button.grid(row=47, column=1, pady=10, padx=10)
168
- import_btn = CustomButton(scrollable_frame.scrollable_frame, text="Import Settings", command=lambda: import_settings(scrollable_frame))
169
- import_btn.grid(row=47, column=0, pady=20, padx=20)
169
+ import_btn = CustomButton(scrollable_frame.scrollable_frame, text="Import", command=lambda: import_settings(scrollable_frame))
170
+ import_btn.grid(row=47, column=0, pady=10, padx=10)
170
171
  run_button = CustomButton(scrollable_frame.scrollable_frame, text="Run", command=lambda: start_process(q, fig_queue))
171
- run_button.grid(row=45, column=0, pady=20, padx=20)
172
+ run_button.grid(row=45, column=0, pady=10, padx=10)
172
173
  abort_button = CustomButton(scrollable_frame.scrollable_frame, text="Abort", command=initiate_abort)
173
- abort_button.grid(row=45, column=1, pady=20, padx=20)
174
+ abort_button.grid(row=45, column=1, pady=10, padx=10)
174
175
  progress_label = ttk.Label(scrollable_frame.scrollable_frame, text="Processing: 0%", background="black", foreground="white") # Create progress field
175
176
  progress_label.grid(row=50, column=0, columnspan=2, sticky="ew", pady=(5, 0), padx=10)
176
177
 
@@ -218,5 +219,4 @@ def gui_mask():
218
219
  root.mainloop()
219
220
 
220
221
  if __name__ == "__main__":
221
- gui_mask()
222
-
222
+ gui_mask()
spacr/gui_measure_app.py CHANGED
@@ -3,10 +3,8 @@ import tkinter as tk
3
3
  from tkinter import ttk, scrolledtext
4
4
  from matplotlib.figure import Figure
5
5
  from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
6
- import matplotlib.pyplot as plt
7
6
  matplotlib.use('Agg') # Use the non-GUI Agg backend
8
7
  from multiprocessing import Process, Queue, Value
9
- from ttkthemes import ThemedTk
10
8
  from tkinter import filedialog
11
9
 
12
10
  try:
@@ -15,7 +13,7 @@ except AttributeError:
15
13
  pass
16
14
 
17
15
  from .logger import log_function_call
18
- from .gui_utils import ScrollableFrame, StdoutRedirector, CustomButton, ToggleSwitch
16
+ from .gui_utils import ScrollableFrame, StdoutRedirector, CustomButton, ToggleSwitch, ToolTip
19
17
  from .gui_utils import process_stdout_stderr, set_dark_style, set_default_font, generate_fields, main_thread_update_function, create_menu_bar
20
18
  from .gui_utils import measure_variables, measure_crop_wrapper, clear_canvas, check_measure_gui_settings, read_settings_from_csv, update_settings_from_csv, style_text_boxes
21
19
 
@@ -98,13 +96,13 @@ def import_settings(scrollable_frame):
98
96
  vars_dict = generate_fields(new_settings, scrollable_frame)
99
97
 
100
98
  #@log_function_call
101
- def initiate_measure_root(parent_frame, width, height):
99
+ def initiate_measure_root(parent_frame):#, width, height):
102
100
  global vars_dict, q, canvas, fig_queue, canvas_widget, thread_control, variables, advanced_var, scrollable_frame
103
101
 
104
102
  style = ttk.Style(parent_frame)
105
103
  set_dark_style(style)
106
104
  style_text_boxes(style)
107
- set_default_font(parent_frame, font_name="Open Sans", size=8)
105
+ set_default_font(parent_frame, font_name="Arial", size=8)
108
106
 
109
107
  parent_frame.configure(bg='black')
110
108
  parent_frame.grid_rowconfigure(0, weight=1)
spacr/gui_utils.py CHANGED
@@ -6,6 +6,10 @@ import tkinter as tk
6
6
  from tkinter import ttk, messagebox
7
7
  import tkinter.font as tkFont
8
8
  from torchvision import models
9
+ #from ttf_opensans import opensans
10
+
11
+ from tkinter import font as tkFont
12
+
9
13
 
10
14
  from .logger import log_function_call
11
15
 
@@ -14,6 +18,29 @@ try:
14
18
  except AttributeError:
15
19
  pass
16
20
 
21
+ class ToolTip:
22
+ def __init__(self, widget, text):
23
+ self.widget = widget
24
+ self.text = text
25
+ self.tooltip_window = None
26
+ widget.bind("<Enter>", self.show_tooltip)
27
+ widget.bind("<Leave>", self.hide_tooltip)
28
+
29
+ def show_tooltip(self, event):
30
+ x = event.x_root + 20
31
+ y = event.y_root + 10
32
+ self.tooltip_window = tk.Toplevel(self.widget)
33
+ self.tooltip_window.wm_overrideredirect(True)
34
+ self.tooltip_window.wm_geometry(f"+{x}+{y}")
35
+ label = tk.Label(self.tooltip_window, text=self.text, background="yellow", relief='solid', borderwidth=1)
36
+ label.pack()
37
+
38
+ def hide_tooltip(self, event):
39
+ if self.tooltip_window:
40
+ self.tooltip_window.destroy()
41
+ self.tooltip_window = None
42
+
43
+
17
44
  def load_app(root, app_name, app_func):
18
45
  # Destroy the current window
19
46
  root.destroy()
@@ -61,18 +88,14 @@ class CustomButton(tk.Frame):
61
88
  self.text = text
62
89
  self.command = command
63
90
 
64
- self.canvas = tk.Canvas(self, width=200, height=50, highlightthickness=0, bg="black")
91
+ self.canvas = tk.Canvas(self, width=150, height=50, highlightthickness=0, bg="black")
65
92
  self.canvas.grid(row=0, column=0)
66
93
 
67
- self.button_bg = self.create_rounded_rectangle(0, 0, 200, 50, radius=20, fill="#800080")
68
-
69
- # Load the Open Sans font
70
- self.font_path = 'fonts/OpenSans-Regular.ttf'
71
- if not os.path.exists(self.font_path):
72
- self.download_font()
94
+ self.button_bg = self.create_rounded_rectangle(0, 0, 150, 50, radius=20, fill="#800080")
73
95
 
74
- self.open_sans = tkFont.Font(family="Open Sans", size=10)
75
- self.button_text = self.canvas.create_text(100, 25, text=self.text, fill="white", font=self.open_sans)
96
+ # Create a Tkinter font object using OpenSans
97
+ self.font_style = tkFont.Font(family="Arial", size=12, weight=tkFont.NORMAL)
98
+ self.button_text = self.canvas.create_text(75, 25, text=self.text, fill="white", font=self.font_style)
76
99
 
77
100
  self.bind("<Enter>", self.on_enter)
78
101
  self.bind("<Leave>", self.on_leave)
@@ -114,7 +137,7 @@ class CustomButton(tk.Frame):
114
137
  x1, y1]
115
138
 
116
139
  return self.canvas.create_polygon(points, **kwargs, smooth=True)
117
-
140
+
118
141
  class ToggleSwitch(ttk.Frame):
119
142
  def __init__(self, parent, text="", variable=None, command=None, *args, **kwargs):
120
143
  super().__init__(parent, *args, **kwargs)
@@ -203,7 +226,7 @@ class ToggleSwitch(ttk.Frame):
203
226
 
204
227
  return self.canvas.create_polygon(points, **kwargs, smooth=True)
205
228
 
206
- def set_default_font(root, font_name="Helvetica", size=12):
229
+ def set_default_font(root, font_name="Arial", size=12):
207
230
  default_font = (font_name, size)
208
231
  root.option_add("*Font", default_font)
209
232
  root.option_add("*TButton.Font", default_font)
@@ -211,7 +234,7 @@ def set_default_font(root, font_name="Helvetica", size=12):
211
234
  root.option_add("*TEntry.Font", default_font)
212
235
 
213
236
  def check_and_download_font():
214
- font_name = "Open Sans"
237
+ font_name = "Arial"
215
238
  font_dir = "fonts"
216
239
  font_path = os.path.join(font_dir, "OpenSans-Regular.ttf")
217
240
 
@@ -234,36 +257,25 @@ def check_and_download_font():
234
257
  tkFont.nametofont("TkTextFont").configure(family=font_name, size=10)
235
258
  tkFont.nametofont("TkHeadingFont").configure(family=font_name, size=12)
236
259
  except tk.TclError:
237
- tkFont.nametofont("TkDefaultFont").configure(family="Open Sans", size=10)
238
- tkFont.nametofont("TkTextFont").configure(family="Open Sans", size=10)
239
- tkFont.nametofont("TkHeadingFont").configure(family="Open Sans", size=12)
260
+ tkFont.nametofont("TkDefaultFont").configure(family="Arial", size=10)
261
+ tkFont.nametofont("TkTextFont").configure(family="Arial", size=10)
262
+ tkFont.nametofont("TkHeadingFont").configure(family="Arial", size=12)
240
263
  else:
241
264
  tkFont.nametofont("TkDefaultFont").configure(family=font_name, size=10)
242
265
  tkFont.nametofont("TkTextFont").configure(family=font_name, size=10)
243
266
  tkFont.nametofont("TkHeadingFont").configure(family=font_name, size=12)
244
267
 
245
- def style_text_boxes_v1(style):
246
- style.configure('TEntry', padding='5 5 5 5', borderwidth=1, relief='solid', fieldbackground='#000000', foreground='#ffffff')
247
- style.configure('TCombobox', fieldbackground='#000000', background='#000000', foreground='#ffffff')
248
- style.configure('Custom.TButton', padding='10 10 10 10', borderwidth=1, relief='solid', background='#008080', foreground='#ffffff', font=('Open Sans', 10, 'bold'))
249
- style.map('Custom.TButton',
250
- background=[('active', '#66b2b2'), ('disabled', '#004d4d'), ('!disabled', '#008080')],
251
- foreground=[('active', '#ffffff'), ('disabled', '#888888')])
252
- style.configure('Custom.TLabel', padding='5 5 5 5', borderwidth=1, relief='flat', background='#000000', foreground='#ffffff', font=('Open Sans', 10))
253
- style.configure('TCheckbutton', background='#333333', foreground='#ffffff', indicatoron=False, relief='flat')
254
- style.map('TCheckbutton', background=[('selected', '#555555'), ('active', '#555555')])
255
-
256
268
  def style_text_boxes(style):
257
269
  check_and_download_font()
258
- open_sans = tkFont.Font(family="Open Sans", size=10) # Define the Open Sans font
259
- style.configure('TEntry', padding='5 5 5 5', borderwidth=1, relief='solid', fieldbackground='#000000', foreground='#ffffff', font=open_sans)
260
- style.configure('TCombobox', fieldbackground='#000000', background='#000000', foreground='#ffffff', font=open_sans)
261
- style.configure('Custom.TButton', padding='10 10 10 10', borderwidth=1, relief='solid', background='#008080', foreground='#ffffff', font=open_sans)
270
+ font_style = tkFont.Font(family="Arial", size=10) # Define the Arial font
271
+ style.configure('TEntry', padding='5 5 5 5', borderwidth=1, relief='solid', fieldbackground='#000000', foreground='#ffffff', font=font_style)
272
+ style.configure('TCombobox', fieldbackground='#000000', background='#000000', foreground='#ffffff', font=font_style)
273
+ style.configure('Custom.TButton', padding='10 10 10 10', borderwidth=1, relief='solid', background='#008080', foreground='#ffffff', font=font_style)
262
274
  style.map('Custom.TButton',
263
275
  background=[('active', '#66b2b2'), ('disabled', '#004d4d'), ('!disabled', '#008080')],
264
276
  foreground=[('active', '#ffffff'), ('disabled', '#888888')])
265
- style.configure('Custom.TLabel', padding='5 5 5 5', borderwidth=1, relief='flat', background='#000000', foreground='#ffffff', font=open_sans)
266
- style.configure('TCheckbutton', background='#333333', foreground='#ffffff', indicatoron=False, relief='flat', font=open_sans)
277
+ style.configure('Custom.TLabel', padding='5 5 5 5', borderwidth=1, relief='flat', background='#000000', foreground='#ffffff', font=font_style)
278
+ style.configure('TCheckbutton', background='#333333', foreground='#ffffff', indicatoron=False, relief='flat', font=font_style)
267
279
  style.map('TCheckbutton', background=[('selected', '#555555'), ('active', '#555555')])
268
280
 
269
281
 
@@ -701,11 +713,98 @@ def add_mask_gui_defaults(settings):
701
713
  def generate_fields(variables, scrollable_frame):
702
714
  vars_dict = {}
703
715
  row = 0
716
+ tooltips = {
717
+ "src": "Path to the folder containing the images.",
718
+ "metadata_type": "Type of metadata to expect in the images. This will determine how the images are processed. If 'custom' is selected, you can provide a custom regex pattern to extract metadata from the image names",
719
+ "custom_regex": "Custom regex pattern to extract metadata from the image names. This will only be used if 'custom' is selected for 'metadata_type'.",
720
+ "experiment": "Name of the experiment. This will be used to name the output files.",
721
+ "channels": "List of channels to use for the analysis. The first channel is 0, the second is 1, and so on. For example, [0,1,2] will use channels 0, 1, and 2.",
722
+ "magnification": "At what magnification the images were taken. This will be used to determine the size of the objects in the images.",
723
+ "nucleus_channel": "The channel to use for the nucleus. If None, the nucleus will not be segmented.",
724
+ "nucleus_background": "The background intensity for the nucleus channel. This will be used to remove background noise.",
725
+ "nucleus_Signal_to_noise": "The signal-to-noise ratio for the nucleus channel. This will be used to determine the range of intensities to normalize images to for nucleus segmentation.",
726
+ "nucleus_CP_prob": "The cellpose probability threshold for the nucleus channel. This will be used to segment the nucleus.",
727
+ "cell_channel": "The channel to use for the cell. If None, the cell will not be segmented.",
728
+ "cell_background": "The background intensity for the cell channel. This will be used to remove background noise.",
729
+ "cell_Signal_to_noise": "The signal-to-noise ratio for the cell channel. This will be used to determine the range of intensities to normalize images to for cell segmentation.",
730
+ "cell_CP_prob": "The cellpose probability threshold for the cell channel. This will be used to segment the cell.",
731
+ "pathogen_channel": "The channel to use for the pathogen. If None, the pathogen will not be segmented.",
732
+ "pathogen_background": "The background intensity for the pathogen channel. This will be used to remove background noise.",
733
+ "pathogen_Signal_to_noise": "The signal-to-noise ratio for the pathogen channel. This will be used to determine the range of intensities to normalize images to for pathogen segmentation.",
734
+ "pathogen_CP_prob": "The cellpose probability threshold for the pathogen channel. This will be used to segment the pathogen.",
735
+ "preprocess": "Whether to preprocess the images before segmentation. This includes background removal and normalization. Set to False only if this step has already been done.",
736
+ "masks": "Whether to generate masks for the segmented objects. If True, masks will be generated for the nucleus, cell, and pathogen.",
737
+ "examples_to_plot": "The number of images to plot for each segmented object. This will be used to visually inspect the segmentation results and normalization .",
738
+ "randomize": "Whether to randomize the order of the images before processing. Recommended to avoid bias in the segmentation.",
739
+ "batch_size": "The batch size to use for processing the images. This will determine how many images are processed at once. Images are normalized and segmented in batches. Lower if application runs out of RAM or VRAM.",
740
+ "timelapse": "Whether to process the images as a timelapse.",
741
+ "timelapse_displacement": "The displacement between frames in the timelapse. This will be used to align the frames before processing.",
742
+ "timelapse_memory": "The number of frames to in tandem objects must be present in to be considered the same object in the timelapse.",
743
+ "timelapse_frame_limits": "The frame limits to use for the timelapse. This will determine which frames are processed. For example, [5,20] will process frames 5 to 20.",
744
+ "timelapse_remove_transient": "Whether to remove transient objects in the timelapse. Transient objects are present in fewer than all frames.",
745
+ "timelapse_mode": "The mode to use for processing the timelapse. 'trackpy' uses the trackpy library for tracking objects, while 'btrack' uses the btrack library.",
746
+ "timelapse_objects": "The objects to track in the timelapse (cell, nucleus or pathogen). This will determine which objects are tracked over time. If None, all objects will be tracked.",
747
+ "fps": "Frames per second of the automatically generated timelapse movies.",
748
+ "remove_background": "Whether to remove background noise from the images. This will help improve the quality of the segmentation.",
749
+ "lower_quantile": "The lower quantile to use for normalizing the images. This will be used to determine the range of intensities to normalize images to.",
750
+ "merge_pathogens": "Whether to merge pathogen objects that share more than 75% of their perimiter.",
751
+ "normalize_plots": "Whether to normalize the plots.",
752
+ "all_to_mip": "Whether to convert all images to maximum intensity projections before processing.",
753
+ "pick_slice": "Whether to pick a single slice from the z-stack images. If False, the maximum intensity projection will be used.",
754
+ "skip_mode": "The mode to use for skipping images. This will determine how to handle images that cannot be processed.",
755
+ "save": "Whether to save the results to disk.",
756
+ "plot": "Whether to plot the results.",
757
+ "workers": "The number of workers to use for processing the images. This will determine how many images are processed in parallel. Increase to speed up processing.",
758
+ "verbose": "Whether to print verbose output during processing.",
759
+ "input_folder": "Path to the folder containing the images.",
760
+ "cell_mask_dim": "The dimension of the array the cell mask is saved in.",
761
+ "cell_min_size": "The minimum size of cell objects in pixels2.",
762
+ "cytoplasm_min_size": "The minimum size of cytoplasm objects in pixels2.",
763
+ "nucleus_mask_dim": "The dimension of the array the nucleus mask is saved in.",
764
+ "nucleus_min_size": "The minimum size of nucleus objects in pixels2.",
765
+ "pathogen_mask_dim": "The dimension of the array the pathogen mask is saved in.",
766
+ "pathogen_min_size": "The minimum size of pathogen objects in pixels2.",
767
+ "save_png": "Whether to save the segmented objects as PNG images.",
768
+ "crop_mode": "The mode to use for cropping the images. This will determine which objects are cropped from the images (cell, nucleus, pathogen, cytoplasm).",
769
+ "use_bounding_box": "Whether to use the bounding box of the objects for cropping. If False, only the object itself will be cropped.",
770
+ "png_size": "The size of the PNG images to save. This will determine the size of the saved images.",
771
+ "normalize": "The percentiles to use for normalizing the images. This will be used to determine the range of intensities to normalize images to., if None, no normalization is done.",
772
+ "png_dims": "The dimensions of the PNG images to save. This will determine the dimensions of the saved images. Maximum of 3 dimensions e.g. [1,2,3].",
773
+ "normalize_by": "Whether to normalize the images by field of view (fov) or by PNG image (png).",
774
+ "save_measurements": "Whether to save the measurements to disk.",
775
+ "representative_images": "Whether to save representative images of the segmented objects (Not working yet).",
776
+ "plot": "Whether to plot results.",
777
+ "plot_filtration": "Whether to plot the filtration steps.",
778
+ "include_uninfected": "Whether to include uninfected cells in the analysis.",
779
+ "dialate_pngs": "Whether to dialate the PNG images before saving.",
780
+ "dialate_png_ratios": "The ratios to use for dialating the PNG images. This will determine the amount of dialation applied to the images before cropping.",
781
+ "timelapse_objects": "The objects to track in the timelapse (cell, nucleus or pathogen). This will determine which objects are tracked over time. If None, all objects will be tracked.",
782
+ "max_workers": "The number of workers to use for processing the images. This will determine how many images are processed in parallel. Increase to speed up processing.",
783
+ "cells: ": "The cell types to include in the analysis.",
784
+ "cell_loc": "The locations of the cell types in the images.",
785
+ "pathogens": "The pathogen types to include in the analysis.",
786
+ "pathogen_loc": "The locations of the pathogen types in the images.",
787
+ "treatments": "The treatments to include in the analysis.",
788
+ "treatment_loc": "The locations of the treatments in the images.",
789
+ "channel_of_interest": "The channel of interest to use for the analysis.",
790
+ "compartments": "The compartments to measure in the images.",
791
+ "measurement": "The measurement to use for the analysis.",
792
+ "nr_imgs": "The number of images to plot.",
793
+ "um_per_pixel": "The micrometers per pixel for the images.",
794
+ }
795
+
704
796
  for key, (var_type, options, default_value) in variables.items():
705
797
  label, widget, var = create_input_field(scrollable_frame.scrollable_frame, key, row, var_type, options, default_value)
706
798
  vars_dict[key] = (label, widget, var) # Store the label, widget, and variable
799
+
800
+ # Add tooltip to the label if it exists in the tooltips dictionary
801
+ if key in tooltips:
802
+ ToolTip(label, tooltips[key])
803
+
707
804
  row += 1
708
805
  return vars_dict
806
+
807
+
709
808
 
710
809
  class TextRedirector(object):
711
810
  def __init__(self, widget, queue):
@@ -735,7 +834,7 @@ def create_dark_mode(root, style, console_output):
735
834
  style.map('TCombobox', fieldbackground=[('readonly', input_bg)], selectbackground=[('readonly', input_bg)], foreground=[('readonly', dark_text)])
736
835
 
737
836
  if console_output != None:
738
- console_output.config(bg=dark_bg, fg=light_text, insertbackground=light_text) #, font=("Open Sans", 12)
837
+ console_output.config(bg=dark_bg, fg=light_text, insertbackground=light_text) #, font=("Arial", 12)
739
838
  root.configure(bg=dark_bg)
740
839
 
741
840
  def set_dark_style(style):