spacr 0.1.81__tar.gz → 0.2.0__tar.gz

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.
Files changed (77) hide show
  1. {spacr-0.1.81/spacr.egg-info → spacr-0.2.0}/PKG-INFO +1 -1
  2. {spacr-0.1.81 → spacr-0.2.0}/setup.py +2 -2
  3. {spacr-0.1.81 → spacr-0.2.0}/spacr/__init__.py +6 -2
  4. {spacr-0.1.81 → spacr-0.2.0}/spacr/app_annotate.py +6 -5
  5. {spacr-0.1.81 → spacr-0.2.0}/spacr/app_make_masks.py +8 -15
  6. {spacr-0.1.81 → spacr-0.2.0}/spacr/core.py +1 -1
  7. spacr-0.2.0/spacr/gui.py +157 -0
  8. {spacr-0.1.81 → spacr-0.2.0}/spacr/gui_core.py +113 -67
  9. {spacr-0.1.81 → spacr-0.2.0}/spacr/gui_elements.py +233 -87
  10. {spacr-0.1.81 → spacr-0.2.0}/spacr/gui_utils.py +3 -3
  11. spacr-0.2.0/spacr/resources/icons/abort.png +0 -0
  12. spacr-0.2.0/spacr/resources/icons/annotate.png +0 -0
  13. spacr-0.2.0/spacr/resources/icons/cellpose_masks.png +0 -0
  14. spacr-0.2.0/spacr/resources/icons/classify.png +0 -0
  15. spacr-0.2.0/spacr/resources/icons/default.png +0 -0
  16. spacr-0.2.0/spacr/resources/icons/download.png +0 -0
  17. spacr-0.2.0/spacr/resources/icons/logo_spacr.png +0 -0
  18. spacr-0.2.0/spacr/resources/icons/make_masks.png +0 -0
  19. spacr-0.2.0/spacr/resources/icons/map_barcodes.png +0 -0
  20. spacr-0.2.0/spacr/resources/icons/mask.png +0 -0
  21. spacr-0.2.0/spacr/resources/icons/measure.png +0 -0
  22. spacr-0.2.0/spacr/resources/icons/regression.png +0 -0
  23. spacr-0.2.0/spacr/resources/icons/run.png +0 -0
  24. spacr-0.2.0/spacr/resources/icons/sequencing.png +0 -0
  25. spacr-0.2.0/spacr/resources/icons/settings.png +0 -0
  26. spacr-0.2.0/spacr/resources/icons/train_cellpose.png +0 -0
  27. spacr-0.2.0/spacr/resources/icons/umap.png +0 -0
  28. {spacr-0.1.81 → spacr-0.2.0}/spacr/settings.py +12 -12
  29. {spacr-0.1.81 → spacr-0.2.0/spacr.egg-info}/PKG-INFO +1 -1
  30. {spacr-0.1.81 → spacr-0.2.0}/spacr.egg-info/SOURCES.txt +20 -3
  31. spacr-0.1.81/spacr/gui.py +0 -176
  32. {spacr-0.1.81 → spacr-0.2.0}/LICENSE +0 -0
  33. {spacr-0.1.81 → spacr-0.2.0}/MANIFEST.in +0 -0
  34. {spacr-0.1.81 → spacr-0.2.0}/README.rst +0 -0
  35. {spacr-0.1.81 → spacr-0.2.0}/setup.cfg +0 -0
  36. {spacr-0.1.81 → spacr-0.2.0}/spacr/__main__.py +0 -0
  37. {spacr-0.1.81 → spacr-0.2.0}/spacr/app_classify.py +0 -0
  38. {spacr-0.1.81 → spacr-0.2.0}/spacr/app_mask.py +0 -0
  39. {spacr-0.1.81 → spacr-0.2.0}/spacr/app_measure.py +0 -0
  40. {spacr-0.1.81 → spacr-0.2.0}/spacr/app_sequencing.py +0 -0
  41. {spacr-0.1.81 → spacr-0.2.0}/spacr/app_umap.py +0 -0
  42. {spacr-0.1.81 → spacr-0.2.0}/spacr/chris.py +0 -0
  43. {spacr-0.1.81 → spacr-0.2.0}/spacr/deep_spacr.py +0 -0
  44. {spacr-0.1.81 → spacr-0.2.0}/spacr/graph_learning.py +0 -0
  45. {spacr-0.1.81 → spacr-0.2.0}/spacr/io.py +0 -0
  46. {spacr-0.1.81 → spacr-0.2.0}/spacr/logger.py +0 -0
  47. {spacr-0.1.81 → spacr-0.2.0}/spacr/measure.py +0 -0
  48. {spacr-0.1.81 → spacr-0.2.0}/spacr/plot.py +0 -0
  49. {spacr-0.1.81/spacr → spacr-0.2.0/spacr/resources}/models/cp/toxo_plaque_cyto_e25000_X1120_Y1120.CP_model +0 -0
  50. {spacr-0.1.81/spacr → spacr-0.2.0/spacr/resources}/models/cp/toxo_plaque_cyto_e25000_X1120_Y1120.CP_model_settings.csv +0 -0
  51. {spacr-0.1.81/spacr → spacr-0.2.0/spacr/resources}/models/cp/toxo_pv_lumen.CP_model +0 -0
  52. {spacr-0.1.81 → spacr-0.2.0}/spacr/sequencing.py +0 -0
  53. {spacr-0.1.81 → spacr-0.2.0}/spacr/sim.py +0 -0
  54. {spacr-0.1.81 → spacr-0.2.0}/spacr/sim_app.py +0 -0
  55. {spacr-0.1.81 → spacr-0.2.0}/spacr/timelapse.py +0 -0
  56. {spacr-0.1.81 → spacr-0.2.0}/spacr/utils.py +0 -0
  57. {spacr-0.1.81 → spacr-0.2.0}/spacr/version.py +0 -0
  58. {spacr-0.1.81 → spacr-0.2.0}/spacr.egg-info/dependency_links.txt +0 -0
  59. {spacr-0.1.81 → spacr-0.2.0}/spacr.egg-info/entry_points.txt +0 -0
  60. {spacr-0.1.81 → spacr-0.2.0}/spacr.egg-info/requires.txt +0 -0
  61. {spacr-0.1.81 → spacr-0.2.0}/spacr.egg-info/top_level.txt +0 -0
  62. {spacr-0.1.81 → spacr-0.2.0}/tests/test_annotate_app.py +0 -0
  63. {spacr-0.1.81 → spacr-0.2.0}/tests/test_core.py +0 -0
  64. {spacr-0.1.81 → spacr-0.2.0}/tests/test_gui_classify_app.py +0 -0
  65. {spacr-0.1.81 → spacr-0.2.0}/tests/test_gui_mask_app.py +0 -0
  66. {spacr-0.1.81 → spacr-0.2.0}/tests/test_gui_measure_app.py +0 -0
  67. {spacr-0.1.81 → spacr-0.2.0}/tests/test_gui_sim_app.py +0 -0
  68. {spacr-0.1.81 → spacr-0.2.0}/tests/test_gui_utils.py +0 -0
  69. {spacr-0.1.81 → spacr-0.2.0}/tests/test_io.py +0 -0
  70. {spacr-0.1.81 → spacr-0.2.0}/tests/test_mask_app.py +0 -0
  71. {spacr-0.1.81 → spacr-0.2.0}/tests/test_measure.py +0 -0
  72. {spacr-0.1.81 → spacr-0.2.0}/tests/test_plot.py +0 -0
  73. {spacr-0.1.81 → spacr-0.2.0}/tests/test_sim.py +0 -0
  74. {spacr-0.1.81 → spacr-0.2.0}/tests/test_timelapse.py +0 -0
  75. {spacr-0.1.81 → spacr-0.2.0}/tests/test_train.py +0 -0
  76. {spacr-0.1.81 → spacr-0.2.0}/tests/test_umap.py +0 -0
  77. {spacr-0.1.81 → spacr-0.2.0}/tests/test_utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: spacr
