spacr 0.0.17__py3-none-any.whl → 0.0.20__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/__init__.py +2 -0
- spacr/alpha.py +18 -0
- spacr/cli.py +1 -200
- spacr/core.py +267 -56
- spacr/graph_learning.py +256 -75
- spacr/graph_learning_lap.py +84 -0
- spacr/gui_classify_app.py +6 -21
- spacr/gui_mask_app.py +9 -43
- spacr/gui_measure_app.py +10 -24
- spacr/gui_sim_app.py +0 -213
- spacr/gui_utils.py +84 -66
- spacr/io.py +258 -110
- spacr/measure.py +11 -17
- spacr/old_code.py +187 -1
- spacr/plot.py +92 -87
- spacr/timelapse.py +213 -52
- spacr/utils.py +219 -118
- {spacr-0.0.17.dist-info → spacr-0.0.20.dist-info}/METADATA +28 -26
- spacr-0.0.20.dist-info/RECORD +31 -0
- {spacr-0.0.17.dist-info → spacr-0.0.20.dist-info}/WHEEL +1 -1
- spacr/gui_temp.py +0 -212
- spacr/test_annotate_app.py +0 -58
- spacr/test_plot.py +0 -43
- spacr/test_train.py +0 -39
- spacr/test_utils.py +0 -33
- spacr-0.0.17.dist-info/RECORD +0 -34
- {spacr-0.0.17.dist-info → spacr-0.0.20.dist-info}/LICENSE +0 -0
- {spacr-0.0.17.dist-info → spacr-0.0.20.dist-info}/entry_points.txt +0 -0
- {spacr-0.0.17.dist-info → spacr-0.0.20.dist-info}/top_level.txt +0 -0
spacr/gui_sim_app.py
CHANGED
@@ -1,213 +0,0 @@
|
|
1
|
-
import sys, ctypes, csv, matplotlib, traceback
|
2
|
-
import tkinter as tk
|
3
|
-
from tkinter import ttk, scrolledtext
|
4
|
-
from ttkthemes import ThemedTk
|
5
|
-
from matplotlib.figure import Figure
|
6
|
-
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
|
7
|
-
from matplotlib.figure import Figure
|
8
|
-
matplotlib.use('Agg')
|
9
|
-
from tkinter import filedialog
|
10
|
-
from multiprocessing import Process, Queue, Value
|
11
|
-
|
12
|
-
try:
|
13
|
-
ctypes.windll.shcore.SetProcessDpiAwareness(True)
|
14
|
-
except AttributeError:
|
15
|
-
pass
|
16
|
-
|
17
|
-
from .logger import log_function_call
|
18
|
-
|
19
|
-
from .gui_utils import ScrollableFrame, StdoutRedirector
|
20
|
-
from .gui_utils import create_dark_mode, set_dark_style, set_default_font, generate_fields, process_stdout_stderr, safe_literal_eval, clear_canvas, main_thread_update_function
|
21
|
-
from .gui_utils import sim_variables, check_sim_gui_settings, run_multiple_simulations_wrapper
|
22
|
-
|
23
|
-
thread_control = {"run_thread": None, "stop_requested": False}
|
24
|
-
|
25
|
-
@log_function_call
|
26
|
-
def run_sim_gui(q, fig_queue, stop_requested):
|
27
|
-
global vars_dict
|
28
|
-
process_stdout_stderr(q)
|
29
|
-
try:
|
30
|
-
settings = check_sim_gui_settings(vars_dict)
|
31
|
-
for key in settings:
|
32
|
-
value = settings[key]
|
33
|
-
print(key, value, type(value))
|
34
|
-
run_multiple_simulations_wrapper(settings, q, fig_queue)
|
35
|
-
except Exception as e:
|
36
|
-
q.put(f"Error during processing: {e}")
|
37
|
-
traceback.print_exc()
|
38
|
-
finally:
|
39
|
-
stop_requested.value = 1
|
40
|
-
|
41
|
-
@log_function_call
|
42
|
-
def start_process(q, fig_queue):
|
43
|
-
global thread_control
|
44
|
-
if thread_control.get("run_thread") is not None:
|
45
|
-
initiate_abort()
|
46
|
-
|
47
|
-
stop_requested = Value('i', 0) # multiprocessing shared value for inter-process communication
|
48
|
-
thread_control["stop_requested"] = stop_requested
|
49
|
-
thread_control["run_thread"] = Process(target=run_sim_gui, args=(q, fig_queue, stop_requested))
|
50
|
-
thread_control["run_thread"].start()
|
51
|
-
|
52
|
-
@log_function_call
|
53
|
-
def initiate_abort():
|
54
|
-
global thread_control
|
55
|
-
if thread_control.get("stop_requested") is not None:
|
56
|
-
thread_control["stop_requested"].value = 1
|
57
|
-
|
58
|
-
if thread_control.get("run_thread") is not None:
|
59
|
-
thread_control["run_thread"].join(timeout=5)
|
60
|
-
if thread_control["run_thread"].is_alive():
|
61
|
-
thread_control["run_thread"].terminate()
|
62
|
-
thread_control["run_thread"] = None
|
63
|
-
|
64
|
-
def import_settings(scrollable_frame):
|
65
|
-
global vars_dict, original_variables_structure
|
66
|
-
|
67
|
-
csv_file_path = filedialog.askopenfilename(filetypes=[("CSV files", "*.csv")])
|
68
|
-
|
69
|
-
if not csv_file_path:
|
70
|
-
return
|
71
|
-
|
72
|
-
imported_variables = {}
|
73
|
-
|
74
|
-
with open(csv_file_path, newline='') as csvfile:
|
75
|
-
reader = csv.DictReader(csvfile)
|
76
|
-
for row in reader:
|
77
|
-
key = row['Key']
|
78
|
-
value = row['Value']
|
79
|
-
# Evaluate the value safely using safe_literal_eval
|
80
|
-
imported_variables[key] = safe_literal_eval(value)
|
81
|
-
|
82
|
-
# Track changed variables and apply the imported ones, printing changes as we go
|
83
|
-
for key, var in vars_dict.items():
|
84
|
-
if key in imported_variables and var.get() != imported_variables[key]:
|
85
|
-
print(f"Updating '{key}' from '{var.get()}' to '{imported_variables[key]}'")
|
86
|
-
var.set(imported_variables[key])
|
87
|
-
|
88
|
-
@log_function_call
|
89
|
-
def initiate_sim_root(width, height):
|
90
|
-
global root, vars_dict, q, canvas, fig_queue, canvas_widget, thread_control
|
91
|
-
|
92
|
-
theme = 'breeze'
|
93
|
-
|
94
|
-
if theme in ['clam']:
|
95
|
-
root = tk.Tk()
|
96
|
-
style = ttk.Style(root)
|
97
|
-
style.theme_use(theme) #plastik, clearlooks, elegance, default was clam #alt, breeze, arc
|
98
|
-
set_dark_style(style)
|
99
|
-
elif theme in ['breeze']:
|
100
|
-
root = ThemedTk(theme="breeze")
|
101
|
-
style = ttk.Style(root)
|
102
|
-
set_dark_style(style)
|
103
|
-
|
104
|
-
set_default_font(root, font_name="Arial", size=10)
|
105
|
-
#root.state('zoomed') # For Windows to maximize the window
|
106
|
-
root.attributes('-fullscreen', True)
|
107
|
-
root.geometry(f"{width}x{height}")
|
108
|
-
root.title("SpaCer: Simulate screen")
|
109
|
-
fig_queue = Queue()
|
110
|
-
|
111
|
-
def _process_fig_queue():
|
112
|
-
global canvas
|
113
|
-
try:
|
114
|
-
while not fig_queue.empty():
|
115
|
-
clear_canvas(canvas)
|
116
|
-
fig = fig_queue.get_nowait()
|
117
|
-
#set_fig_text_properties(fig, font_size=8)
|
118
|
-
for ax in fig.get_axes():
|
119
|
-
ax.set_xticks([]) # Remove x-axis ticks
|
120
|
-
ax.set_yticks([]) # Remove y-axis ticks
|
121
|
-
ax.xaxis.set_visible(False) # Hide the x-axis
|
122
|
-
ax.yaxis.set_visible(False) # Hide the y-axis
|
123
|
-
#ax.title.set_fontsize(14)
|
124
|
-
#disable_interactivity(fig)
|
125
|
-
fig.tight_layout()
|
126
|
-
fig.set_facecolor('#333333')
|
127
|
-
canvas.figure = fig
|
128
|
-
fig_width, fig_height = canvas_widget.winfo_width(), canvas_widget.winfo_height()
|
129
|
-
fig.set_size_inches(fig_width / fig.dpi, fig_height / fig.dpi, forward=True)
|
130
|
-
canvas.draw_idle()
|
131
|
-
except Exception as e:
|
132
|
-
traceback.print_exc()
|
133
|
-
#pass
|
134
|
-
finally:
|
135
|
-
canvas_widget.after(100, _process_fig_queue)
|
136
|
-
|
137
|
-
# Process queue for console output
|
138
|
-
def _process_console_queue():
|
139
|
-
while not q.empty():
|
140
|
-
message = q.get_nowait()
|
141
|
-
console_output.insert(tk.END, message)
|
142
|
-
console_output.see(tk.END)
|
143
|
-
console_output.after(100, _process_console_queue)
|
144
|
-
|
145
|
-
# Vertical container for settings and console
|
146
|
-
vertical_container = tk.PanedWindow(root, orient=tk.HORIZONTAL) #VERTICAL
|
147
|
-
vertical_container.pack(fill=tk.BOTH, expand=True)
|
148
|
-
|
149
|
-
# Scrollable Frame for user settings
|
150
|
-
scrollable_frame = ScrollableFrame(vertical_container, bg='#333333')
|
151
|
-
vertical_container.add(scrollable_frame, stretch="always")
|
152
|
-
|
153
|
-
# Setup for user input fields (variables)
|
154
|
-
variables = sim_variables()
|
155
|
-
vars_dict = generate_fields(variables, scrollable_frame)
|
156
|
-
|
157
|
-
# Horizontal container for Matplotlib figure and the vertical pane (for settings and console)
|
158
|
-
horizontal_container = tk.PanedWindow(vertical_container, orient=tk.VERTICAL) #HORIZONTAL
|
159
|
-
vertical_container.add(horizontal_container, stretch="always")
|
160
|
-
|
161
|
-
# Matplotlib figure setup
|
162
|
-
figure = Figure(figsize=(30, 4), dpi=100, facecolor='#333333')
|
163
|
-
plot = figure.add_subplot(111)
|
164
|
-
plot.plot([], []) # This creates an empty plot.
|
165
|
-
plot.axis('off')
|
166
|
-
|
167
|
-
# Embedding the Matplotlib figure in the Tkinter window
|
168
|
-
canvas = FigureCanvasTkAgg(figure, master=horizontal_container)
|
169
|
-
canvas.get_tk_widget().configure(cursor='arrow', background='#333333', highlightthickness=0)
|
170
|
-
#canvas.get_tk_widget().configure(cursor='arrow')
|
171
|
-
canvas_widget = canvas.get_tk_widget()
|
172
|
-
horizontal_container.add(canvas_widget, stretch="always")
|
173
|
-
canvas.draw()
|
174
|
-
canvas.figure = figure
|
175
|
-
|
176
|
-
# Console output setup below the settings
|
177
|
-
console_output = scrolledtext.ScrolledText(vertical_container, height=10)
|
178
|
-
vertical_container.add(console_output, stretch="always")
|
179
|
-
|
180
|
-
# Queue and redirection setup for updating console output safely
|
181
|
-
q = Queue()
|
182
|
-
sys.stdout = StdoutRedirector(console_output)
|
183
|
-
sys.stderr = StdoutRedirector(console_output)
|
184
|
-
|
185
|
-
# This is your GUI setup where you create the Run button
|
186
|
-
run_button = ttk.Button(scrollable_frame.scrollable_frame, text="Run",command=lambda: start_process(q, fig_queue))
|
187
|
-
run_button.grid(row=40, column=0, pady=10)
|
188
|
-
|
189
|
-
abort_button = ttk.Button(scrollable_frame.scrollable_frame, text="Abort", command=initiate_abort)
|
190
|
-
abort_button.grid(row=40, column=1, pady=10)
|
191
|
-
|
192
|
-
progress_label = ttk.Label(scrollable_frame.scrollable_frame, text="Processing: 0%", background="#333333", foreground="white")
|
193
|
-
progress_label.grid(row=41, column=0, columnspan=2, sticky="ew", pady=(5, 0))
|
194
|
-
|
195
|
-
# Create the Import Settings button
|
196
|
-
import_btn = tk.Button(root, text="Import Settings", command=lambda: import_settings(scrollable_frame))
|
197
|
-
import_btn.pack(pady=20)
|
198
|
-
|
199
|
-
_process_console_queue()
|
200
|
-
_process_fig_queue()
|
201
|
-
create_dark_mode(root, style, console_output)
|
202
|
-
|
203
|
-
root.after(100, lambda: main_thread_update_function(root, q, fig_queue, canvas_widget, progress_label))
|
204
|
-
|
205
|
-
return root, vars_dict
|
206
|
-
|
207
|
-
def gui_sim():
|
208
|
-
global vars_dict, root
|
209
|
-
root, vars_dict = initiate_sim_root(1000, 1500)
|
210
|
-
root.mainloop()
|
211
|
-
|
212
|
-
if __name__ == "__main__":
|
213
|
-
gui_sim()
|
spacr/gui_utils.py
CHANGED
@@ -1,6 +1,6 @@
|
|
1
|
-
import spacr, inspect, traceback, io, sys, ast, ctypes, matplotlib
|
2
|
-
matplotlib.use('Agg')
|
1
|
+
import spacr, inspect, traceback, io, sys, ast, ctypes, matplotlib, re, csv
|
3
2
|
import matplotlib.pyplot as plt
|
3
|
+
matplotlib.use('Agg')
|
4
4
|
import numpy as np
|
5
5
|
import tkinter as tk
|
6
6
|
from tkinter import ttk, messagebox
|
@@ -14,6 +14,26 @@ except AttributeError:
|
|
14
14
|
|
15
15
|
from .logger import log_function_call
|
16
16
|
|
17
|
+
def read_settings_from_csv(csv_file_path):
|
18
|
+
settings = {}
|
19
|
+
with open(csv_file_path, newline='') as csvfile:
|
20
|
+
reader = csv.DictReader(csvfile)
|
21
|
+
for row in reader:
|
22
|
+
key = row['Key']
|
23
|
+
value = row['Value']
|
24
|
+
settings[key] = value
|
25
|
+
return settings
|
26
|
+
|
27
|
+
def update_settings_from_csv(variables, csv_settings):
|
28
|
+
new_settings = variables.copy() # Start with a copy of the original settings
|
29
|
+
for key, value in csv_settings.items():
|
30
|
+
if key in new_settings:
|
31
|
+
# Get the variable type and options from the original settings
|
32
|
+
var_type, options, _ = new_settings[key]
|
33
|
+
# Update the default value with the CSV value, keeping the type and options unchanged
|
34
|
+
new_settings[key] = (var_type, options, value)
|
35
|
+
return new_settings
|
36
|
+
|
17
37
|
def safe_literal_eval(value):
|
18
38
|
try:
|
19
39
|
# First, try to evaluate as a literal
|
@@ -103,62 +123,52 @@ def check_mask_gui_settings(vars_dict):
|
|
103
123
|
def check_measure_gui_settings(vars_dict):
|
104
124
|
settings = {}
|
105
125
|
for key, var in vars_dict.items():
|
106
|
-
value = var.get() #
|
126
|
+
value = var.get() # Retrieves the string representation for entries or the actual value for checkboxes and combos.
|
107
127
|
|
108
128
|
try:
|
109
|
-
if key
|
110
|
-
# Converts string representation to a list of integers
|
129
|
+
if key in ['channels', 'png_dims']:
|
111
130
|
settings[key] = [int(chan) for chan in ast.literal_eval(value)] if value else []
|
112
131
|
|
113
132
|
elif key in ['cell_loc', 'pathogen_loc', 'treatment_loc']:
|
114
|
-
|
115
|
-
|
133
|
+
# Convert to a list of lists of strings, ensuring all structures are lists.
|
134
|
+
settings[key] = [list(map(str, sublist)) for sublist in ast.literal_eval(value)] if value else []
|
135
|
+
|
116
136
|
elif key == 'dialate_png_ratios':
|
117
|
-
settings[key] = [float(num) for num in
|
137
|
+
settings[key] = [float(num) for num in ast.literal_eval(value)] if value else []
|
118
138
|
|
119
139
|
elif key == 'normalize':
|
120
|
-
|
121
|
-
settings[key] = [int(num) for num in ast.literal_eval(value)] if value else None
|
140
|
+
settings[key] = [int(num) for num in ast.literal_eval(value)] if value else []
|
122
141
|
|
123
|
-
|
124
|
-
|
142
|
+
# Directly assign string values for these specific keys
|
143
|
+
elif key in ['normalize_by', 'experiment', 'measurement', 'input_folder']:
|
125
144
|
settings[key] = value
|
126
145
|
|
127
146
|
elif key == 'png_size':
|
128
|
-
|
129
|
-
temp_val = ast.literal_eval(value) if value else []
|
130
|
-
settings[key] = [list(map(int, dim)) for dim in temp_val] if temp_val else None
|
131
|
-
|
132
|
-
# Handling for other keys as in your original function...
|
147
|
+
settings[key] = [list(map(int, dim)) for dim in ast.literal_eval(value)] if value else []
|
133
148
|
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
elif key == 'timelapse_objects':
|
139
|
-
# Ensure it's a list of strings
|
140
|
-
settings[key] = eval(value) if value else []
|
141
|
-
|
142
|
-
# Handling for keys that should be treated as strings directly
|
143
|
-
elif key in ['normalize_by', 'experiment', 'measurement', 'input_folder']:
|
144
|
-
settings[key] = str(value) if value else None
|
149
|
+
# Ensure these are lists of strings, converting from tuples if necessary
|
150
|
+
elif key in ['timelapse_objects', 'crop_mode', 'cells', 'pathogens', 'treatments']:
|
151
|
+
eval_value = ast.literal_eval(value) if value else []
|
152
|
+
settings[key] = list(map(str, eval_value)) if isinstance(eval_value, (list, tuple)) else [str(eval_value)]
|
145
153
|
|
146
|
-
# Handling for single values
|
154
|
+
# Handling for single non-string values (int, float, bool)
|
147
155
|
elif key in ['cell_mask_dim', 'cell_min_size', 'nucleus_mask_dim', 'nucleus_min_size', 'pathogen_mask_dim', 'pathogen_min_size', 'cytoplasm_min_size', 'max_workers', 'channel_of_interest', 'nr_imgs']:
|
148
156
|
settings[key] = int(value) if value else None
|
149
157
|
|
150
158
|
elif key == 'um_per_pixel':
|
151
159
|
settings[key] = float(value) if value else None
|
152
160
|
|
153
|
-
#
|
161
|
+
# Handling boolean values based on checkboxes
|
154
162
|
elif key in ['save_png', 'use_bounding_box', 'save_measurements', 'plot', 'plot_filtration', 'include_uninfected', 'dialate_pngs', 'timelapse', 'representative_images']:
|
155
|
-
settings[key] =
|
163
|
+
settings[key] = var.get()
|
156
164
|
|
157
165
|
except SyntaxError as e:
|
158
|
-
|
166
|
+
print(f"Syntax error processing {key}: {str(e)}")
|
167
|
+
#messagebox.showerror("Error", f"Syntax error processing {key}: {str(e)}")
|
159
168
|
return None
|
160
169
|
except Exception as e:
|
161
|
-
|
170
|
+
print(f"Error processing {key}: {str(e)}")
|
171
|
+
#messagebox.showerror("Error", f"Error processing {key}: {str(e)}")
|
162
172
|
return None
|
163
173
|
|
164
174
|
return settings
|
@@ -268,11 +278,21 @@ def sim_variables():
|
|
268
278
|
}
|
269
279
|
return variables
|
270
280
|
|
281
|
+
def add_measure_gui_defaults(settings):
|
282
|
+
settings['compartments'] = ['pathogen', 'cytoplasm']
|
283
|
+
return settings
|
284
|
+
|
271
285
|
def measure_variables():
|
272
286
|
variables = {
|
273
287
|
'input_folder':('entry', None, '/mnt/data/CellVoyager/40x/einar/mitotrackerHeLaToxoDsRed_20240224_123156/test_gui/merged'),
|
274
288
|
'channels': ('combo', ['[0,1,2,3]','[0,1,2]','[0,1]','[0]'], '[0,1,2,3]'),
|
275
289
|
'cell_mask_dim':('entry', None, 4),
|
290
|
+
'cell_min_size':('entry', None, 0),
|
291
|
+
'cytoplasm_min_size':('entry', None, 0),
|
292
|
+
'nucleus_mask_dim':('entry', None, 5),
|
293
|
+
'nucleus_min_size':('entry', None, 0),
|
294
|
+
'pathogen_mask_dim':('entry', None, 6),
|
295
|
+
'pathogen_min_size':('entry', None, 0),
|
276
296
|
'save_png':('check', None, True),
|
277
297
|
'crop_mode':('entry', None, '["cell"]'),
|
278
298
|
'use_bounding_box':('check', None, True),
|
@@ -298,6 +318,7 @@ def measure_variables():
|
|
298
318
|
'treatments': ('entry', None, '["cm","lovastatin_20uM"]'),
|
299
319
|
'treatment_loc': ('entry', None, '[["c1","c2"], ["c3","c4"]]'),
|
300
320
|
'channel_of_interest':('entry', None, 3),
|
321
|
+
'compartments':('entry', None, '["pathogen","cytoplasm"]'),
|
301
322
|
'measurement':('entry', None, 'mean_intensity'),
|
302
323
|
'nr_imgs':('entry', None, 32),
|
303
324
|
'um_per_pixel':('entry', None, 0.1)
|
@@ -346,7 +367,7 @@ def classify_variables():
|
|
346
367
|
return variables
|
347
368
|
|
348
369
|
|
349
|
-
|
370
|
+
#@log_function_call
|
350
371
|
def create_input_field(frame, label_text, row, var_type='entry', options=None, default_value=None):
|
351
372
|
label = ttk.Label(frame, text=label_text, style='TLabel') # Assuming you have a dark mode style for labels too
|
352
373
|
label.grid(column=0, row=row, sticky=tk.W, padx=5, pady=5)
|
@@ -370,10 +391,6 @@ def create_input_field(frame, label_text, row, var_type='entry', options=None, d
|
|
370
391
|
var = None # Placeholder in case of an undefined var_type
|
371
392
|
|
372
393
|
return var
|
373
|
-
|
374
|
-
def add_measure_gui_defaults(settings):
|
375
|
-
settings['compartments'] = ['pathogen', 'cytoplasm']
|
376
|
-
return settings
|
377
394
|
|
378
395
|
def mask_variables():
|
379
396
|
variables = {
|
@@ -395,10 +412,10 @@ def mask_variables():
|
|
395
412
|
'pathogen_background': ('entry', None, 100),
|
396
413
|
'pathogen_Signal_to_noise': ('entry', None, 3),
|
397
414
|
'pathogen_CP_prob': ('entry', None, 0),
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
415
|
+
'preprocess': ('check', None, True),
|
416
|
+
'masks': ('check', None, True),
|
417
|
+
'examples_to_plot': ('entry', None, 1),
|
418
|
+
'randomize': ('check', None, True),
|
402
419
|
'batch_size': ('entry', None, 50),
|
403
420
|
'timelapse': ('check', None, False),
|
404
421
|
'timelapse_displacement': ('entry', None, None),
|
@@ -407,14 +424,14 @@ def mask_variables():
|
|
407
424
|
'timelapse_remove_transient': ('check', None, True),
|
408
425
|
'timelapse_mode': ('combo', ['trackpy', 'btrack'], 'trackpy'),
|
409
426
|
'timelapse_objects': ('combo', ['cell','nucleus','pathogen','cytoplasm', None], None),
|
410
|
-
|
411
|
-
|
427
|
+
'fps': ('entry', None, 2),
|
428
|
+
'remove_background': ('check', None, True),
|
412
429
|
'lower_quantile': ('entry', None, 0.01),
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
430
|
+
'merge': ('check', None, False),
|
431
|
+
'normalize_plots': ('check', None, True),
|
432
|
+
'all_to_mip': ('check', None, False),
|
433
|
+
'pick_slice': ('check', None, False),
|
434
|
+
'skip_mode': ('entry', None, None),
|
418
435
|
'save': ('check', None, True),
|
419
436
|
'plot': ('check', None, True),
|
420
437
|
'workers': ('entry', None, 30),
|
@@ -482,30 +499,31 @@ def set_dark_style(style):
|
|
482
499
|
style.configure('TEntry', background='#333333', foreground='white')
|
483
500
|
style.configure('TCheckbutton', background='#333333', foreground='white')
|
484
501
|
|
485
|
-
|
502
|
+
#@log_function_call
|
486
503
|
def main_thread_update_function(root, q, fig_queue, canvas_widget, progress_label):
|
487
504
|
try:
|
505
|
+
ansi_escape_pattern = re.compile(r'\x1B\[[0-?]*[ -/]*[@-~]')
|
488
506
|
while not q.empty():
|
489
507
|
message = q.get_nowait()
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
508
|
+
clean_message = ansi_escape_pattern.sub('', message)
|
509
|
+
if clean_message.startswith("Progress"):
|
510
|
+
progress_label.config(text=clean_message)
|
511
|
+
if clean_message.startswith("\rProgress"):
|
512
|
+
progress_label.config(text=clean_message)
|
513
|
+
elif clean_message.startswith("Successfully"):
|
514
|
+
progress_label.config(text=clean_message)
|
515
|
+
elif clean_message.startswith("Processing"):
|
516
|
+
progress_label.config(text=clean_message)
|
517
|
+
elif clean_message.startswith("scale"):
|
497
518
|
pass
|
498
|
-
elif
|
519
|
+
elif clean_message.startswith("plot_cropped_arrays"):
|
499
520
|
pass
|
500
|
-
elif
|
521
|
+
elif clean_message == "" or clean_message == "\r" or clean_message.strip() == "":
|
501
522
|
pass
|
502
523
|
else:
|
503
|
-
print(
|
504
|
-
while not fig_queue.empty():
|
505
|
-
fig = fig_queue.get_nowait()
|
506
|
-
clear_canvas(canvas_widget)
|
524
|
+
print(clean_message)
|
507
525
|
except Exception as e:
|
508
|
-
print(f"Error updating GUI: {e}")
|
526
|
+
print(f"Error updating GUI canvas: {e}")
|
509
527
|
finally:
|
510
528
|
root.after(100, lambda: main_thread_update_function(root, q, fig_queue, canvas_widget, progress_label))
|
511
529
|
|
@@ -538,7 +556,6 @@ def clear_canvas(canvas):
|
|
538
556
|
# Redraw the now empty canvas without changing its size
|
539
557
|
canvas.draw_idle()
|
540
558
|
|
541
|
-
@log_function_call
|
542
559
|
def measure_crop_wrapper(settings, q, fig_queue):
|
543
560
|
"""
|
544
561
|
Wraps the measure_crop function to integrate with GUI processes.
|
@@ -562,6 +579,7 @@ def measure_crop_wrapper(settings, q, fig_queue):
|
|
562
579
|
plt.show = my_show
|
563
580
|
|
564
581
|
try:
|
582
|
+
print('start')
|
565
583
|
spacr.measure.measure_crop(settings=settings, annotation_settings={}, advanced_settings={})
|
566
584
|
except Exception as e:
|
567
585
|
errorMessage = f"Error during processing: {e}"
|
@@ -594,7 +612,7 @@ def preprocess_generate_masks_wrapper(settings, q, fig_queue):
|
|
594
612
|
plt.show = my_show
|
595
613
|
|
596
614
|
try:
|
597
|
-
spacr.core.preprocess_generate_masks(settings['src'], settings=settings
|
615
|
+
spacr.core.preprocess_generate_masks(settings['src'], settings=settings)
|
598
616
|
except Exception as e:
|
599
617
|
errorMessage = f"Error during processing: {e}"
|
600
618
|
q.put(errorMessage) # Send the error message to the GUI via the queue
|