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/__init__.py +4 -1
- spacr/app_annotate.py +3 -3
- spacr/app_classify.py +5 -203
- spacr/app_make_masks.py +3 -3
- spacr/app_make_masks_v2.py +3 -3
- spacr/app_mask.py +5 -250
- spacr/app_measure.py +5 -250
- spacr/app_sequencing.py +8 -0
- spacr/app_umap.py +8 -0
- spacr/core.py +8 -6
- spacr/deep_spacr.py +3 -1
- spacr/gui.py +28 -13
- spacr/gui_utils.py +878 -871
- spacr/measure.py +24 -3
- spacr/sequencing.py +1 -17
- spacr/settings.py +440 -6
- spacr/utils.py +59 -5
- {spacr-0.1.16.dist-info → spacr-0.1.55.dist-info}/METADATA +2 -1
- {spacr-0.1.16.dist-info → spacr-0.1.55.dist-info}/RECORD +23 -21
- spacr-0.1.55.dist-info/entry_points.txt +8 -0
- spacr-0.1.16.dist-info/entry_points.txt +0 -8
- {spacr-0.1.16.dist-info → spacr-0.1.55.dist-info}/LICENSE +0 -0
- {spacr-0.1.16.dist-info → spacr-0.1.55.dist-info}/WHEEL +0 -0
- {spacr-0.1.16.dist-info → spacr-0.1.55.dist-info}/top_level.txt +0 -0
spacr/__init__.py
CHANGED
@@ -15,10 +15,11 @@ from . import deep_spacr
|
|
15
15
|
from . import app_annotate
|
16
16
|
from . import gui_utils
|
17
17
|
from . import app_make_masks
|
18
|
-
from . import app_make_masks_v2
|
19
18
|
from . import app_mask
|
20
19
|
from . import app_measure
|
21
20
|
from . import app_classify
|
21
|
+
from . import app_sequencing
|
22
|
+
from . import app_umap
|
22
23
|
from . import logger
|
23
24
|
|
24
25
|
|
@@ -40,6 +41,8 @@ __all__ = [
|
|
40
41
|
"app_mask",
|
41
42
|
"app_measure",
|
42
43
|
"app_classify",
|
44
|
+
"app_sequencing",
|
45
|
+
"app_umap",
|
43
46
|
"logger"
|
44
47
|
]
|
45
48
|
|
spacr/app_annotate.py
CHANGED
@@ -13,7 +13,7 @@ from IPython.display import display, HTML
|
|
13
13
|
from tkinter import font as tkFont
|
14
14
|
from tkinter import TclError
|
15
15
|
|
16
|
-
from .gui_utils import
|
16
|
+
from .gui_utils import spacrFrame, spacrButton, set_dark_style, create_menu_bar, set_default_font
|
17
17
|
|
18
18
|
class ImageApp:
|
19
19
|
def __init__(self, root, db_path, src, image_type=None, channels=None, grid_rows=None, grid_cols=None, image_size=(200, 200), annotation_column='annotate', normalize=False, percentiles=(1,99), measurement=None, threshold=None):
|
@@ -379,7 +379,7 @@ def initiate_annotation_app_root(parent_frame):
|
|
379
379
|
container = tk.PanedWindow(parent_frame, orient=tk.HORIZONTAL, bg='black')
|
380
380
|
container.pack(fill=tk.BOTH, expand=True)
|
381
381
|
|
382
|
-
scrollable_frame =
|
382
|
+
scrollable_frame = spacrFrame(container, bg='black')
|
383
383
|
container.add(scrollable_frame, stretch="always")
|
384
384
|
|
385
385
|
# Setup input fields
|
@@ -444,7 +444,7 @@ def initiate_annotation_app_root(parent_frame):
|
|
444
444
|
# Start the annotate application in the same root window
|
445
445
|
annotate_app(parent_frame, settings)
|
446
446
|
|
447
|
-
run_button =
|
447
|
+
run_button = spacrButton(scrollable_frame.scrollable_frame, text="Run", command=run_app,
|
448
448
|
font=tkFont.Font(family="Arial", size=12, weight=tkFont.NORMAL))
|
449
449
|
run_button.grid(row=row, column=0, columnspan=2, pady=10, padx=10)
|
450
450
|
|
spacr/app_classify.py
CHANGED
@@ -1,206 +1,8 @@
|
|
1
|
-
|
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
|
-
from matplotlib.figure import Figure
|
7
|
-
matplotlib.use('Agg')
|
8
|
-
from tkinter import filedialog
|
9
|
-
from multiprocessing import Process, Queue, Value
|
10
|
-
import traceback
|
1
|
+
from .gui import MainApp
|
11
2
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
pass
|
16
|
-
|
17
|
-
from .logger import log_function_call
|
18
|
-
from .settings import set_default_train_test_model
|
19
|
-
from .gui_utils import ScrollableFrame, StdoutRedirector, CustomButton, set_dark_style, set_default_font, generate_fields, process_stdout_stderr, clear_canvas, main_thread_update_function, convert_settings_dict_for_gui
|
20
|
-
from .gui_utils import check_classify_gui_settings, train_test_model_wrapper, read_settings_from_csv, update_settings_from_csv, set_dark_style, create_menu_bar
|
21
|
-
|
22
|
-
thread_control = {"run_thread": None, "stop_requested": False}
|
23
|
-
|
24
|
-
#@log_function_call
|
25
|
-
def initiate_abort():
|
26
|
-
global thread_control
|
27
|
-
if thread_control.get("stop_requested") is not None:
|
28
|
-
thread_control["stop_requested"].value = 1
|
29
|
-
|
30
|
-
if thread_control.get("run_thread") is not None:
|
31
|
-
thread_control["run_thread"].join(timeout=5)
|
32
|
-
if thread_control["run_thread"].is_alive():
|
33
|
-
thread_control["run_thread"].terminate()
|
34
|
-
thread_control["run_thread"] = None
|
35
|
-
|
36
|
-
#@log_function_call
|
37
|
-
def run_classify_gui(q, fig_queue, stop_requested):
|
38
|
-
global vars_dict
|
39
|
-
process_stdout_stderr(q)
|
40
|
-
try:
|
41
|
-
settings = check_classify_gui_settings(vars_dict)
|
42
|
-
for key in settings:
|
43
|
-
value = settings[key]
|
44
|
-
print(key, value, type(value))
|
45
|
-
train_test_model_wrapper(settings['src'], settings)
|
46
|
-
except Exception as e:
|
47
|
-
q.put(f"Error during processing: {e}")
|
48
|
-
traceback.print_exc()
|
49
|
-
finally:
|
50
|
-
stop_requested.value = 1
|
51
|
-
|
52
|
-
#@log_function_call
|
53
|
-
def start_process(q, fig_queue):
|
54
|
-
global thread_control
|
55
|
-
if thread_control.get("run_thread") is not None:
|
56
|
-
initiate_abort()
|
57
|
-
|
58
|
-
stop_requested = Value('i', 0) # multiprocessing shared value for inter-process communication
|
59
|
-
thread_control["stop_requested"] = stop_requested
|
60
|
-
thread_control["run_thread"] = Process(target=run_classify_gui, args=(q, fig_queue, stop_requested))
|
61
|
-
thread_control["run_thread"].start()
|
62
|
-
|
63
|
-
def import_settings(scrollable_frame):
|
64
|
-
global vars_dict
|
65
|
-
|
66
|
-
csv_file_path = filedialog.askopenfilename(filetypes=[("CSV files", "*.csv")])
|
67
|
-
csv_settings = read_settings_from_csv(csv_file_path)
|
68
|
-
settings = set_default_train_test_model({})
|
69
|
-
variables = convert_settings_dict_for_gui(settings)
|
70
|
-
new_settings = update_settings_from_csv(variables, csv_settings)
|
71
|
-
vars_dict = generate_fields(new_settings, scrollable_frame)
|
72
|
-
|
73
|
-
#@log_function_call
|
74
|
-
def initiate_classify_root(parent_frame):
|
75
|
-
global vars_dict, q, canvas, fig_queue, canvas_widget, thread_control
|
76
|
-
|
77
|
-
style = ttk.Style(parent_frame)
|
78
|
-
set_dark_style(style)
|
79
|
-
set_default_font(parent_frame, font_name="Helvetica", size=8)
|
80
|
-
|
81
|
-
parent_frame.configure(bg='black')
|
82
|
-
parent_frame.grid_rowconfigure(0, weight=1)
|
83
|
-
parent_frame.grid_columnconfigure(0, weight=1)
|
84
|
-
fig_queue = Queue()
|
85
|
-
|
86
|
-
def _process_fig_queue():
|
87
|
-
global canvas
|
88
|
-
try:
|
89
|
-
while not fig_queue.empty():
|
90
|
-
clear_canvas(canvas)
|
91
|
-
fig = fig_queue.get_nowait()
|
92
|
-
for ax in fig.get_axes():
|
93
|
-
ax.set_xticks([]) # Remove x-axis ticks
|
94
|
-
ax.set_yticks([]) # Remove y-axis ticks
|
95
|
-
ax.xaxis.set_visible(False) # Hide the x-axis
|
96
|
-
ax.yaxis.set_visible(False) # Hide the y-axis
|
97
|
-
fig.tight_layout()
|
98
|
-
fig.set_facecolor('black')
|
99
|
-
canvas.figure = fig
|
100
|
-
fig_width, fig_height = canvas_widget.winfo_width(), canvas_widget.winfo_height()
|
101
|
-
fig.set_size_inches(fig_width / fig.dpi, fig_height / fig.dpi, forward=True)
|
102
|
-
canvas.draw_idle()
|
103
|
-
except Exception as e:
|
104
|
-
traceback.print_exc()
|
105
|
-
finally:
|
106
|
-
canvas_widget.after(100, _process_fig_queue)
|
107
|
-
|
108
|
-
def _process_console_queue():
|
109
|
-
while not q.empty():
|
110
|
-
message = q.get_nowait()
|
111
|
-
console_output.insert(tk.END, message)
|
112
|
-
console_output.see(tk.END)
|
113
|
-
console_output.after(100, _process_console_queue)
|
114
|
-
|
115
|
-
vertical_container = tk.PanedWindow(parent_frame, orient=tk.HORIZONTAL)
|
116
|
-
vertical_container.grid(row=0, column=0, sticky=tk.NSEW)
|
117
|
-
parent_frame.grid_rowconfigure(0, weight=1)
|
118
|
-
parent_frame.grid_columnconfigure(0, weight=1)
|
119
|
-
|
120
|
-
# Settings Section
|
121
|
-
settings_frame = tk.Frame(vertical_container, bg='black')
|
122
|
-
vertical_container.add(settings_frame, stretch="always")
|
123
|
-
settings_label = ttk.Label(settings_frame, text="Settings", background="black", foreground="white")
|
124
|
-
settings_label.grid(row=0, column=0, pady=10, padx=10)
|
125
|
-
scrollable_frame = ScrollableFrame(settings_frame, bg='black')
|
126
|
-
scrollable_frame.grid(row=1, column=0, sticky="nsew")
|
127
|
-
settings_frame.grid_rowconfigure(1, weight=1)
|
128
|
-
settings_frame.grid_columnconfigure(0, weight=1)
|
129
|
-
|
130
|
-
# Setup for user input fields (variables)
|
131
|
-
settings = set_default_train_test_model({})
|
132
|
-
variables = convert_settings_dict_for_gui(settings)
|
133
|
-
vars_dict = generate_fields(variables, scrollable_frame)
|
134
|
-
|
135
|
-
# Button section
|
136
|
-
btn_row = 1
|
137
|
-
run_button = CustomButton(scrollable_frame.scrollable_frame, text="Run", command=lambda: start_process(q, fig_queue), font=('Helvetica', 10))
|
138
|
-
run_button.grid(row=btn_row, column=0, pady=20, padx=20)
|
139
|
-
abort_button = CustomButton(scrollable_frame.scrollable_frame, text="Abort", command=initiate_abort, font=('Helvetica', 10))
|
140
|
-
abort_button.grid(row=btn_row, column=1, pady=20, padx=20)
|
141
|
-
btn_row += 1
|
142
|
-
import_btn = CustomButton(scrollable_frame.scrollable_frame, text="Import", command=lambda: import_settings(scrollable_frame), font=('Helvetica', 10))
|
143
|
-
import_btn.grid(row=btn_row, column=0, pady=20, padx=20)
|
144
|
-
btn_row += 1
|
145
|
-
progress_label = ttk.Label(scrollable_frame.scrollable_frame, text="Processing: 0%", background="black", foreground="white") # Create progress field
|
146
|
-
progress_label.grid(row=btn_row, column=0, columnspan=2, sticky="ew", pady=(5, 0), padx=10)
|
147
|
-
|
148
|
-
# Plot Canvas Section
|
149
|
-
plot_frame = tk.PanedWindow(vertical_container, orient=tk.VERTICAL)
|
150
|
-
vertical_container.add(plot_frame, stretch="always")
|
151
|
-
figure = Figure(figsize=(30, 4), dpi=100, facecolor='black')
|
152
|
-
plot = figure.add_subplot(111)
|
153
|
-
plot.plot([], [])
|
154
|
-
plot.axis('off')
|
155
|
-
canvas = FigureCanvasTkAgg(figure, master=plot_frame)
|
156
|
-
canvas.get_tk_widget().configure(cursor='arrow', background='black', highlightthickness=0)
|
157
|
-
canvas_widget = canvas.get_tk_widget()
|
158
|
-
plot_frame.add(canvas_widget, stretch="always")
|
159
|
-
canvas.draw()
|
160
|
-
canvas.figure = figure
|
161
|
-
|
162
|
-
# Console Section
|
163
|
-
console_frame = tk.Frame(vertical_container, bg='black')
|
164
|
-
vertical_container.add(console_frame, stretch="always")
|
165
|
-
console_label = ttk.Label(console_frame, text="Console", background="black", foreground="white")
|
166
|
-
console_label.grid(row=0, column=0, pady=10, padx=10)
|
167
|
-
console_output = scrolledtext.ScrolledText(console_frame, height=10, bg='black', fg='white', insertbackground='white')
|
168
|
-
console_output.grid(row=1, column=0, sticky="nsew")
|
169
|
-
console_frame.grid_rowconfigure(1, weight=1)
|
170
|
-
console_frame.grid_columnconfigure(0, weight=1)
|
171
|
-
|
172
|
-
q = Queue()
|
173
|
-
sys.stdout = StdoutRedirector(console_output)
|
174
|
-
sys.stderr = StdoutRedirector(console_output)
|
175
|
-
|
176
|
-
_process_console_queue()
|
177
|
-
_process_fig_queue()
|
178
|
-
|
179
|
-
parent_frame.after(100, lambda: main_thread_update_function(parent_frame, q, fig_queue, canvas_widget, progress_label))
|
180
|
-
|
181
|
-
return parent_frame, vars_dict
|
182
|
-
|
183
|
-
def gui_classify():
|
184
|
-
root = tk.Tk()
|
185
|
-
width = root.winfo_screenwidth()
|
186
|
-
height = root.winfo_screenheight()
|
187
|
-
root.geometry(f"{width}x{height}")
|
188
|
-
root.title("SpaCr: classify objects")
|
189
|
-
|
190
|
-
# Clear previous content if any
|
191
|
-
if hasattr(root, 'content_frame'):
|
192
|
-
for widget in root.content_frame.winfo_children():
|
193
|
-
widget.destroy()
|
194
|
-
root.content_frame.grid_forget()
|
195
|
-
else:
|
196
|
-
root.content_frame = tk.Frame(root)
|
197
|
-
root.content_frame.grid(row=1, column=0, sticky="nsew")
|
198
|
-
root.grid_rowconfigure(1, weight=1)
|
199
|
-
root.grid_columnconfigure(0, weight=1)
|
200
|
-
|
201
|
-
initiate_classify_root(root.content_frame)
|
202
|
-
create_menu_bar(root)
|
203
|
-
root.mainloop()
|
3
|
+
def start_classify_app():
|
4
|
+
app = MainApp(default_app="Classify")
|
5
|
+
app.mainloop()
|
204
6
|
|
205
7
|
if __name__ == "__main__":
|
206
|
-
|
8
|
+
start_classify_app()
|
spacr/app_make_masks.py
CHANGED
@@ -13,7 +13,7 @@ from ttkthemes import ThemedTk
|
|
13
13
|
|
14
14
|
from .logger import log_function_call
|
15
15
|
|
16
|
-
from .gui_utils import
|
16
|
+
from .gui_utils import spacrFrame, spacrButton, set_dark_style, create_menu_bar, set_default_font
|
17
17
|
|
18
18
|
class modify_masks:
|
19
19
|
|
@@ -869,7 +869,7 @@ def initiate_mask_app_root(parent_frame):
|
|
869
869
|
container = tk.PanedWindow(parent_frame, orient=tk.HORIZONTAL)
|
870
870
|
container.pack(fill=tk.BOTH, expand=True)
|
871
871
|
|
872
|
-
scrollable_frame =
|
872
|
+
scrollable_frame = spacrFrame(container, bg='black')
|
873
873
|
container.add(scrollable_frame, stretch="always")
|
874
874
|
|
875
875
|
# Setup input fields
|
@@ -897,7 +897,7 @@ def initiate_mask_app_root(parent_frame):
|
|
897
897
|
# Start the modify_masks application in the same root window
|
898
898
|
app_instance = modify_masks(parent_frame, folder_path, scale_factor)
|
899
899
|
|
900
|
-
run_button =
|
900
|
+
run_button = spacrButton(scrollable_frame.scrollable_frame, text="Run", command=run_app)
|
901
901
|
run_button.grid(row=row, column=0, columnspan=2, pady=10, padx=10)
|
902
902
|
|
903
903
|
return parent_frame
|
spacr/app_make_masks_v2.py
CHANGED
@@ -13,7 +13,7 @@ from ttkthemes import ThemedTk
|
|
13
13
|
from pyqtgraph import GraphicsLayoutWidget, ViewBox, ImageItem, mkQApp
|
14
14
|
|
15
15
|
from .logger import log_function_call
|
16
|
-
from .gui_utils import
|
16
|
+
from .gui_utils import spacrFrame, spacrButton, set_dark_style, create_menu_bar, set_default_font
|
17
17
|
|
18
18
|
class ModifyMasks:
|
19
19
|
def __init__(self, root, folder_path, scale_factor):
|
@@ -643,7 +643,7 @@ def initiate_mask_app_root(width, height):
|
|
643
643
|
container = tk.PanedWindow(root, orient=tk.HORIZONTAL)
|
644
644
|
container.pack(fill=tk.BOTH, expand=True)
|
645
645
|
|
646
|
-
scrollable_frame =
|
646
|
+
scrollable_frame = spacrFrame(container, bg='black')
|
647
647
|
container.add(scrollable_frame, stretch="always")
|
648
648
|
|
649
649
|
vars_dict = {
|
@@ -673,7 +673,7 @@ def initiate_mask_app_root(width, height):
|
|
673
673
|
|
674
674
|
create_dark_mode(root, style, console_output=None)
|
675
675
|
|
676
|
-
run_button =
|
676
|
+
run_button = spacrButton(scrollable_frame.scrollable_frame, text="Run", command=run_app)
|
677
677
|
run_button.grid(row=row, column=0, columnspan=2, pady=10, padx=10)
|
678
678
|
|
679
679
|
return root
|
spacr/app_mask.py
CHANGED
@@ -1,253 +1,8 @@
|
|
1
|
-
|
1
|
+
from .gui import MainApp
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
from matplotlib.figure import Figure
|
7
|
-
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
|
8
|
-
matplotlib.use('Agg')
|
9
|
-
from tkinter import filedialog
|
10
|
-
from multiprocessing import Process, Queue, Value
|
11
|
-
import traceback
|
12
|
-
|
13
|
-
try:
|
14
|
-
ctypes.windll.shcore.SetProcessDpiAwareness(True)
|
15
|
-
except AttributeError:
|
16
|
-
pass
|
17
|
-
|
18
|
-
from .logger import log_function_call
|
19
|
-
from .settings import set_default_settings_preprocess_generate_masks
|
20
|
-
from .gui_utils import ScrollableFrame, StdoutRedirector, ToggleSwitch, CustomButton, ToolTip
|
21
|
-
from .gui_utils import clear_canvas, main_thread_update_function, set_dark_style, generate_fields, process_stdout_stderr, set_default_font, set_dark_style, convert_settings_dict_for_gui
|
22
|
-
from .gui_utils import check_mask_gui_settings, preprocess_generate_masks_wrapper, read_settings_from_csv, update_settings_from_csv, create_menu_bar
|
23
|
-
|
24
|
-
thread_control = {"run_thread": None, "stop_requested": False}
|
25
|
-
|
26
|
-
test_mode_button = None
|
27
|
-
|
28
|
-
def toggle_test_mode():
|
29
|
-
global vars_dict
|
30
|
-
current_state = vars_dict['test_mode'][2].get()
|
31
|
-
new_state = not current_state
|
32
|
-
vars_dict['test_mode'][2].set(new_state)
|
33
|
-
if new_state:
|
34
|
-
test_mode_button.config(bg="blue")
|
35
|
-
else:
|
36
|
-
test_mode_button.config(bg="gray")
|
37
|
-
|
38
|
-
def toggle_advanced_settings():
|
39
|
-
global vars_dict
|
40
|
-
|
41
|
-
timelapse_settings = ['timelapse','fps','timelapse_displacement','timelapse_memory','timelapse_frame_limits','timelapse_remove_transient','timelapse_mode','timelapse_objects']
|
42
|
-
misc_settings = ['all_to_mip','pick_slice','skip_mode','upscale','upscale_factor','adjust_cells','lower_percentile','filter','merge_pathogens','pathogen_model']
|
43
|
-
opperational_settings = ['examples_to_plot','normalize_plots','normalize','cmap','figuresize','plot','pathogen_FT','cell_FT','nucleus_FT','nucleus_CP_prob','nucleus_Signal_to_noise','nucleus_background','cell_CP_prob','cell_Signal_to_noise','cell_background','pathogen_CP_prob','pathogen_Signal_to_noise','pathogen_background','remove_background_pathogen','remove_background_nucleus','remove_background_cell','verbose','randomize','workers','metadata_type','custom_regex','test_images','batch_size','save','masks','preprocess']
|
44
|
-
advanced_settings = timelapse_settings+misc_settings+opperational_settings
|
45
|
-
|
46
|
-
# Toggle visibility of advanced settings
|
47
|
-
for setting in advanced_settings:
|
48
|
-
label, widget, var = vars_dict[setting]
|
49
|
-
if advanced_var.get() is False:
|
50
|
-
label.grid_remove() # Hide the label
|
51
|
-
widget.grid_remove() # Hide the widget
|
52
|
-
else:
|
53
|
-
label.grid() # Show the label
|
54
|
-
widget.grid() # Show the widget
|
55
|
-
|
56
|
-
#@log_function_call
|
57
|
-
def initiate_abort():
|
58
|
-
global thread_control
|
59
|
-
if thread_control.get("stop_requested") is not None:
|
60
|
-
thread_control["stop_requested"].value = 1
|
61
|
-
|
62
|
-
if thread_control.get("run_thread") is not None:
|
63
|
-
thread_control["run_thread"].join(timeout=5)
|
64
|
-
if thread_control["run_thread"].is_alive():
|
65
|
-
thread_control["run_thread"].terminate()
|
66
|
-
thread_control["run_thread"] = None
|
67
|
-
|
68
|
-
#@log_function_call
|
69
|
-
def run_mask_gui(q, fig_queue, stop_requested):
|
70
|
-
global vars_dict
|
71
|
-
process_stdout_stderr(q)
|
72
|
-
try:
|
73
|
-
settings = check_mask_gui_settings(vars_dict)
|
74
|
-
preprocess_generate_masks_wrapper(settings, q, fig_queue)
|
75
|
-
except Exception as e:
|
76
|
-
q.put(f"Error during processing: {e}")
|
77
|
-
traceback.print_exc()
|
78
|
-
finally:
|
79
|
-
stop_requested.value = 1
|
80
|
-
|
81
|
-
#@log_function_call
|
82
|
-
def start_process(q, fig_queue):
|
83
|
-
global thread_control
|
84
|
-
if thread_control.get("run_thread") is not None:
|
85
|
-
initiate_abort()
|
86
|
-
|
87
|
-
stop_requested = Value('i', 0) # multiprocessing shared value for inter-process communication
|
88
|
-
thread_control["stop_requested"] = stop_requested
|
89
|
-
thread_control["run_thread"] = Process(target=run_mask_gui, args=(q, fig_queue, stop_requested))
|
90
|
-
thread_control["run_thread"].start()
|
91
|
-
|
92
|
-
def import_settings(scrollable_frame):
|
93
|
-
global vars_dict
|
94
|
-
|
95
|
-
csv_file_path = filedialog.askopenfilename(filetypes=[("CSV files", "*.csv")])
|
96
|
-
csv_settings = read_settings_from_csv(csv_file_path)
|
97
|
-
settings = set_default_settings_preprocess_generate_masks({})
|
98
|
-
variables = convert_settings_dict_for_gui(settings)
|
99
|
-
new_settings = update_settings_from_csv(variables, csv_settings)
|
100
|
-
vars_dict = generate_fields(new_settings, scrollable_frame)
|
101
|
-
|
102
|
-
#@log_function_call
|
103
|
-
def initiate_mask_root(parent_frame):
|
104
|
-
global vars_dict, q, canvas, fig_queue, canvas_widget, thread_control, advanced_var, scrollable_frame
|
105
|
-
|
106
|
-
style = ttk.Style(parent_frame)
|
107
|
-
set_dark_style(style)
|
108
|
-
set_default_font(parent_frame, font_name="Helvetica", size=8)
|
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, bg='black')
|
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", style="Custom.TLabel", 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 = set_default_settings_preprocess_generate_masks({})
|
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))
|
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", command=toggle_test_mode, font=('Helvetica', 10))
|
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")
|
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([], []) # This creates an empty 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_mask():
|
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: generate masks")
|
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_mask_root(root.content_frame)
|
249
|
-
create_menu_bar(root)
|
250
|
-
root.mainloop()
|
3
|
+
def start_mask_app():
|
4
|
+
app = MainApp(default_app="Mask")
|
5
|
+
app.mainloop()
|
251
6
|
|
252
7
|
if __name__ == "__main__":
|
253
|
-
|
8
|
+
start_mask_app()
|