spacr 0.1.16__py3-none-any.whl → 0.1.55__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,253 +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 .settings import get_measure_crop_settings
17
- from .gui_utils import ScrollableFrame, StdoutRedirector, CustomButton, ToggleSwitch
18
- from .gui_utils import process_stdout_stderr, set_dark_style, set_default_font, generate_fields, main_thread_update_function, create_menu_bar, convert_settings_dict_for_gui
19
- from .gui_utils import measure_crop_wrapper, clear_canvas, check_measure_gui_settings, read_settings_from_csv, update_settings_from_csv, set_dark_style
20
-
21
- thread_control = {"run_thread": None, "stop_requested": False}
22
-
23
- def import_settings(scrollable_frame):
24
- global vars_dict
25
-
26
- csv_file_path = filedialog.askopenfilename(filetypes=[("CSV files", "*.csv")])
27
- csv_settings = read_settings_from_csv(csv_file_path)
28
- settings = get_measure_crop_settings({})
29
- variables = convert_settings_dict_for_gui(settings)
30
- new_settings = update_settings_from_csv(variables, csv_settings)
31
- vars_dict = generate_fields(new_settings, scrollable_frame)
32
-
33
- test_mode_button = None
34
-
35
- def toggle_test_mode():
36
- global vars_dict
37
- current_state = vars_dict['test_mode'][2].get()
38
- new_state = not current_state
39
- vars_dict['test_mode'][2].set(new_state)
40
- if new_state:
41
- test_mode_button.config(bg="blue")
42
- else:
43
- test_mode_button.config(bg="gray")
44
-
45
- def toggle_advanced_settings():
46
- global vars_dict
47
-
48
- timelapse_settings = ['timelapse', 'timelapse_objects']
49
- misc_settings = ['representative_images', 'plot', 'plot_filtration', 'include_uninfected', 'dialate_pngs', 'dialate_png_ratios']
50
- opperational_settings = ['max_workers','experiment','cells','cell_loc','pathogens','pathogen_loc','treatments','treatment_loc','channel_of_interest','compartments','measurement','nr_imgs', 'um_per_pixel']
51
-
52
- advanced_settings = timelapse_settings+misc_settings+opperational_settings
53
-
54
- # Toggle visibility of advanced settings
55
- for setting in advanced_settings:
56
- label, widget, var = vars_dict[setting]
57
- if advanced_var.get() is False:
58
- label.grid_remove() # Hide the label
59
- widget.grid_remove() # Hide the widget
60
- else:
61
- label.grid() # Show the label
62
- widget.grid() # Show the widget
63
-
64
- #@log_function_call
65
- def run_measure_gui(q, fig_queue, stop_requested):
66
- global vars_dict
67
- process_stdout_stderr(q)
68
- try:
69
- print('hello')
70
- settings = check_measure_gui_settings(vars_dict)
71
- measure_crop_wrapper(settings=settings, q=q, fig_queue=fig_queue)
72
- except Exception as e:
73
- q.put(f"Error during processing: {e}")
74
- traceback.print_exc()
75
- finally:
76
- stop_requested.value = 1
77
-
78
- #@log_function_call
79
- def start_process(q, fig_queue):
80
- global thread_control
81
- if thread_control.get("run_thread") is not None:
82
- initiate_abort()
83
-
84
- stop_requested = Value('i', 0) # multiprocessing shared value for inter-process communication
85
- thread_control["stop_requested"] = stop_requested
86
- thread_control["run_thread"] = Process(target=run_measure_gui, args=(q, fig_queue, stop_requested))
87
- thread_control["run_thread"].start()
88
-
89
- #@log_function_call
90
- def initiate_abort():
91
- global thread_control
92
- if thread_control.get("stop_requested") is not None:
93
- thread_control["stop_requested"].value = 1
94
-
95
- if thread_control.get("run_thread") is not None:
96
- thread_control["run_thread"].join(timeout=5)
97
- if thread_control["run_thread"].is_alive():
98
- thread_control["run_thread"].terminate()
99
- thread_control["run_thread"] = None
100
-
101
- #@log_function_call
102
- def initiate_measure_root(parent_frame):
103
- global vars_dict, q, canvas, fig_queue, canvas_widget, thread_control, variables, advanced_var, scrollable_frame
104
-
105
- style = ttk.Style(parent_frame)
106
- set_dark_style(style)
107
- set_default_font(parent_frame, font_name="Helvetica", size=8)
108
-
109
- parent_frame.configure(bg='black')
110
- parent_frame.grid_rowconfigure(0, weight=1)
111
- parent_frame.grid_columnconfigure(0, weight=1)
112
-
113
- fig_queue = Queue()
114
-
115
- # Initialize after_tasks if not already done
116
- if not hasattr(parent_frame, 'after_tasks'):
117
- parent_frame.after_tasks = []
118
-
119
- def _process_fig_queue():
120
- global canvas
121
- try:
122
- while not fig_queue.empty():
123
- clear_canvas(canvas)
124
- fig = fig_queue.get_nowait()
125
- for ax in fig.get_axes():
126
- ax.set_xticks([]) # Remove x-axis ticks
127
- ax.set_yticks([]) # Remove y-axis ticks
128
- ax.xaxis.set_visible(False) # Hide the x-axis
129
- ax.yaxis.set_visible(False) # Hide the y-axis
130
- fig.tight_layout()
131
- fig.set_facecolor('black')
132
- canvas.figure = fig
133
- fig_width, fig_height = canvas_widget.winfo_width(), canvas_widget.winfo_height()
134
- fig.set_size_inches(fig_width / fig.dpi, fig_height / fig.dpi, forward=True)
135
- canvas.draw_idle()
136
- except Exception as e:
137
- traceback.print_exc()
138
- finally:
139
- after_id = canvas_widget.after(100, _process_fig_queue)
140
- parent_frame.after_tasks.append(after_id)
141
-
142
- def _process_console_queue():
143
- while not q.empty():
144
- message = q.get_nowait()
145
- console_output.insert(tk.END, message)
146
- console_output.see(tk.END)
147
- after_id = console_output.after(100, _process_console_queue)
148
- parent_frame.after_tasks.append(after_id)
149
-
150
- # Clear previous content if any
151
- for widget in parent_frame.winfo_children():
152
- widget.destroy()
153
-
154
- vertical_container = tk.PanedWindow(parent_frame, orient=tk.HORIZONTAL)
155
- vertical_container.grid(row=0, column=0, sticky=tk.NSEW)
156
- parent_frame.grid_rowconfigure(0, weight=1)
157
- parent_frame.grid_columnconfigure(0, weight=1)
158
-
159
- # Settings Section
160
- settings_frame = tk.Frame(vertical_container, bg='black')
161
- vertical_container.add(settings_frame, stretch="always")
162
- settings_label = ttk.Label(settings_frame, text="Settings", background="black", foreground="white")
163
- settings_label.grid(row=0, column=0, pady=10, padx=10)
164
- scrollable_frame = ScrollableFrame(settings_frame, bg='black')
165
- scrollable_frame.grid(row=1, column=0, sticky="nsew")
166
- settings_frame.grid_rowconfigure(1, weight=1)
167
- settings_frame.grid_columnconfigure(0, weight=1)
168
-
169
- # Create advanced settings checkbox
170
- advanced_var = tk.BooleanVar(value=False)
171
- advanced_Toggle = ToggleSwitch(scrollable_frame.scrollable_frame, text="Advanced Settings", variable=advanced_var, command=toggle_advanced_settings)
172
- advanced_Toggle.grid(row=4, column=0, pady=10, padx=10)
173
- settings = get_measure_crop_settings({})
174
- variables = convert_settings_dict_for_gui(settings)
175
- vars_dict = generate_fields(variables, scrollable_frame)
176
- toggle_advanced_settings()
177
- vars_dict['Test mode'] = (None, None, tk.BooleanVar(value=False))
178
-
179
- # Button section
180
- btn_row = 1
181
- run_button = CustomButton(scrollable_frame.scrollable_frame, text="Run", command=lambda: start_process(q, fig_queue), font=('Helvetica', 10))
182
- run_button.grid(row=btn_row, column=0, pady=5, padx=5)
183
- abort_button = CustomButton(scrollable_frame.scrollable_frame, text="Abort", command=initiate_abort, font=('Helvetica', 10))
184
- abort_button.grid(row=btn_row, column=1, pady=5, padx=5)
185
- btn_row += 1
186
- test_mode_button = CustomButton(scrollable_frame.scrollable_frame, text="Test Mode", command=toggle_test_mode)
187
- test_mode_button.grid(row=btn_row, column=0, pady=5, padx=5)
188
- import_btn = CustomButton(scrollable_frame.scrollable_frame, text="Import", command=lambda: import_settings(scrollable_frame), font=('Helvetica', 10))
189
- import_btn.grid(row=btn_row, column=1, pady=5, padx=5)
190
- btn_row += 1
191
- progress_label = ttk.Label(scrollable_frame.scrollable_frame, text="Processing: 0%", background="black", foreground="white") # Create progress field
192
- progress_label.grid(row=btn_row, column=0, columnspan=2, sticky="ew", pady=(5, 0), padx=10)
193
-
194
- # Plot Canvas Section
195
- plot_frame = tk.PanedWindow(vertical_container, orient=tk.VERTICAL)
196
- vertical_container.add(plot_frame, stretch="always")
197
- figure = Figure(figsize=(30, 4), dpi=100, facecolor='black')
198
- plot = figure.add_subplot(111)
199
- plot.plot([], [])
200
- plot.axis('off')
201
- canvas = FigureCanvasTkAgg(figure, master=plot_frame)
202
- canvas.get_tk_widget().configure(cursor='arrow', background='black', highlightthickness=0)
203
- canvas_widget = canvas.get_tk_widget()
204
- plot_frame.add(canvas_widget, stretch="always")
205
- canvas.draw()
206
- canvas.figure = figure
207
-
208
- # Console Section
209
- console_frame = tk.Frame(vertical_container, bg='black')
210
- vertical_container.add(console_frame, stretch="always")
211
- console_label = ttk.Label(console_frame, text="Console", background="black", foreground="white")
212
- console_label.grid(row=0, column=0, pady=10, padx=10)
213
- console_output = scrolledtext.ScrolledText(console_frame, height=10, bg='black', fg='white', insertbackground='white')
214
- console_output.grid(row=1, column=0, sticky="nsew")
215
- console_frame.grid_rowconfigure(1, weight=1)
216
- console_frame.grid_columnconfigure(0, weight=1)
217
-
218
- q = Queue()
219
- sys.stdout = StdoutRedirector(console_output)
220
- sys.stderr = StdoutRedirector(console_output)
221
-
222
- _process_console_queue()
223
- _process_fig_queue()
224
-
225
- after_id = parent_frame.after(100, lambda: main_thread_update_function(parent_frame, q, fig_queue, canvas_widget, progress_label))
226
- parent_frame.after_tasks.append(after_id)
227
-
228
- return parent_frame, vars_dict
229
-
230
- def gui_measure():
231
- root = tk.Tk()
232
- width = root.winfo_screenwidth()
233
- height = root.winfo_screenheight()
234
- root.geometry(f"{width}x{height}")
235
- root.title("SpaCr: measure objects")
236
-
237
- # Clear previous content if any
238
- if hasattr(root, 'content_frame'):
239
- for widget in root.content_frame.winfo_children():
240
- widget.destroy()
241
- root.content_frame.grid_forget()
242
- else:
243
- root.content_frame = tk.Frame(root)
244
- root.content_frame.grid(row=1, column=0, sticky="nsew")
245
- root.grid_rowconfigure(1, weight=1)
246
- root.grid_columnconfigure(0, weight=1)
247
-
248
- initiate_measure_root(root.content_frame)
249
- create_menu_bar(root)
250
- root.mainloop()
3
+ def start_measure_app():
4
+ app = MainApp(default_app="Measure")
5
+ app.mainloop()
251
6
 
