spacr 0.0.1__py3-none-any.whl → 0.0.2__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 -0
- spacr/alpha.py +18 -0
- spacr/cli.py +25 -187
- spacr/core.py +267 -56
- spacr/graph_learning.py +276 -0
- spacr/graph_learning_lap.py +84 -0
- spacr/gui_classify_app.py +197 -0
- spacr/gui_mask_app.py +58 -106
- spacr/gui_measure_app.py +14 -28
- spacr/gui_sim_app.py +0 -0
- spacr/gui_utils.py +311 -115
- spacr/io.py +260 -112
- spacr/measure.py +11 -17
- spacr/old_code.py +187 -1
- spacr/plot.py +92 -85
- spacr/sim.py +8 -1
- spacr/timelapse.py +213 -52
- spacr/train.py +7 -1
- spacr/utils.py +220 -119
- spacr-0.0.2.dist-info/METADATA +130 -0
- spacr-0.0.2.dist-info/RECORD +31 -0
- {spacr-0.0.1.dist-info → spacr-0.0.2.dist-info}/entry_points.txt +2 -0
- spacr-0.0.1.dist-info/METADATA +0 -64
- spacr-0.0.1.dist-info/RECORD +0 -26
- {spacr-0.0.1.dist-info → spacr-0.0.2.dist-info}/LICENSE +0 -0
- {spacr-0.0.1.dist-info → spacr-0.0.2.dist-info}/WHEEL +0 -0
- {spacr-0.0.1.dist-info → spacr-0.0.2.dist-info}/top_level.txt +0 -0
spacr/gui_mask_app.py
CHANGED
@@ -1,15 +1,14 @@
|
|
1
|
-
import spacr, sys,
|
1
|
+
import spacr, sys, ctypes, csv, matplotlib
|
2
2
|
import tkinter as tk
|
3
3
|
from tkinter import ttk, scrolledtext
|
4
4
|
from ttkthemes import ThemedTk
|
5
5
|
from matplotlib.figure import Figure
|
6
6
|
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
|
7
|
-
import matplotlib.pyplot as plt
|
8
7
|
from matplotlib.figure import Figure
|
9
|
-
from threading import Thread
|
10
8
|
matplotlib.use('Agg')
|
11
|
-
from threading import Thread
|
12
9
|
from tkinter import filedialog
|
10
|
+
from multiprocessing import Process, Queue, Value
|
11
|
+
import traceback
|
13
12
|
|
14
13
|
try:
|
15
14
|
ctypes.windll.shcore.SetProcessDpiAwareness(True)
|
@@ -17,112 +16,60 @@ except AttributeError:
|
|
17
16
|
pass
|
18
17
|
|
19
18
|
from .logger import log_function_call
|
20
|
-
from .gui_utils import ScrollableFrame, StdoutRedirector, create_dark_mode, set_dark_style, set_default_font,
|
21
|
-
from .gui_utils import
|
19
|
+
from .gui_utils import ScrollableFrame, StdoutRedirector, safe_literal_eval, clear_canvas, main_thread_update_function, create_dark_mode, set_dark_style, set_default_font, generate_fields, process_stdout_stderr
|
20
|
+
from .gui_utils import mask_variables, check_mask_gui_settings, preprocess_generate_masks_wrapper, read_settings_from_csv, update_settings_from_csv #, add_mask_gui_defaults
|
22
21
|
|
23
22
|
thread_control = {"run_thread": None, "stop_requested": False}
|
24
23
|
|
25
|
-
|
26
|
-
def __init__(self, container, *args, bg='#333333', **kwargs):
|
27
|
-
super().__init__(container, *args, **kwargs)
|
28
|
-
self.configure(style='TFrame') # Ensure this uses the styled frame from dark mode
|
29
|
-
|
30
|
-
canvas = tk.Canvas(self, bg=bg) # Set canvas background to match dark mode
|
31
|
-
scrollbar = ttk.Scrollbar(self, orient="vertical", command=canvas.yview)
|
32
|
-
|
33
|
-
self.scrollable_frame = ttk.Frame(canvas, style='TFrame') # Ensure it uses the styled frame
|
34
|
-
self.scrollable_frame.bind(
|
35
|
-
"<Configure>",
|
36
|
-
lambda e: canvas.configure(scrollregion=canvas.bbox("all"))
|
37
|
-
)
|
38
|
-
|
39
|
-
canvas.create_window((0, 0), window=self.scrollable_frame, anchor="nw")
|
40
|
-
canvas.configure(yscrollcommand=scrollbar.set)
|
41
|
-
|
42
|
-
canvas.pack(side="left", fill="both", expand=True)
|
43
|
-
scrollbar.pack(side="right", fill="y")
|
44
|
-
|
45
|
-
def clear_canvas():
|
46
|
-
global canvas
|
47
|
-
# Clear each plot (axes) in the figure
|
48
|
-
for ax in canvas.figure.get_axes():
|
49
|
-
ax.clear() # Clears the axes, but keeps them visible for new plots
|
50
|
-
|
51
|
-
# Redraw the now empty canvas without changing its size
|
52
|
-
canvas.draw_idle() # Using draw_idle for efficiency in redrawing
|
53
|
-
|
24
|
+
@log_function_call
|
54
25
|
def initiate_abort():
|
55
|
-
global thread_control
|
56
|
-
thread_control
|
57
|
-
|
58
|
-
|
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)
|
59
32
|
if thread_control["run_thread"].is_alive():
|
60
|
-
|
33
|
+
thread_control["run_thread"].terminate()
|
61
34
|
thread_control["run_thread"] = None
|
62
|
-
|
63
|
-
def preprocess_generate_masks_wrapper(*args, **kwargs):
|
64
|
-
global fig_queue
|
65
|
-
def my_show():
|
66
|
-
fig = plt.gcf()
|
67
|
-
fig_queue.put(fig) # Put the figure into the queue
|
68
|
-
plt.close(fig) # Close the figure to prevent it from being shown by plt.show()
|
69
|
-
|
70
|
-
original_show = plt.show
|
71
|
-
plt.show = my_show
|
72
|
-
|
73
|
-
try:
|
74
|
-
spacr.core.preprocess_generate_masks(*args, **kwargs)
|
75
|
-
except Exception as e:
|
76
|
-
pass
|
77
|
-
finally:
|
78
|
-
plt.show = original_show
|
79
35
|
|
80
|
-
|
81
|
-
|
36
|
+
@log_function_call
|
37
|
+
def run_mask_gui(q, fig_queue, stop_requested):
|
38
|
+
global vars_dict
|
39
|
+
process_stdout_stderr(q)
|
82
40
|
try:
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
41
|
+
settings = check_mask_gui_settings(vars_dict)
|
42
|
+
#settings = add_mask_gui_defaults(settings)
|
43
|
+
#for key in settings:
|
44
|
+
# value = settings[key]
|
45
|
+
# print(key, value, type(value))
|
46
|
+
preprocess_generate_masks_wrapper(settings, q, fig_queue)
|
88
47
|
except Exception as e:
|
89
|
-
|
90
|
-
|
48
|
+
q.put(f"Error during processing: {e}")
|
49
|
+
traceback.print_exc()
|
91
50
|
finally:
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
def start_thread(q, fig_queue):
|
51
|
+
stop_requested.value = 1
|
52
|
+
|
53
|
+
@log_function_call
|
54
|
+
def start_process(q, fig_queue):
|
98
55
|
global thread_control
|
99
|
-
thread_control
|
100
|
-
|
56
|
+
if thread_control.get("run_thread") is not None:
|
57
|
+
initiate_abort()
|
58
|
+
|
59
|
+
stop_requested = Value('i', 0) # multiprocessing shared value for inter-process communication
|
60
|
+
thread_control["stop_requested"] = stop_requested
|
61
|
+
thread_control["run_thread"] = Process(target=run_mask_gui, args=(q, fig_queue, stop_requested))
|
101
62
|
thread_control["run_thread"].start()
|
102
63
|
|
103
64
|
def import_settings(scrollable_frame):
|
104
|
-
global vars_dict
|
65
|
+
global vars_dict
|
105
66
|
|
106
67
|
csv_file_path = filedialog.askopenfilename(filetypes=[("CSV files", "*.csv")])
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
with open(csv_file_path, newline='') as csvfile:
|
114
|
-
reader = csv.DictReader(csvfile)
|
115
|
-
for row in reader:
|
116
|
-
key = row['Key']
|
117
|
-
value = row['Value']
|
118
|
-
# Evaluate the value safely using safe_literal_eval
|
119
|
-
imported_variables[key] = safe_literal_eval(value)
|
120
|
-
|
121
|
-
# Track changed variables and apply the imported ones, printing changes as we go
|
122
|
-
for key, var in vars_dict.items():
|
123
|
-
if key in imported_variables and var.get() != imported_variables[key]:
|
124
|
-
print(f"Updating '{key}' from '{var.get()}' to '{imported_variables[key]}'")
|
125
|
-
var.set(imported_variables[key])
|
68
|
+
csv_settings = read_settings_from_csv(csv_file_path)
|
69
|
+
variables = mask_variables()
|
70
|
+
#variables = add_mask_gui_defaults(variables)
|
71
|
+
new_settings = update_settings_from_csv(variables, csv_settings)
|
72
|
+
vars_dict = generate_fields(new_settings, scrollable_frame)
|
126
73
|
|
127
74
|
@log_function_call
|
128
75
|
def initiate_mask_root(width, height):
|
@@ -145,13 +92,13 @@ def initiate_mask_root(width, height):
|
|
145
92
|
root.attributes('-fullscreen', True)
|
146
93
|
root.geometry(f"{width}x{height}")
|
147
94
|
root.title("SpaCer: generate masks")
|
148
|
-
fig_queue =
|
149
|
-
|
95
|
+
fig_queue = Queue()
|
96
|
+
|
150
97
|
def _process_fig_queue():
|
151
98
|
global canvas
|
152
99
|
try:
|
153
100
|
while not fig_queue.empty():
|
154
|
-
clear_canvas()
|
101
|
+
clear_canvas(canvas)
|
155
102
|
fig = fig_queue.get_nowait()
|
156
103
|
#set_fig_text_properties(fig, font_size=8)
|
157
104
|
for ax in fig.get_axes():
|
@@ -167,13 +114,12 @@ def initiate_mask_root(width, height):
|
|
167
114
|
fig_width, fig_height = canvas_widget.winfo_width(), canvas_widget.winfo_height()
|
168
115
|
fig.set_size_inches(fig_width / fig.dpi, fig_height / fig.dpi, forward=True)
|
169
116
|
canvas.draw_idle()
|
170
|
-
except queue.Empty:
|
171
|
-
pass
|
172
117
|
except Exception as e:
|
173
|
-
|
118
|
+
traceback.print_exc()
|
119
|
+
#pass
|
174
120
|
finally:
|
175
121
|
canvas_widget.after(100, _process_fig_queue)
|
176
|
-
|
122
|
+
|
177
123
|
# Process queue for console output
|
178
124
|
def _process_console_queue():
|
179
125
|
while not q.empty():
|
@@ -211,22 +157,26 @@ def initiate_mask_root(width, height):
|
|
211
157
|
canvas_widget = canvas.get_tk_widget()
|
212
158
|
horizontal_container.add(canvas_widget, stretch="always")
|
213
159
|
canvas.draw()
|
160
|
+
canvas.figure = figure
|
214
161
|
|
215
162
|
# Console output setup below the settings
|
216
163
|
console_output = scrolledtext.ScrolledText(vertical_container, height=10)
|
217
164
|
vertical_container.add(console_output, stretch="always")
|
218
165
|
|
219
166
|
# Queue and redirection setup for updating console output safely
|
220
|
-
q =
|
167
|
+
q = Queue()
|
221
168
|
sys.stdout = StdoutRedirector(console_output)
|
222
169
|
sys.stderr = StdoutRedirector(console_output)
|
223
170
|
|
224
171
|
# This is your GUI setup where you create the Run button
|
225
|
-
run_button = ttk.Button(scrollable_frame.scrollable_frame, text="Run",command=lambda:
|
226
|
-
run_button.grid(row=
|
172
|
+
run_button = ttk.Button(scrollable_frame.scrollable_frame, text="Run",command=lambda: start_process(q, fig_queue))
|
173
|
+
run_button.grid(row=45, column=0, pady=10)
|
227
174
|
|
228
175
|
abort_button = ttk.Button(scrollable_frame.scrollable_frame, text="Abort", command=initiate_abort)
|
229
|
-
abort_button.grid(row=
|
176
|
+
abort_button.grid(row=45, column=1, pady=10)
|
177
|
+
|
178
|
+
progress_label = ttk.Label(scrollable_frame.scrollable_frame, text="Processing: 0%", background="#333333", foreground="white")
|
179
|
+
progress_label.grid(row=41, column=0, columnspan=2, sticky="ew", pady=(5, 0))
|
230
180
|
|
231
181
|
# Create the Import Settings button
|
232
182
|
import_btn = tk.Button(root, text="Import Settings", command=lambda: import_settings(scrollable_frame))
|
@@ -236,12 +186,14 @@ def initiate_mask_root(width, height):
|
|
236
186
|
_process_fig_queue()
|
237
187
|
create_dark_mode(root, style, console_output)
|
238
188
|
|
189
|
+
root.after(100, lambda: main_thread_update_function(root, q, fig_queue, canvas_widget, progress_label))
|
190
|
+
|
239
191
|
return root, vars_dict
|
240
192
|
|
241
193
|
def gui_mask():
|
242
194
|
global vars_dict, root
|
243
195
|
root, vars_dict = initiate_mask_root(1000, 1500)
|
244
196
|
root.mainloop()
|
245
|
-
|
197
|
+
|
246
198
|
if __name__ == "__main__":
|
247
199
|
gui_mask()
|
spacr/gui_measure_app.py
CHANGED
@@ -7,7 +7,7 @@ import matplotlib.pyplot as plt
|
|
7
7
|
matplotlib.use('Agg') # Use the non-GUI Agg backend
|
8
8
|
from multiprocessing import Process, Queue, Value
|
9
9
|
from ttkthemes import ThemedTk
|
10
|
-
from tkinter import filedialog
|
10
|
+
from tkinter import filedialog, StringVar, BooleanVar, IntVar, DoubleVar, Tk
|
11
11
|
|
12
12
|
try:
|
13
13
|
ctypes.windll.shcore.SetProcessDpiAwareness(True)
|
@@ -15,19 +15,18 @@ except AttributeError:
|
|
15
15
|
pass
|
16
16
|
|
17
17
|
from .logger import log_function_call
|
18
|
-
from .gui_utils import ScrollableFrame, StdoutRedirector, set_dark_style, set_default_font,
|
19
|
-
from .gui_utils import
|
18
|
+
from .gui_utils import ScrollableFrame, StdoutRedirector, process_stdout_stderr, set_dark_style, set_default_font, generate_fields, create_dark_mode, main_thread_update_function
|
19
|
+
from .gui_utils import measure_variables, measure_crop_wrapper, clear_canvas, safe_literal_eval, check_measure_gui_settings, read_settings_from_csv, update_settings_from_csv
|
20
20
|
|
21
21
|
thread_control = {"run_thread": None, "stop_requested": False}
|
22
22
|
|
23
|
-
|
24
23
|
@log_function_call
|
25
24
|
def run_measure_gui(q, fig_queue, stop_requested):
|
26
25
|
global vars_dict
|
27
26
|
process_stdout_stderr(q)
|
28
27
|
try:
|
28
|
+
print('hello')
|
29
29
|
settings = check_measure_gui_settings(vars_dict)
|
30
|
-
settings = add_measure_gui_defaults(settings)
|
31
30
|
#for key in settings:
|
32
31
|
# value = settings[key]
|
33
32
|
# print(key, value, type(value))
|
@@ -61,29 +60,15 @@ def initiate_abort():
|
|
61
60
|
thread_control["run_thread"].terminate()
|
62
61
|
thread_control["run_thread"] = None
|
63
62
|
|
63
|
+
@log_function_call
|
64
64
|
def import_settings(scrollable_frame):
|
65
|
-
global vars_dict
|
65
|
+
global vars_dict
|
66
66
|
|
67
67
|
csv_file_path = filedialog.askopenfilename(filetypes=[("CSV files", "*.csv")])
|
68
|
-
|
69
|
-
|
70
|
-
|
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])
|
68
|
+
csv_settings = read_settings_from_csv(csv_file_path)
|
69
|
+
variables = measure_variables()
|
70
|
+
new_settings = update_settings_from_csv(variables, csv_settings)
|
71
|
+
vars_dict = generate_fields(new_settings, scrollable_frame)
|
87
72
|
|
88
73
|
@log_function_call
|
89
74
|
def initiate_measure_root(width, height):
|
@@ -135,7 +120,7 @@ def initiate_measure_root(width, height):
|
|
135
120
|
#pass
|
136
121
|
finally:
|
137
122
|
canvas_widget.after(100, _process_fig_queue)
|
138
|
-
|
123
|
+
|
139
124
|
# Process queue for console output
|
140
125
|
def _process_console_queue():
|
141
126
|
while not q.empty():
|
@@ -173,6 +158,7 @@ def initiate_measure_root(width, height):
|
|
173
158
|
canvas_widget = canvas.get_tk_widget()
|
174
159
|
horizontal_container.add(canvas_widget, stretch="always")
|
175
160
|
canvas.draw()
|
161
|
+
canvas.figure = figure
|
176
162
|
|
177
163
|
# Console output setup below the settings
|
178
164
|
console_output = scrolledtext.ScrolledText(vertical_container, height=10)
|
@@ -190,7 +176,7 @@ def initiate_measure_root(width, height):
|
|
190
176
|
abort_button = ttk.Button(scrollable_frame.scrollable_frame, text="Abort", command=initiate_abort)
|
191
177
|
abort_button.grid(row=40, column=1, pady=10)
|
192
178
|
|
193
|
-
progress_label = ttk.Label(scrollable_frame.scrollable_frame, text="Progress:
|
179
|
+
progress_label = ttk.Label(scrollable_frame.scrollable_frame, text="Progress: ", background="#333333", foreground="white")
|
194
180
|
progress_label.grid(row=41, column=0, columnspan=2, sticky="ew", pady=(5, 0))
|
195
181
|
|
196
182
|
# Create the Import Settings button
|
@@ -201,7 +187,7 @@ def initiate_measure_root(width, height):
|
|
201
187
|
_process_fig_queue()
|
202
188
|
create_dark_mode(root, style, console_output)
|
203
189
|
|
204
|
-
root.after(100, lambda: main_thread_update_function(root, q, fig_queue, canvas_widget, progress_label))
|
190
|
+
#root.after(100, lambda: main_thread_update_function(root, q, fig_queue, canvas_widget, progress_label))
|
205
191
|
|
206
192
|
return root, vars_dict
|
207
193
|
|
spacr/gui_sim_app.py
ADDED
File without changes
|