3
- Version: 0.1.81
3
+ Version: 0.2.0
4
4
  Summary: Spatial phenotype analysis of crisp screens (SpaCr)
5
5
  Home-page: https://github.com/EinarOlafsson/spacr
6
6
  Author: Einar Birnir Olafsson
@@ -50,7 +50,7 @@ dependencies = [
50
50
 
51
51
  setup(
52
52
  name="spacr",
53
- version="0.1.81",
53
+ version="0.2.0",
54
54
  author="Einar Birnir Olafsson",
55
55
  author_email="olafsson@med.umich.com",
56
56
  description="Spatial phenotype analysis of crisp screens (SpaCr)",
@@ -58,7 +58,7 @@ setup(
58
58
  url="https://github.com/EinarOlafsson/spacr",
59
59
  packages=find_packages(exclude=["tests.*", "tests"]),
60
60
  include_package_data=True,
61
- package_data={'spacr': ['models/cp/*'],},
61
+ package_data={'spacr': ['resources/models/cp/*', 'resources/icons/*'],},
62
62
  install_requires=dependencies,
63
63
  entry_points={
64
64
  'console_scripts': [
@@ -16,8 +16,8 @@ from . import app_annotate
16
16
  from . import gui_utils
17
17
  from . import gui_elements
18
18
  from . import gui_core
19
- from . import gui_run
20
- from . import gui_wrappers
19
+ from . import gui
20
+ from . import gui
21
21
  from . import app_make_masks
22
22
  from . import app_mask
23
23
  from . import app_measure
@@ -40,6 +40,10 @@ __all__ = [
40
40
  "deep_spacr",
41
41
  "app_annotate",
42
42
  "gui_utils",
43
+ "gui_elements",
44
+ "gui_core",
45
+ "gui",
46
+ "gui",
43
47
  "app_make_masks",
44
48
  "app_mask",
45
49
  "app_measure",
@@ -1,15 +1,16 @@
1
1
  import tkinter as tk
2
+ from tkinter import ttk
2
3
  from .gui import MainApp
4
+ from .gui_elements import set_dark_style
3
5
 
4
6
  def initiate_annotation_app(parent_frame):
5
7
  from .gui_utils import generate_annotate_fields, annotate_app
6
8
  # Set up the settings window
7
9
  settings_window = tk.Toplevel(parent_frame)
8
10
  settings_window.title("Annotation Settings")
9
- settings_window.configure(bg='black') # Set the background color to black
10
-
11
- # Use the existing function to create the settings UI
12
- settings_frame = tk.Frame(settings_window, bg='black') # Set the background color to black
11
+ style_out = set_dark_style(ttk.Style())
12
+ settings_window.configure(bg=style_out['bg_color'])
13
+ settings_frame = tk.Frame(settings_window, bg=style_out['bg_color'])
13
14
  settings_frame.pack(fill=tk.BOTH, expand=True)
14
15
  vars_dict = generate_annotate_fields(settings_frame)
15
16
 
@@ -41,7 +42,7 @@ def initiate_annotation_app(parent_frame):
41
42
  settings_window.destroy()
42
43
  annotate_app(parent_frame, settings)
43
44
 
44
- start_button = tk.Button(settings_window, text="Start Annotation", command=start_annotation_app, bg='black', fg='white')
45
+ start_button = tk.Button(settings_window, text="Start Annotation", command=start_annotation_app, bg=style_out['bg_color'], fg=style_out['bg_color'])
45
46
  start_button.pack(pady=10)
46
47
 
47
48
  def start_annotate_app():
@@ -3,26 +3,22 @@ from tkinter import ttk
3
3
  from .gui import MainApp
4
4
 
5
5
  def initiate_make_mask_app(parent_frame):
6
- from .gui_elements import modify_masks
7
- # Set up the settings window
6
+ from .gui_elements import ModifyMaskApp, set_dark_style
8
7
  settings_window = tk.Toplevel(parent_frame)
9
8
  settings_window.title("Make Masks Settings")
10
- settings_window.configure(bg='black') # Set the background color to black
11
-
12
- # Use the existing function to create the settings UI
13
- settings_frame = tk.Frame(settings_window, bg='black') # Set the background color to black
9
+ style_out = set_dark_style(ttk.Style())
10
+ settings_window.configure(bg=style_out['bg_color'])
11
+ settings_frame = tk.Frame(settings_window, bg=style_out['bg_color'])
14
12
  settings_frame.pack(fill=tk.BOTH, expand=True)
15
13
 
16
14
  vars_dict = {
17
15
  'folder_path': ttk.Entry(settings_frame),
18
16
  'scale_factor': ttk.Entry(settings_frame)
19
17
  }
20
-
21
- # Arrange input fields and labels
22
18
  row = 0
23
19
  for name, entry in vars_dict.items():
24
20
  ttk.Label(settings_frame, text=f"{name.replace('_', ' ').capitalize()}:",
25
- background="black", foreground="white").grid(row=row, column=0)
21
+ background=style_out['bg_color'], foreground=style_out['fg_color']).grid(row=row, column=0)
26
22
  entry.grid(row=row, column=1)
27
23
  row += 1
28
24
 
@@ -32,15 +28,12 @@ def initiate_make_mask_app(parent_frame):
32
28
  try:
33
29
  scale_factor = float(vars_dict['scale_factor'].get())
34
30
  except ValueError:
35
- scale_factor = None # Handle invalid input gracefully
36
-
37
- # Convert empty strings to None
31
+ scale_factor = None
38
32
  folder_path = folder_path if folder_path != '' else None
39
-
40
33
  settings_window.destroy()
41
- modify_masks(parent_frame, folder_path, scale_factor)
34
+ ModifyMaskApp(parent_frame, folder_path, scale_factor)
42
35
 
43
- run_button = tk.Button(settings_window, text="Start Make Masks", command=start_make_mask_app, bg='black', fg='white')
36
+ run_button = tk.Button(settings_window, text="Start Make Masks", command=start_make_mask_app, bg=style_out['bg_color'], fg=style_out['fg_color'])
44
37
  run_button.pack(pady=10)
45
38
 
46
39
  def start_make_mask_app():
@@ -1738,7 +1738,7 @@ def preprocess_generate_masks(src, settings={}):
1738
1738
  if os.path.exists(os.path.join(src,'measurements')):
1739
1739
  _pivot_counts_table(db_path=os.path.join(src,'measurements', 'measurements.db'))
1740
1740
 
1741
- #Concatinate stack with masks
1741
+ #Concatenate stack with masks
1742
1742
  _load_and_concatenate_arrays(src, settings['channels'], settings['cell_channel'], settings['nucleus_channel'], settings['pathogen_channel'])
1743
1743
 
1744
1744
  if settings['plot']:
@@ -0,0 +1,157 @@
1
+ import tkinter as tk
2
+ from tkinter import ttk
3
+ from PIL import Image, ImageTk, ImageDraw
4
+ import os
5
+ from multiprocessing import set_start_method
6
+ from .gui_elements import spacrButton, create_menu_bar, set_dark_style
7
+ from .gui_core import initiate_root
8
+
9
+ class MainApp(tk.Tk):
10
+ def __init__(self, default_app=None):
11
+ super().__init__()
12
+ width = self.winfo_screenwidth()
13
+ height = self.winfo_screenheight()
14
+ self.geometry(f"{width}x{height}")
15
+ self.title("SpaCr GUI Collection")
16
+ self.configure(bg='#333333') # Set window background to dark gray
17
+
18
+ # Initialize style and apply dark style to the main window
19
+ style = ttk.Style()
20
+ self.color_settings = set_dark_style(style, parent_frame=self)
21
+ self.main_buttons = {} # Initialize main_buttons dictionary here
22
+ self.additional_buttons = {} # Initialize additional_buttons dictionary here
23
+
24
+ self.main_gui_apps = {
25
+ "Mask": (lambda frame: initiate_root(frame, 'mask'), "Generate cellpose masks for cells, nuclei and pathogen images."),
26
+ "Measure": (lambda frame: initiate_root(frame, 'measure'), "Measure single object intensity and morphological feature. Crop and save single object image"),
27
+ "Annotate": (lambda frame: initiate_root(frame, 'annotate'), "Annotation single object images on a grid. Annotations are saved to database."),
28
+ "Make Masks": (lambda frame: initiate_root(frame, 'make_masks'), "Adjust pre-existing Cellpose models to your specific dataset for improved performance"),
29
+ "Classify": (lambda frame: initiate_root(frame, 'classify'), "Train Torch Convolutional Neural Networks (CNNs) or Transformers to classify single object images."),
30
+ }
31
+
32
+ self.additional_gui_apps = {
33
+ "Sequencing": (lambda frame: initiate_root(frame, 'sequencing'), "Analyze sequencing data."),
34
+ "Umap": (lambda frame: initiate_root(frame, 'umap'), "Generate UMAP embeddings with datapoints represented as images."),
35
+ "Train Cellpose": (lambda frame: initiate_root(frame, 'train_cellpose'), "Train custom Cellpose models."),
36
+ "ML Analyze": (lambda frame: initiate_root(frame, 'ml_analyze'), "Machine learning analysis of data."),
37
+ "Cellpose Masks": (lambda frame: initiate_root(frame, 'cellpose_masks'), "Generate Cellpose masks."),
38
+ "Cellpose All": (lambda frame: initiate_root(frame, 'cellpose_all'), "Run Cellpose on all images."),
39
+ "Map Barcodes": (lambda frame: initiate_root(frame, 'map_barcodes'), "Map barcodes to data."),
40
+ "Regression": (lambda frame: initiate_root(frame, 'regression'), "Perform regression analysis."),
41
+ "Recruitment": (lambda frame: initiate_root(frame, 'recruitment'), "Analyze recruitment data.")
42
+ }
43
+
44
+ self.selected_app = tk.StringVar()
45
+ self.create_widgets()
46
+
47
+ if default_app in self.main_gui_apps:
48
+ self.load_app(default_app, self.main_gui_apps[default_app][0])
49
+ elif default_app in self.additional_gui_apps:
50
+ self.load_app(default_app, self.additional_gui_apps[default_app][0])
51
+
52
+ def create_widgets(self):
53
+ # Create the menu bar
54
+ create_menu_bar(self)
55
+
56
+ # Create a canvas to hold the selected app and other elements
57
+ self.canvas = tk.Canvas(self, highlightthickness=0)
58
+ self.canvas.grid(row=0, column=0, sticky="nsew")
59
+ self.grid_rowconfigure(0, weight=1)
60
+ self.grid_columnconfigure(0, weight=1)
61
+
62
+ # Create a frame inside the canvas to hold the main content
63
+ self.content_frame = tk.Frame(self.canvas)
64
+ self.content_frame.grid(row=0, column=0, sticky="nsew")
65
+
66
+ # Center the content frame within the canvas
67
+ self.canvas.create_window((self.winfo_screenwidth() // 2, self.winfo_screenheight() // 2), window=self.content_frame, anchor="center")
68
+
69
+ # Apply dark style to canvas and content_frame
70
+ set_dark_style(ttk.Style(), containers=[self.canvas, self.content_frame])
71
+
72
+ # Create startup screen with buttons for each main GUI app and drop-down for additional apps
73
+ self.create_startup_screen()
74
+
75
+ def create_startup_screen(self):
76
+ self.clear_frame(self.content_frame)
77
+
78
+ # Create frames for the grids
79
+ main_buttons_frame = tk.Frame(self.content_frame)
80
+ main_buttons_frame.pack(pady=10)
81
+ set_dark_style(ttk.Style(), containers=[main_buttons_frame])
82
+
83
+ additional_buttons_frame = tk.Frame(self.content_frame)
84
+ additional_buttons_frame.pack(pady=10)
85
+ set_dark_style(ttk.Style(), containers=[additional_buttons_frame])
86
+
87
+ # Create a frame for the description below the icon grids
88
+ description_frame = tk.Frame(self.content_frame, height=70) # Increased height to 70
89
+ description_frame.pack(fill=tk.X, pady=10)
90
+ description_frame.pack_propagate(False) # Prevent the frame from resizing based on its content
91
+ set_dark_style(ttk.Style(), containers=[description_frame])
92
+
93
+ # Use a Label widget to display descriptions
94
+ self.description_label = tk.Label(description_frame, text="", wraplength=800, justify="center", font=('Helvetica', 12), fg=self.color_settings['fg_color'], bg=self.color_settings['bg_color'])
95
+ self.description_label.pack(fill=tk.BOTH, pady=10)
96
+
97
+ # Load the logo image and place it in the main apps row
98
+ logo_button = spacrButton(main_buttons_frame, text="SpaCr", command=lambda: self.load_app("logo_spacr", initiate_root), icon_name="logo_spacr", size=100, show_text=False)
99
+ logo_button.grid(row=0, column=0, padx=5, pady=5)
100
+ self.main_buttons[logo_button] = "SpaCr: An advanced application suite for cellpose masks, measurements, annotations, and more."
101
+
102
+ # Create icon buttons for the main apps
103
+ for i, (app_name, app_data) in enumerate(self.main_gui_apps.items()):
104
+ app_func, app_desc = app_data
105
+ button = spacrButton(main_buttons_frame, text=app_name, command=lambda app_name=app_name, app_func=app_func: self.load_app(app_name, app_func), icon_name=app_name.lower(), size=100, show_text=False)
106
+ button.grid(row=0, column=i + 1, padx=5, pady=5)
107
+ self.main_buttons[button] = app_desc
108
+
109
+ # Create icon buttons for the additional apps
110
+ for i, (app_name, app_data) in enumerate(self.additional_gui_apps.items()):
111
+ app_func, app_desc = app_data
112
+ button = spacrButton(additional_buttons_frame, text=app_name, command=lambda app_name=app_name, app_func=app_func: self.load_app(app_name, app_func), icon_name=app_name.lower(), size=75, show_text=False)
113
+ button.grid(row=0, column=i, padx=5, pady=5) # Ensure all icons are in a single row
114
+ self.additional_buttons[button] = app_desc
115
+
116
+ # Update description initially
117
+ self.update_description()
118
+
119
+ def update_description(self):
120
+ # Check all buttons and update description if any has the active color
121
+ for button, desc in {**self.main_buttons, **self.additional_buttons}.items():
122
+ if button.canvas.itemcget(button.button_bg, "fill") == self.color_settings['active_color']:
123
+ self.show_description(desc)
124
+ return
125
+ self.clear_description()
126
+
127
+ def show_description(self, description):
128
+ if self.description_label.winfo_exists():
129
+ self.description_label.config(text=description)
130
+ self.description_label.update_idletasks() # Ensure the label updates immediately
131
+
132
+ def clear_description(self):
133
+ if self.description_label.winfo_exists():
134
+ self.description_label.config(text="")
135
+ self.description_label.update_idletasks() # Ensure the label updates immediately
136
+
137
+ def load_app(self, app_name, app_func):
138
+ # Clear the current content frame
139
+ self.clear_frame(self.canvas)
140
+
141
+ # Initialize the selected app
142
+ app_frame = tk.Frame(self.canvas)
143
+ app_frame.pack(fill=tk.BOTH, expand=True)
144
+ set_dark_style(ttk.Style(), containers=[app_frame])
145
+ app_func(app_frame)
146
+
147
+ def clear_frame(self, frame):
148
+ for widget in frame.winfo_children():
149
+ widget.destroy()
150
+
151
+ def gui_app():
152
+ app = MainApp()
153
+ app.mainloop()
154
+
155
+ if __name__ == "__main__":
156
+ set_start_method('spawn', force=True)
157
+ gui_app()
@@ -17,7 +17,7 @@ except AttributeError:
17
17
  pass
18
18
 
19
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
20
+ from .gui_elements import spacrButton, spacrLabel, spacrFrame, spacrDropdownMenu ,set_dark_style, set_default_font
21
21
 
22
22
  # Define global variables
23
23
  q = None
@@ -231,25 +231,43 @@ def import_settings(settings_type='mask'):
231
231
  vars_dict = hide_all_settings(vars_dict, categories=None)
232
232
 
233
233
  def convert_settings_dict_for_gui(settings):
234
+ from torchvision import models as torch_models
235
+ torchvision_models = [name for name, obj in torch_models.__dict__.items() if callable(obj)]
236
+ chans = ['0', '1', '2', '3', '4', '5', '6', '7', '8', None]
237
+ chans_v2 = [0, 1, 2, 3, None]
234
238
  variables = {}
235
239
  special_cases = {
236
240
  'metadata_type': ('combo', ['cellvoyager', 'cq1', 'nikon', 'zeis', 'custom'], 'cellvoyager'),
237
241
  'channels': ('combo', ['[0,1,2,3]', '[0,1,2]', '[0,1]', '[0]'], '[0,1,2,3]'),
238
- 'cell_mask_dim': ('combo', ['0', '1', '2', '3', '4', '5', '6', '7', '8', None], None),
239
- 'nucleus_mask_dim': ('combo', ['0', '1', '2', '3', '4', '5', '6', '7', '8', None], None),
240
- 'pathogen_mask_dim': ('combo', ['0', '1', '2', '3', '4', '5', '6', '7', '8', None], None),
241
- #'crop_mode': ('combo', ['cell', 'nucleus', 'pathogen', '[cell, nucleus, pathogen]', '[cell,nucleus, pathogen]'], ['cell']),
242
+ 'channel_dims': ('combo', ['[0,1,2,3]', '[0,1,2]', '[0,1]', '[0]'], '[0,1,2,3]'),
243
+ 'cell_mask_dim': ('combo', chans, None),
244
+ 'cell_chann_dim': ('combo', chans, None),
245
+ 'nucleus_mask_dim': ('combo', chans, None),
246
+ 'nucleus_chann_dim': ('combo', chans, None),
247
+ 'pathogen_mask_dim': ('combo', chans, None),
248
+ 'pathogen_chann_dim': ('combo', chans, None),
249
+ 'crop_mode': ('combo', ['cell', 'nucleus', 'pathogen', '[cell, nucleus, pathogen]', '[cell,nucleus, pathogen]'], ['cell']),
242
250
  'magnification': ('combo', [20, 40, 60], 20),
243
- 'nucleus_channel': ('combo', [0, 1, 2, 3, None], None),
244
- 'cell_channel': ('combo', [0, 1, 2, 3, None], None),
245
- 'pathogen_channel': ('combo', [0, 1, 2, 3, None], None),
251
+ 'nucleus_channel': ('combo', chans_v2, None),
252
+ 'cell_channel': ('combo', chans_v2, None),
253
+ 'channel_of_interest': ('combo', chans_v2, None),
254
+ 'pathogen_channel': ('combo', chans_v2, None),
246
255
  'timelapse_mode': ('combo', ['trackpy', 'btrack'], 'trackpy'),
256
+ 'train_mode': ('combo', ['erm', 'irm'], 'erm'),
257
+ 'clustering': ('combo', ['dbscan', 'kmean'], 'dbscan'),
258
+ 'reduction_method': ('combo', ['umap', 'tsne'], 'umap'),
259
+ 'model_name': ('combo', ['cyto', 'cyto_2', 'cyto_3', 'nuclei'], 'cyto'),
260
+ 'regression_type': ('combo', ['ols','gls','wls','rlm','glm','mixed','quantile','logit','probit','poisson','lasso','ridge'], 'ols'),
247
261
  'timelapse_objects': ('combo', ['cell', 'nucleus', 'pathogen', 'cytoplasm', None], None),
248
- 'model_type': ('combo', ['resnet50', 'other_model'], 'resnet50'),
262
+ 'model_type': ('combo', torchvision_models, 'resnet50'),
249
263
  'optimizer_type': ('combo', ['adamw', 'adam'], 'adamw'),
250
264
  'schedule': ('combo', ['reduce_lr_on_plateau', 'step_lr'], 'reduce_lr_on_plateau'),
251
265
  'loss_type': ('combo', ['focal_loss', 'binary_cross_entropy_with_logits'], 'focal_loss'),
252
266
  'normalize_by': ('combo', ['fov', 'png'], 'png'),
267
+ 'agg_type': ('combo', ['mean', 'median'], 'mean'),
268
+ 'grouping': ('combo', ['mean', 'median'], 'mean'),
269
+ 'min_max': ('combo', ['allq', 'all'], 'allq'),
270
+ 'transform': ('combo', ['log', 'sqrt', 'square', None], None)
253
271
  }
254
272
 
255
273
  for key, value in settings.items():
@@ -271,17 +289,16 @@ def convert_settings_dict_for_gui(settings):
271
289
 
272
290
  def setup_settings_panel(vertical_container, settings_type='mask', window_dimensions=[500, 1000]):
273
291
  global vars_dict, scrollable_frame
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
292
+ 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
275
293
 
276
- width = (window_dimensions[0])//6
294
+ width = (window_dimensions[0]) // 6
277
295
  height = window_dimensions[1]
278
296
 
279
- # Settings Frame
280
- settings_frame = tk.Frame(vertical_container, bg='black', height=height, width=width)
297
+ settings_frame = tk.Frame(vertical_container)
281
298
  vertical_container.add(settings_frame, stretch="always")
282
- settings_label = spacrLabel(settings_frame, text="Settings", background="black", foreground="white", anchor='center', justify='center', align="center")
299
+ settings_label = spacrLabel(settings_frame, text="Settings", anchor='center', justify='center', align="center")
283
300
  settings_label.grid(row=0, column=0, pady=10, padx=10)
284
- scrollable_frame = spacrFrame(settings_frame, bg='black', width=width)
301
+ scrollable_frame = spacrFrame(settings_frame)
285
302
  scrollable_frame.grid(row=1, column=0, sticky="nsew")
286
303
  settings_frame.grid_rowconfigure(1, weight=1)
287
304
  settings_frame.grid_columnconfigure(0, weight=1)
@@ -310,24 +327,18 @@ def setup_settings_panel(vertical_container, settings_type='mask', window_dimens
310
327
  settings = get_perform_regression_default_settings(settings={})
311
328
  elif settings_type == 'recruitment':
312
329
  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_
325
330
  else:
326
331
  raise ValueError(f"Invalid settings type: {settings_type}")
327
332
 
328
-
329
333
  variables = convert_settings_dict_for_gui(settings)
330
334
  vars_dict = generate_fields(variables, scrollable_frame)
335
+
336
+ containers = [settings_frame]
337
+ widgets = [settings_label, scrollable_frame]
338
+
339
+ style = ttk.Style(vertical_container)
340
+ _ = set_dark_style(style, containers=containers, widgets=widgets)
341
+
331
342
  print("Settings panel setup complete")
332
343
  return scrollable_frame, vars_dict
333
344
 
@@ -335,45 +346,58 @@ def setup_plot_section(vertical_container):
335
346
  global canvas, canvas_widget
336
347
  plot_frame = tk.PanedWindow(vertical_container, orient=tk.VERTICAL)
337
348
  vertical_container.add(plot_frame, stretch="always")
338
- figure = Figure(figsize=(30, 4), dpi=100, facecolor='black')
349
+ figure = Figure(figsize=(30, 4), dpi=100)
339
350
  plot = figure.add_subplot(111)
340
351
  plot.plot([], []) # This creates an empty plot.
341
352
  plot.axis('off')
342
353
  canvas = FigureCanvasTkAgg(figure, master=plot_frame)
343
- canvas.get_tk_widget().configure(cursor='arrow', background='black', highlightthickness=0)
354
+ canvas.get_tk_widget().configure(cursor='arrow', highlightthickness=0)
344
355
  canvas_widget = canvas.get_tk_widget()
345
356
  plot_frame.add(canvas_widget, stretch="always")
346
357
  canvas.draw()
347
358
  canvas.figure = figure
359
+ style_out = set_dark_style(ttk.Style())
360
+
361
+ figure.patch.set_facecolor(style_out['bg_color'])
362
+ plot.set_facecolor(style_out['bg_color'])
363
+ containers = [plot_frame]
364
+ widgets = [canvas_widget]
365
+ style = ttk.Style(vertical_container)
366
+ _ = set_dark_style(style, containers=containers, widgets=widgets)
348
367
  return canvas, canvas_widget
349
368
 
350
369
  def setup_console(vertical_container):
351
370
  global console_output
352
- print("Setting up console frame")
353
- console_frame = tk.Frame(vertical_container, bg='black')
371
+ console_frame = tk.Frame(vertical_container)
354
372
  vertical_container.add(console_frame, stretch="always")
355
- console_label = spacrLabel(console_frame, text="Console", background="black", foreground="white", anchor='center', justify='center', align="center")
373
+ console_label = spacrLabel(console_frame, text="Console", anchor='center', justify='center', align="center")
356
374
  console_label.grid(row=0, column=0, pady=10, padx=10)
357
- console_output = scrolledtext.ScrolledText(console_frame, height=10, bg='black', fg='white', insertbackground='white')
375
+ console_output = scrolledtext.ScrolledText(console_frame, height=10)
358
376
  console_output.grid(row=1, column=0, sticky="nsew")
359
377
  console_frame.grid_rowconfigure(1, weight=1)
360
378
  console_frame.grid_columnconfigure(0, weight=1)
361
- print("Console setup complete")
379
+ containers = [console_frame]
380
+ widgets = [console_label, console_output]
381
+ style = ttk.Style(vertical_container)
382
+ _ = set_dark_style(style, containers=containers, widgets=widgets)
362
383
  return console_output
363
384
 
364
385
  def setup_progress_frame(vertical_container):
365
386
  global progress_output
366
- progress_frame = tk.Frame(vertical_container, bg='black')
387
+ progress_frame = tk.Frame(vertical_container)
367
388
  vertical_container.add(progress_frame, stretch="always")
368
- label_frame = tk.Frame(progress_frame, bg='black')
389
+ label_frame = tk.Frame(progress_frame)
369
390
  label_frame.grid(row=0, column=0, sticky="ew", pady=(5, 0), padx=10)
370
- progress_label = spacrLabel(label_frame, text="Processing: 0%", background="black", foreground="white", font=('Helvetica', 12), anchor='w', justify='left', align="left")
391
+ progress_label = spacrLabel(label_frame, text="Processing: 0%", font=('Helvetica', 12), anchor='w', justify='left', align="left")
371
392
  progress_label.grid(row=0, column=0, sticky="w")
372
- progress_output = scrolledtext.ScrolledText(progress_frame, height=10, bg='black', fg='white', insertbackground='white')
393
+ progress_output = scrolledtext.ScrolledText(progress_frame, height=10)
373
394
  progress_output.grid(row=1, column=0, sticky="nsew")
374
395
  progress_frame.grid_rowconfigure(1, weight=1)
375
396
  progress_frame.grid_columnconfigure(0, weight=1)
376
- print("Progress frame setup complete")
397
+ containers = [progress_frame, label_frame]
398
+ widgets = [progress_label, progress_output]
399
+ style = ttk.Style(vertical_container)
400
+ _ = set_dark_style(style, containers=containers, widgets=widgets)
377
401
  return progress_output
378
402
 
379
403
  def download_hug_dataset():
@@ -459,60 +483,78 @@ def download_dataset(repo_id, subfolder, local_dir=None, retries=5, delay=5):
459
483
 
460
484
  raise Exception("Failed to download files after multiple attempts.")
461
485
 
462
- def setup_button_section(horizontal_container, settings_type='mask', window_dimensions=[500, 1000], run=True, abort=True, download=True, import_btn=True):
486
+ def setup_button_section(horizontal_container, settings_type='mask', window_dimensions=[500, 1000], run=True, abort=True, download=True, import_btn=True):
463
487
  global button_frame, button_scrollable_frame, run_button, abort_button, download_dataset_button, import_button, q, fig_queue, vars_dict
464
488
  from .settings import descriptions
465
489
 
466
- width = (window_dimensions[0])//8
490
+ width = (window_dimensions[0]) // 8
467
491
  height = window_dimensions[1]
468
492
 
469
- button_frame = tk.Frame(horizontal_container, bg='black', height=height, width=width)
493
+ button_frame = tk.Frame(horizontal_container)
470
494
  horizontal_container.add(button_frame, stretch="always", sticky="nsew")
471
495
  button_frame.grid_rowconfigure(0, weight=0)
472
496
  button_frame.grid_rowconfigure(1, weight=1)
473
497
  button_frame.grid_columnconfigure(0, weight=1)
474
498
 
475
- categories_label = spacrLabel(button_frame, text="Categories", background="black", foreground="white", font=('Helvetica', 12), anchor='center', justify='center', align="center")
499
+ categories_label = spacrLabel(button_frame, text="Categories", anchor='center', justify='center', align="center")
476
500
  categories_label.grid(row=0, column=0, pady=10, padx=10)
477
- button_scrollable_frame = spacrFrame(button_frame, bg='black')
501
+ button_scrollable_frame = spacrFrame(button_frame)
478
502
  button_scrollable_frame.grid(row=1, column=0, sticky="nsew")
479
503
 
504
+ widgets = [categories_label, button_scrollable_frame.scrollable_frame]
505
+
480
506
  btn_col = 0
481
507
  btn_row = 1
482
-
508
+
483
509
  if run:
484
- run_button = spacrButton(button_scrollable_frame.scrollable_frame, text="Run", command=lambda: start_process(q, fig_queue, settings_type), font=('Helvetica', 12))
510
+ run_button = spacrButton(button_scrollable_frame.scrollable_frame, text="run", command=lambda: start_process(q, fig_queue, settings_type))
485
511
  run_button.grid(row=btn_row, column=btn_col, pady=5, padx=5, sticky='ew')
512
+ widgets.append(run_button)
486
513
  btn_row += 1
487
514
 
488
515
  if abort and settings_type in ['mask', 'measure', 'classify', 'sequencing', 'umap']:
489
- abort_button = spacrButton(button_scrollable_frame.scrollable_frame, text="Abort", command=initiate_abort, font=('Helvetica', 12))
516
+ abort_button = spacrButton(button_scrollable_frame.scrollable_frame, text="abort", command=initiate_abort)
490
517
  abort_button.grid(row=btn_row, column=btn_col, pady=5, padx=5, sticky='ew')
518
+ widgets.append(abort_button)
491
519
  btn_row += 1
492
520
 
493
521
  if download and settings_type in ['mask']:
494
- download_dataset_button = spacrButton(button_scrollable_frame.scrollable_frame, text="Download", command=download_hug_dataset, font=('Helvetica', 12))
522
+ download_dataset_button = spacrButton(button_scrollable_frame.scrollable_frame, text="download", command=download_hug_dataset)
495
523
  download_dataset_button.grid(row=btn_row, column=btn_col, pady=5, padx=5, sticky='ew')
524
+ widgets.append(download_dataset_button)
496
525
  btn_row += 1
497
526
 
498
527
  if import_btn:
499
- import_button = spacrButton(button_scrollable_frame.scrollable_frame, text="Import", command=lambda: import_settings(settings_type), font=('Helvetica', 12))
528
+ import_button = spacrButton(button_scrollable_frame.scrollable_frame, text="settings", command=lambda: import_settings(settings_type))
500
529
  import_button.grid(row=btn_row, column=btn_col, pady=5, padx=5, sticky='ew')
530
+ widgets.append(import_button)
501
531
 
502
- # Call toggle_settings after vars_dict is initialized
503
532
  if vars_dict is not None:
504
533
  toggle_settings(button_scrollable_frame)
505
534
 
506
- # Description frame
507
- description_frame = tk.Frame(horizontal_container, bg='black', height=height, width=width)
535
+ description_frame = tk.Frame(horizontal_container)
508
536
  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
537
+ description_frame.grid_columnconfigure(0, weight=1)
538
+ description_frame.grid_rowconfigure(0, weight=1) # Add this line to make the row expandable
539
+
540
+ description_label = tk.Label(description_frame, text="Module Description", anchor='nw', justify='left', wraplength=width - 50)
541
+ description_label.grid(row=0, column=0, pady=50, padx=20, sticky='nsew')
512
542
  description_text = descriptions.get(settings_type, "No description available for this module.")
513
543
  description_label.config(text=description_text)
514
544
 
515
- return button_scrollable_frame
545
+ def update_wraplength(event):
546
+ new_width = event.width - 40 # Adjust as needed
547
+ description_label.config(wraplength=new_width)
548
+
549
+ description_label.bind('<Configure>', update_wraplength)
550
+
551
+ containers = [button_frame, description_frame]
552
+ widgets.extend([description_label])
553
+
554
+ style = ttk.Style(horizontal_container)
555
+ _ = set_dark_style(style, containers=containers, widgets=widgets)
556
+
557
+ return button_frame, button_scrollable_frame, description_frame, description_label
516
558
 
517
559
  def hide_all_settings(vars_dict, categories):
518
560
  """
@@ -561,7 +603,6 @@ def toggle_settings(button_scrollable_frame):
561
603
  def on_category_select(selected_category):
562
604
  if selected_category == "Select Category":
563
605
  return
564
- #print(f"Selected category: {selected_category}")
565
606
  if selected_category in categories:
566
607
  toggle_category(categories[selected_category])
567
608
  if selected_category in active_categories:
@@ -569,12 +610,12 @@ def toggle_settings(button_scrollable_frame):
569
610
  else:
570
611
  active_categories.add(selected_category)
571
612
  category_dropdown.update_styles(active_categories)
572
- category_var.set("Select Category") # Reset dropdown text to "Select Category"
613
+ category_var.set("Select Category")
573
614
 
574
615
  category_var = tk.StringVar()
575
616
  non_empty_categories = [category for category, settings in categories.items() if any(setting in vars_dict for setting in settings)]
576
617
  category_dropdown = spacrDropdownMenu(button_scrollable_frame.scrollable_frame, category_var, non_empty_categories, command=on_category_select)
577
- category_dropdown.grid(row=1, column=3, sticky="ew", pady=2, padx=2)
618
+ category_dropdown.grid(row=5, column=0, sticky="ew", pady=2, padx=2)
578
619
  vars_dict = hide_all_settings(vars_dict, categories)
579
620
 
580
621
  def process_fig_queue():
@@ -627,24 +668,29 @@ def set_globals(q_var, console_output_var, parent_frame_var, vars_dict_var, canv
627
668
  progress_label = progress_label_var
628
669
  fig_queue = fig_queue_var
629
670
 
671
+ def create_containers(parent_frame):
672
+ vertical_container = tk.PanedWindow(parent_frame, orient=tk.VERTICAL)
673
+ horizontal_container = tk.PanedWindow(vertical_container, orient=tk.HORIZONTAL)
674
+ settings_frame = tk.Frame(horizontal_container)
675
+ return vertical_container, horizontal_container, settings_frame
676
+
630
677
  def setup_frame(parent_frame):
631
678
  style = ttk.Style(parent_frame)
632
- set_dark_style(style)
679
+ vertical_container, horizontal_container, settings_frame = create_containers(parent_frame)
680
+ containers = [vertical_container, horizontal_container, settings_frame]
681
+
682
+ set_dark_style(style, parent_frame, containers)
633
683
  set_default_font(parent_frame, font_name="Helvetica", size=8)
634
- parent_frame.configure(bg='black')
635
- parent_frame.grid_rowconfigure(0, weight=1)
636
- parent_frame.grid_columnconfigure(0, weight=1)
637
- vertical_container = tk.PanedWindow(parent_frame, orient=tk.VERTICAL, bg='black')
684
+
638
685
  vertical_container.grid(row=0, column=0, sticky=tk.NSEW)
639
- horizontal_container = tk.PanedWindow(vertical_container, orient=tk.HORIZONTAL, bg='black')
640
686
  vertical_container.add(horizontal_container, stretch="always")
641
687
  horizontal_container.grid_columnconfigure(0, weight=1)
642
688
  horizontal_container.grid_columnconfigure(1, weight=1)
643
- settings_frame = tk.Frame(horizontal_container, bg='black')
644
689
  settings_frame.grid_rowconfigure(0, weight=0)
645
690
  settings_frame.grid_rowconfigure(1, weight=1)
646
691
  settings_frame.grid_columnconfigure(0, weight=1)
647
692
  horizontal_container.add(settings_frame, stretch="always", sticky="nsew")
693
+
648
694
  return parent_frame, vertical_container, horizontal_container
649
695
 
650
696
  def initiate_root(parent, settings_type='mask'):