252
7
  if __name__ == "__main__":
253
- gui_measure()
8
+ start_measure_app()
@@ -0,0 +1,8 @@
1
+ from .gui import MainApp
2
+
3
+ def start_seq_app():
4
+ app = MainApp(default_app="Sequencing")
5
+ app.mainloop()
6
+
7
+ if __name__ == "__main__":
8
+ start_seq_app()
spacr/app_umap.py ADDED
@@ -0,0 +1,8 @@
1
+ from .gui import MainApp
2
+
3
+ def start_umap_app():
4
+ app = MainApp(default_app="Umap")
5
+ app.mainloop()
6
+
7
+ if __name__ == "__main__":
8
+ start_umap_app()
spacr/core.py CHANGED
@@ -3021,9 +3021,9 @@ def generate_image_umap(settings={}):
3021
3021
  """
3022
3022
 
3023
3023
  from .io import _read_and_join_tables
3024
- from .utils import get_db_paths, preprocess_data, reduction_and_clustering, remove_noise, generate_colors, correct_paths, plot_embedding, plot_clusters_grid, cluster_feature_analysis, generate_umap_from_images
3025
- from .settings import get_umap_image_settings
3026
- settings = get_umap_image_settings(settings)
3024
+ from .utils import get_db_paths, preprocess_data, reduction_and_clustering, remove_noise, generate_colors, correct_paths, plot_embedding, plot_clusters_grid, cluster_feature_analysis #, generate_umap_from_images
3025
+ from .settings import set_default_umap_image_settings
3026
+ settings = set_default_umap_image_settings(settings)
3027
3027
 
3028
3028
  if isinstance(settings['src'], str):
3029
3029
  settings['src'] = [settings['src']]
@@ -3109,7 +3109,9 @@ def generate_image_umap(settings={}):
3109
3109
 
3110
3110
  else:
3111
3111
  if settings['resnet_features']:
3112
- numeric_data, embedding, labels = generate_umap_from_images(image_paths, settings['n_neighbors'], settings['min_dist'], settings['metric'], settings['clustering'], settings['eps'], settings['min_samples'], settings['n_jobs'], settings['verbose'])
3112
+ # placeholder for resnet features, not implemented yet
3113
+ pass
3114
+ #numeric_data, embedding, labels = generate_umap_from_images(image_paths, settings['n_neighbors'], settings['min_dist'], settings['metric'], settings['clustering'], settings['eps'], settings['min_samples'], settings['n_jobs'], settings['verbose'])
3113
3115
  else:
3114
3116
  # Apply the trained reducer to the entire dataset
3115
3117
  numeric_data = preprocess_data(all_df, settings['filter_by'], settings['remove_highly_correlated'], settings['log_data'], settings['exclude'])
@@ -3205,9 +3207,9 @@ def reducer_hyperparameter_search(settings={}, reduction_params=None, dbscan_par
3205
3207
 
3206
3208
  from .io import _read_and_join_tables
3207
3209
  from .utils import get_db_paths, preprocess_data, search_reduction_and_clustering, generate_colors
3208
- from .settings import get_umap_image_settings
3210
+ from .settings import set_default_umap_image_settings
3209
3211
 
3210
- settings = get_umap_image_settings(settings)
3212
+ settings = set_default_umap_image_settings(settings)
3211
3213
  pointsize = settings['dot_size']
3212
3214
  if isinstance(dbscan_params, dict):
3213
3215
  dbscan_params = [dbscan_params]
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, spacrButton
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, set_dark_style, 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()
@@ -25,16 +20,34 @@ class MainApp(tk.Tk):
25
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."),
28
+ "Sequencing": (lambda frame: initiate_root(frame, 'sequencing'), "Analyze sequensing data."),
29
+ "Umap": (lambda frame: initiate_root(frame, 'umap'), "Generate UMAP embedings with datapoints represented as images.")
33
30
  }
34
31
 
35
32
  self.selected_app = tk.StringVar()
36
33
  self.create_widgets()
37
34
 
35
+
36
+ if default_app == "Mask":
37
+ self.load_app(default_app, self.gui_apps[default_app][0])
38
+ elif default_app == "Measure":
39
+ self.load_app(default_app, self.gui_apps[default_app][1])
40
+ elif default_app == "Annotate":
41
+ self.load_app(default_app, self.gui_apps[default_app][2])
42
+ elif default_app == "Make Masks":
43
+ self.load_app(default_app, self.gui_apps[default_app][3])
44
+ elif default_app == "Classify":
45
+ self.load_app(default_app, self.gui_apps[default_app][4])
46
+ elif default_app == "Sequencing":
47
+ self.load_app(default_app, self.gui_apps[default_app][5])
48
+ elif default_app == "Umap":
49
+ self.load_app(default_app, self.gui_apps[default_app][6])
50
+
38
51
  def create_widgets(self):
39
52
  # Create the menu bar
40
53
  create_menu_bar(self)
@@ -74,7 +87,8 @@ class MainApp(tk.Tk):
74
87
  app_func, app_desc = app_data
75
88
 
76
89
  # Create custom button with text
77
- 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))
90
+ 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))
91
+ #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
92
  button.grid(row=i, column=0, pady=10, padx=10, sticky="w")
79
93
 
80
94
  description_label = tk.Label(buttons_frame, text=app_desc, bg="black", fg="white", wraplength=800, justify="left", font=('Helvetica', 12))
@@ -146,4 +160,5 @@ def gui_app():
146
160
  app.mainloop()
147
161
 
148
162
  if __name__ == "__main__":
149
- gui_app()
163
+ set_start_method('spawn', force=True)
164
+ gui_app()