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/gui_mask_app.py CHANGED
@@ -1,15 +1,14 @@
1
- import spacr, sys, queue, ctypes, csv, matplotlib
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, mask_variables, generate_fields, check_mask_gui_settings, add_mask_gui_defaults
21
- from .gui_utils import safe_literal_eval
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
- class ScrollableFrame(ttk.Frame):
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, q
56
- thread_control["stop_requested"] = True
57
- if thread_control["run_thread"] is not None:
58
- thread_control["run_thread"].join(timeout=1) # Timeout after 1 second
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
- q.put("Thread didn't terminate within timeout.")
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
- def run_mask_gui(q, fig_queue):
81
- global vars_dict, thread_control
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
- while not thread_control["stop_requested"]:
84
- settings = check_mask_gui_settings(vars_dict)
85
- settings = add_mask_gui_defaults(settings)
86
- preprocess_generate_masks_wrapper(settings['src'], settings=settings, advanced_settings={})
87
- thread_control["stop_requested"] = True
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
- pass
90
- #q.put(f"Error during processing: {e}")
48
+ q.put(f"Error during processing: {e}")
49
+ traceback.print_exc()
91
50
  finally:
92
- # Ensure the thread is marked as not running anymore
93
- thread_control["run_thread"] = None
94
- # Reset the stop_requested flag for future operations
95
- thread_control["stop_requested"] = False
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["stop_requested"] = False # Reset the stop signal
100
- thread_control["run_thread"] = Thread(target=run_mask_gui, args=(q, fig_queue))
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, original_variables_structure
65
+ global vars_dict
105
66
 
106
67
  csv_file_path = filedialog.askopenfilename(filetypes=[("CSV files", "*.csv")])
107
-
108
- if not csv_file_path:
109
- return
110
-
111
- imported_variables = {}
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 = queue.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
- pass
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 = queue.Queue()
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: start_thread(q, fig_queue))
226
- run_button.grid(row=40, column=0, pady=10)
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=40, column=1, pady=10)
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, measure_variables, generate_fields, create_dark_mode, check_measure_gui_settings, add_measure_gui_defaults, main_thread_update_function
19
- from .gui_utils import process_stdout_stderr, measure_crop_wrapper, clear_canvas, safe_literal_eval
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, original_variables_structure
65
+ global vars_dict
66
66
 
67
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])
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: 0%", background="#333333", foreground="white")
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