spacr 0.1.12__py3-none-any.whl → 0.1.50__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/app_measure.py CHANGED
@@ -1,248 +1,8 @@
1
- import sys, traceback, matplotlib, ctypes
2
- import tkinter as tk
3
- from tkinter import ttk, scrolledtext
4
- from matplotlib.figure import Figure
5
- from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
6
- matplotlib.use('Agg') # Use the non-GUI Agg backend
7
- from multiprocessing import Process, Queue, Value
8
- from tkinter import filedialog
1
+ from .gui import MainApp
9
2
 
10
- try:
11
- ctypes.windll.shcore.SetProcessDpiAwareness(True)
12
- except AttributeError:
13
- pass
14
-
15
- from .logger import log_function_call
16
- from .gui_utils import ScrollableFrame, StdoutRedirector, CustomButton, ToggleSwitch, ToolTip
17
- from .gui_utils import process_stdout_stderr, set_dark_style, set_default_font, generate_fields, main_thread_update_function, create_menu_bar
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
19
-
20
- thread_control = {"run_thread": None, "stop_requested": False}
21
-
22
- def import_settings(scrollable_frame):
23
- global vars_dict
24
-
25
- csv_file_path = filedialog.askopenfilename(filetypes=[("CSV files", "*.csv")])
26
- csv_settings = read_settings_from_csv(csv_file_path)
27
- variables = measure_variables()
28
- new_settings = update_settings_from_csv(variables, csv_settings)
29
- vars_dict = generate_fields(new_settings, scrollable_frame)
30
-
31
- test_mode_button = None
32
-
33
- def toggle_test_mode():
34
- global vars_dict
35
- current_state = vars_dict['test_mode'][2].get()
36
- new_state = not current_state
37
- vars_dict['test_mode'][2].set(new_state)
38
- if new_state:
39
- test_mode_button.config(bg="blue")
40
- else:
41
- test_mode_button.config(bg="gray")
42
-
43
- def toggle_advanced_settings():
44
- global vars_dict
45
-
46
- timelapse_settings = ['timelapse', 'timelapse_objects']
47
- misc_settings = ['representative_images', 'plot', 'plot_filtration', 'include_uninfected', 'dialate_pngs', 'dialate_png_ratios']
48
- opperational_settings = ['max_workers','experiment','cells','cell_loc','pathogens','pathogen_loc','treatments','treatment_loc','channel_of_interest','compartments','measurement','nr_imgs', 'um_per_pixel']
49
-
50
- advanced_settings = timelapse_settings+misc_settings+opperational_settings
51
-
52
- # Toggle visibility of advanced settings
53
- for setting in advanced_settings:
54
- label, widget, var = vars_dict[setting]
55
- if advanced_var.get() is False:
56
- label.grid_remove() # Hide the label
57
- widget.grid_remove() # Hide the widget
58
- else:
59
- label.grid() # Show the label
60
- widget.grid() # Show the widget
61
-
62
- #@log_function_call
63
- def run_measure_gui(q, fig_queue, stop_requested):
64
- global vars_dict
65
- process_stdout_stderr(q)
66
- try:
67
- print('hello')
68
- settings = check_measure_gui_settings(vars_dict)
69
- measure_crop_wrapper(settings=settings, q=q, fig_queue=fig_queue)
70
- except Exception as e:
71
- q.put(f"Error during processing: {e}")
72
- traceback.print_exc()
73
- finally:
74
- stop_requested.value = 1
75
-
76
- #@log_function_call
77
- def start_process(q, fig_queue):
78
- global thread_control
79
- if thread_control.get("run_thread") is not None:
80
- initiate_abort()
81
-
82
- stop_requested = Value('i', 0) # multiprocessing shared value for inter-process communication
83
- thread_control["stop_requested"] = stop_requested
84
- thread_control["run_thread"] = Process(target=run_measure_gui, args=(q, fig_queue, stop_requested))
85
- thread_control["run_thread"].start()
86
-
87
- #@log_function_call
88
- def initiate_abort():
89
- global thread_control
90
- if thread_control.get("stop_requested") is not None:
91
- thread_control["stop_requested"].value = 1
92
-
93
- if thread_control.get("run_thread") is not None:
94
- thread_control["run_thread"].join(timeout=5)
95
- if thread_control["run_thread"].is_alive():
96
- thread_control["run_thread"].terminate()
97
- thread_control["run_thread"] = None
98
-
99
- #@log_function_call
100
- def initiate_measure_root(parent_frame):
101
- global vars_dict, q, canvas, fig_queue, canvas_widget, thread_control, variables, advanced_var, scrollable_frame
102
-
103
- style = ttk.Style(parent_frame)
104
- set_dark_style(style)
105
- style_text_boxes(style)
106
- set_default_font(parent_frame, font_name="Helvetica", size=8)
107
-
108
- parent_frame.configure(bg='black')
109
- parent_frame.grid_rowconfigure(0, weight=1)
110
- parent_frame.grid_columnconfigure(0, weight=1)
111
-
112
- fig_queue = Queue()
113
-
114
- # Initialize after_tasks if not already done
115
- if not hasattr(parent_frame, 'after_tasks'):
116
- parent_frame.after_tasks = []
117
-
118
- def _process_fig_queue():
119
- global canvas
120
- try:
121
- while not fig_queue.empty():
122
- clear_canvas(canvas)
123
- fig = fig_queue.get_nowait()
124
- for ax in fig.get_axes():
125
- ax.set_xticks([]) # Remove x-axis ticks
126
- ax.set_yticks([]) # Remove y-axis ticks
127
- ax.xaxis.set_visible(False) # Hide the x-axis
128
- ax.yaxis.set_visible(False) # Hide the y-axis
129
- fig.tight_layout()
130
- fig.set_facecolor('black')
131
- canvas.figure = fig
132
- fig_width, fig_height = canvas_widget.winfo_width(), canvas_widget.winfo_height()
133
- fig.set_size_inches(fig_width / fig.dpi, fig_height / fig.dpi, forward=True)
134
- canvas.draw_idle()
135
- except Exception as e:
136
- traceback.print_exc()
137
- finally:
138
- after_id = canvas_widget.after(100, _process_fig_queue)
139
- parent_frame.after_tasks.append(after_id)
140
-
141
- def _process_console_queue():
142
- while not q.empty():
143
- message = q.get_nowait()
144
- console_output.insert(tk.END, message)
145
- console_output.see(tk.END)
146
- after_id = console_output.after(100, _process_console_queue)
147
- parent_frame.after_tasks.append(after_id)
148
-
149
- # Clear previous content if any
150
- for widget in parent_frame.winfo_children():
151
- widget.destroy()
152
-
153
- vertical_container = tk.PanedWindow(parent_frame, orient=tk.HORIZONTAL)
154
- vertical_container.grid(row=0, column=0, sticky=tk.NSEW)
155
- parent_frame.grid_rowconfigure(0, weight=1)
156
- parent_frame.grid_columnconfigure(0, weight=1)
157
-
158
- # Settings Section
159
- settings_frame = tk.Frame(vertical_container, bg='black')
160
- vertical_container.add(settings_frame, stretch="always")
161
- settings_label = ttk.Label(settings_frame, text="Settings", background="black", foreground="white")
162
- settings_label.grid(row=0, column=0, pady=10, padx=10)
163
- scrollable_frame = ScrollableFrame(settings_frame, width=500)
164
- scrollable_frame.grid(row=1, column=0, sticky="nsew")
165
- settings_frame.grid_rowconfigure(1, weight=1)
166
- settings_frame.grid_columnconfigure(0, weight=1)
167
-
168
- # Create advanced settings checkbox
169
- advanced_var = tk.BooleanVar(value=False)
170
- advanced_Toggle = ToggleSwitch(scrollable_frame.scrollable_frame, text="Advanced Settings", variable=advanced_var, command=toggle_advanced_settings)
171
- advanced_Toggle.grid(row=48, column=0, pady=10, padx=10)
172
- variables = measure_variables()
173
- vars_dict = generate_fields(variables, scrollable_frame)
174
- toggle_advanced_settings()
175
- vars_dict['Test mode'] = (None, None, tk.BooleanVar(value=False))
176
-
177
- # Button section
178
- test_mode_button = CustomButton(scrollable_frame.scrollable_frame, text="Test Mode", command=toggle_test_mode)
179
- test_mode_button.grid(row=47, column=1, pady=10, padx=10)
180
- import_btn = CustomButton(scrollable_frame.scrollable_frame, text="Import", command=lambda: import_settings(scrollable_frame), font=('Helvetica', 10))
181
- import_btn.grid(row=47, column=0, pady=20, padx=20)
182
- run_button = CustomButton(scrollable_frame.scrollable_frame, text="Run", command=lambda: start_process(q, fig_queue), font=('Helvetica', 10))
183
- run_button.grid(row=45, column=0, pady=20, padx=20)
184
- abort_button = CustomButton(scrollable_frame.scrollable_frame, text="Abort", command=initiate_abort, font=('Helvetica', 10))
185
- abort_button.grid(row=45, column=1, pady=20, padx=20)
186
- progress_label = ttk.Label(scrollable_frame.scrollable_frame, text="Processing: 0%", background="black", foreground="white") # Create progress field
187
- progress_label.grid(row=50, column=0, columnspan=2, sticky="ew", pady=(5, 0), padx=10)
188
-
189
- # Plot Canvas Section
190
- plot_frame = tk.PanedWindow(vertical_container, orient=tk.VERTICAL)
191
- vertical_container.add(plot_frame, stretch="always")
192
- figure = Figure(figsize=(30, 4), dpi=100, facecolor='black')
193
- plot = figure.add_subplot(111)
194
- plot.plot([], [])
195
- plot.axis('off')
196
- canvas = FigureCanvasTkAgg(figure, master=plot_frame)
197
- canvas.get_tk_widget().configure(cursor='arrow', background='black', highlightthickness=0)
198
- canvas_widget = canvas.get_tk_widget()
199
- plot_frame.add(canvas_widget, stretch="always")
200
- canvas.draw()
201
- canvas.figure = figure
202
-
203
- # Console Section
204
- console_frame = tk.Frame(vertical_container, bg='black')
205
- vertical_container.add(console_frame, stretch="always")
206
- console_label = ttk.Label(console_frame, text="Console", background="black", foreground="white")
207
- console_label.grid(row=0, column=0, pady=10, padx=10)
208
- console_output = scrolledtext.ScrolledText(console_frame, height=10, bg='black', fg='white', insertbackground='white')
209
- console_output.grid(row=1, column=0, sticky="nsew")
210
- console_frame.grid_rowconfigure(1, weight=1)
211
- console_frame.grid_columnconfigure(0, weight=1)
212
-
213
- q = Queue()
214
- sys.stdout = StdoutRedirector(console_output)
215
- sys.stderr = StdoutRedirector(console_output)
216
-
217
- _process_console_queue()
218
- _process_fig_queue()
219
-
220
- after_id = parent_frame.after(100, lambda: main_thread_update_function(parent_frame, q, fig_queue, canvas_widget, progress_label))
221
- parent_frame.after_tasks.append(after_id)
222
-
223
- return parent_frame, vars_dict
224
-
225
- def gui_measure():
226
- root = tk.Tk()
227
- width = root.winfo_screenwidth()
228
- height = root.winfo_screenheight()
229
- root.geometry(f"{width}x{height}")
230
- root.title("SpaCr: measure objects")
231
-
232
- # Clear previous content if any
233
- if hasattr(root, 'content_frame'):
234
- for widget in root.content_frame.winfo_children():
235
- widget.destroy()
236
- root.content_frame.grid_forget()
237
- else:
238
- root.content_frame = tk.Frame(root)
239
- root.content_frame.grid(row=1, column=0, sticky="nsew")
240
- root.grid_rowconfigure(1, weight=1)
241
- root.grid_columnconfigure(0, weight=1)
242
-
243
- initiate_measure_root(root.content_frame)
244
- create_menu_bar(root)
245
- root.mainloop()
3
+ def start_measure_app():
4
+ app = MainApp(default_app="Measure")
5
+ app.mainloop()
246
6
 
247
7
  if __name__ == "__main__":
248
- gui_measure()
8
+ start_measure_app()
spacr/deep_spacr.py CHANGED
@@ -10,6 +10,9 @@ import matplotlib.pyplot as plt
10
10
  from PIL import Image
11
11
 
12
12
  from .logger import log_function_call
13
+ from .utils import close_multiprocessing_processes, reset_mp
14
+ #reset_mp()
15
+ #close_multiprocessing_processes()
13
16
 
14
17
  def evaluate_model_core(model, loader, loader_name, epoch, loss_type):
15
18
  """
@@ -42,7 +45,6 @@ def evaluate_model_core(model, loader, loader_name, epoch, loss_type):
42
45
  for batch_idx, (data, target, _) in enumerate(loader, start=1):
43
46
  start_time = time.time()
44
47
  data, target = data.to(device), target.to(device).float()
45
- #data, target = data.to(torch.float).to(device), target.to(device).float()
46
48
  output = model(data)
47
49
  loss += F.binary_cross_entropy_with_logits(output, target, reduction='sum').item()
48
50
  loss = calculate_loss(output, target, loss_type=loss_type)
spacr/gui.py CHANGED
@@ -1,20 +1,15 @@
1
1
  import tkinter as tk
2
2
  from tkinter import ttk
3
- from tkinter import font as tkFont
4
3
  from PIL import Image, ImageTk
5
4
  import os
6
5
  import requests
7
-
8
- # Import your GUI apps
9
- from .app_mask import initiate_mask_root
10
- from .app_measure import initiate_measure_root
6
+ from multiprocessing import set_start_method
7
+ from .gui_utils import set_dark_style, create_menu_bar, initiate_root
11
8
  from .app_annotate import initiate_annotation_app_root
12
9
  from .app_make_masks import initiate_mask_app_root
13
- from .app_classify import initiate_classify_root
14
- from .gui_utils import CustomButton, style_text_boxes, create_menu_bar
15
10
 
16
11
  class MainApp(tk.Tk):
17
- def __init__(self):
12
+ def __init__(self, default_app=None):
18
13
  super().__init__()
19
14
  width = self.winfo_screenwidth()
20
15
  height = self.winfo_screenheight()
@@ -22,19 +17,31 @@ class MainApp(tk.Tk):
22
17
  self.title("SpaCr GUI Collection")
23
18
  self.configure(bg="black")
24
19
  style = ttk.Style()
25
- style_text_boxes(style)
20
+ set_dark_style(style)
26
21
 
27
22
  self.gui_apps = {
28
- "Mask": (initiate_mask_root, "Generate cellpose masks for cells, nuclei and pathogen images."),
29
- "Measure": (initiate_measure_root, "Measure single object intensity and morphological feature. Crop and save single object image"),
23
+ "Mask": (lambda frame: initiate_root(frame, 'mask'), "Generate cellpose masks for cells, nuclei and pathogen images."),
24
+ "Measure": (lambda frame: initiate_root(frame, 'measure'), "Measure single object intensity and morphological feature. Crop and save single object image"),
30
25
  "Annotate": (initiate_annotation_app_root, "Annotation single object images on a grid. Annotations are saved to database."),
31
26
  "Make Masks": (initiate_mask_app_root, "Adjust pre-existing Cellpose models to your specific dataset for improved performance"),
32
- "Classify": (initiate_classify_root, "Train Torch Convolutional Neural Networks (CNNs) or Transformers to classify single object images.")
27
+ "Classify": (lambda frame: initiate_root(frame, 'classify'), "Train Torch Convolutional Neural Networks (CNNs) or Transformers to classify single object images.")
33
28
  }
34
29
 
35
30
  self.selected_app = tk.StringVar()
36
31
  self.create_widgets()
37
32
 
33
+
34
+ if default_app == "Mask":
35
+ self.load_app(default_app, self.gui_apps[default_app][0])
36
+ elif default_app == "Measure":
37
+ self.load_app(default_app, self.gui_apps[default_app][1])
38
+ elif default_app == "Annotate":
39
+ self.load_app(default_app, self.gui_apps[default_app][2])
40
+ elif default_app == "Make Masks":
41
+ self.load_app(default_app, self.gui_apps[default_app][3])
42
+ elif default_app == "Classify":
43
+ self.load_app(default_app, self.gui_apps[default_app][4])
44
+
38
45
  def create_widgets(self):
39
46
  # Create the menu bar
40
47
  create_menu_bar(self)
@@ -74,7 +81,8 @@ class MainApp(tk.Tk):
74
81
  app_func, app_desc = app_data
75
82
 
76
83
  # Create custom button with text
77
- button = CustomButton(buttons_frame, text=app_name, command=lambda app_name=app_name: self.load_app(app_name, app_func), font=('Helvetica', 12))
84
+ #button = CustomButton(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))
85
+ button = ttk.Button(buttons_frame, text=app_name, command=lambda app_name=app_name, app_func=app_func: self.load_app(app_name, app_func), style='Custom.TButton')
78
86
  button.grid(row=i, column=0, pady=10, padx=10, sticky="w")
79
87
 
80
88
  description_label = tk.Label(buttons_frame, text=app_desc, bg="black", fg="white", wraplength=800, justify="left", font=('Helvetica', 12))
@@ -100,7 +108,6 @@ class MainApp(tk.Tk):
100
108
 
101
109
  try:
102
110
  img_path = os.path.join(os.path.dirname(__file__), 'logo_spacr.png')
103
- print(f"Trying to load logo from {img_path}")
104
111
  logo_image = Image.open(img_path)
105
112
  except (FileNotFoundError, Image.UnidentifiedImageError):
106
113
  print(f"File {img_path} not found or is not a valid image. Attempting to download from GitHub.")
@@ -117,7 +124,9 @@ class MainApp(tk.Tk):
117
124
  print(f"An error occurred while loading the logo: {e}")
118
125
  return False
119
126
  try:
120
- logo_image = logo_image.resize((800, 800), Image.Resampling.LANCZOS)
127
+ screen_height = frame.winfo_screenheight()
128
+ new_height = int(screen_height // 4)
129
+ logo_image = logo_image.resize((new_height, new_height), Image.Resampling.LANCZOS)
121
130
  logo_photo = ImageTk.PhotoImage(logo_image)
122
131
  logo_label = tk.Label(frame, image=logo_photo, bg="black")
123
132
  logo_label.image = logo_photo # Keep a reference to avoid garbage collection
@@ -145,4 +154,5 @@ def gui_app():
145
154
  app.mainloop()
146
155
 
147
156
  if __name__ == "__main__":
148
- gui_app()
157
+ set_start_method('spawn', force=True)
158
+ gui_app()