spacr 0.2.61__py3-none-any.whl → 0.2.66__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 CHANGED
@@ -17,7 +17,6 @@ from . import gui_utils
17
17
  from . import gui_elements
18
18
  from . import gui_core
19
19
  from . import gui
20
- from . import gui
21
20
  from . import app_make_masks
22
21
  from . import app_mask
23
22
  from . import app_measure
@@ -35,7 +34,7 @@ __all__ = [
35
34
  "plot",
36
35
  "measure",
37
36
  "sim",
38
- "sequencing"
37
+ "sequencing",
39
38
  "timelapse",
40
39
  "deep_spacr",
41
40
  "app_annotate",
@@ -43,7 +42,6 @@ __all__ = [
43
42
  "gui_elements",
44
43
  "gui_core",
45
44
  "gui",
46
- "gui",
47
45
  "app_make_masks",
48
46
  "app_mask",
49
47
  "app_measure",
@@ -53,13 +51,5 @@ __all__ = [
53
51
  "logger"
54
52
  ]
55
53
 
56
- # Check for CUDA GPU availability
57
- if torch.cuda.is_available():
58
- from . import graph_learning
59
- __all__.append("graph_learning")
60
- logging.info("CUDA GPU detected. Graph learning module loaded.")
61
- else:
62
- logging.info("No CUDA GPU detected. Graph learning module not loaded.")
63
-
64
54
  logging.basicConfig(filename='spacr.log', level=logging.INFO,
65
55
  format='%(asctime)s:%(levelname)s:%(message)s')
spacr/gui.py CHANGED
@@ -7,6 +7,15 @@ from .gui_core import initiate_root
7
7
  class MainApp(tk.Tk):
8
8
  def __init__(self, default_app=None):
9
9
  super().__init__()
10
+
11
+ # Initialize the window
12
+ self.geometry("100x100")
13
+ self.update_idletasks()
14
+
15
+ # Expand the window to fullscreen
16
+ self.attributes('-fullscreen', True)
17
+ self.update_idletasks()
18
+
10
19
  width = self.winfo_screenwidth()
11
20
  height = self.winfo_screenheight()
12
21
  self.geometry(f"{width}x{height}")
spacr/gui_core.py CHANGED
@@ -83,12 +83,22 @@ def toggle_settings(button_scrollable_frame):
83
83
  def process_fig_queue():
84
84
  global canvas, fig_queue, canvas_widget, parent_frame, uppdate_frequency, figures, figure_index
85
85
 
86
+ from .gui_elements import standardize_figure
86
87
  try:
87
88
  while not fig_queue.empty():
88
89
  fig = fig_queue.get_nowait()
90
+
91
+ if fig is None:
92
+ print("Warning: Retrieved a None figure from fig_queue.")
93
+ continue # Skip processing if the figure is None
94
+
95
+ # Standardize the figure appearance before adding it to the list
96
+ standardize_figure(fig)
97
+
89
98
  figures.append(fig)
90
- figure_index = len(figures) - 1
91
- display_figure(fig)
99
+ if figure_index == len(figures) - 2:
100
+ figure_index += 1
101
+ display_figure(fig)
92
102
  except Exception as e:
93
103
  traceback.print_exc()
94
104
  finally:
@@ -98,8 +108,23 @@ def process_fig_queue():
98
108
  def display_figure(fig):
99
109
  global canvas, canvas_widget
100
110
 
111
+ from .gui_elements import modify_figure_properties, save_figure_as_format, modify_figure
112
+
113
+ # Apply the dark style to the context menu
114
+ style_out = set_dark_style(ttk.Style())
115
+ bg_color = style_out['bg_color']
116
+ fg_color = style_out['fg_color']
117
+
118
+ # Initialize the scale factor for zooming
119
+ scale_factor = 1.0
120
+
121
+ # Save the original x and y limits of the first axis (assuming all axes have the same limits)
122
+ original_xlim = [ax.get_xlim() for ax in fig.get_axes()]
123
+ original_ylim = [ax.get_ylim() for ax in fig.get_axes()]
124
+
101
125
  # Clear previous canvas content
102
- canvas.get_tk_widget().destroy()
126
+ if canvas:
127
+ canvas.get_tk_widget().destroy()
103
128
 
104
129
  # Create a new canvas for the figure
105
130
  new_canvas = FigureCanvasTkAgg(fig, master=canvas_widget.master)
@@ -109,154 +134,141 @@ def display_figure(fig):
109
134
  # Update the global canvas and canvas_widget references
110
135
  canvas = new_canvas
111
136
  canvas_widget = new_canvas.get_tk_widget()
112
-
113
- # Apply the dark style to the context menu
114
- style_out = set_dark_style(ttk.Style())
115
- bg_color = style_out['bg_color']
116
- fg_color = style_out['fg_color']
117
-
118
- # Define the save functions for the context menu
119
- def save_figure_as_format(format):
120
- file_path = filedialog.asksaveasfilename(defaultextension=f".{format}", filetypes=[(f"{format.upper()} files", f"*.{format}"), ("All files", "*.*")])
121
- if file_path:
122
- fig.savefig(file_path, format=format)
123
-
124
- def modify_figure():
125
- def apply_modifications():
126
- try:
127
- x_width = float(x_width_var.get())
128
- y_height = float(y_height_var.get())
129
- line_width = float(line_width_var.get())
130
- font_size = int(font_size_var.get())
131
- modify_figure_properties(fig, x_width=x_width, y_height=y_height, line_width=line_width)
132
- for ax in fig.get_axes():
133
- for label in ax.get_xticklabels() + ax.get_yticklabels():
134
- label.set_fontsize(font_size)
135
- ax.title.set_fontsize(font_size)
136
- ax.xaxis.label.set_fontsize(font_size)
137
- ax.yaxis.label.set_fontsize(font_size)
138
- canvas.draw_idle() # Redraw the canvas after modifications
139
- except ValueError:
140
- print("Invalid input; please enter numeric values.")
141
-
142
- # Create a new window for user input
143
- modify_window = tk.Toplevel()
144
- modify_window.title("Modify Figure Properties")
145
-
146
- # Apply dark style to the popup window
147
- modify_window.configure(bg=bg_color)
148
-
149
- # Create and style the input fields
150
- tk.Label(modify_window, text="X Axis Width:", bg=bg_color, fg=fg_color).grid(row=0, column=0, padx=10, pady=5)
151
- x_width_var = tk.StringVar()
152
- tk.Entry(modify_window, textvariable=x_width_var, bg=bg_color, fg=fg_color).grid(row=0, column=1, padx=10, pady=5)
153
-
154
- tk.Label(modify_window, text="Y Axis Height:", bg=bg_color, fg=fg_color).grid(row=1, column=0, padx=10, pady=5)
155
- y_height_var = tk.StringVar()
156
- tk.Entry(modify_window, textvariable=y_height_var, bg=bg_color, fg=fg_color).grid(row=1, column=1, padx=10, pady=5)
157
-
158
- tk.Label(modify_window, text="Line Width:", bg=bg_color, fg=fg_color).grid(row=2, column=0, padx=10, pady=5)
159
- line_width_var = tk.StringVar()
160
- tk.Entry(modify_window, textvariable=line_width_var, bg=bg_color, fg=fg_color).grid(row=2, column=1, padx=10, pady=5)
161
-
162
- tk.Label(modify_window, text="Font Size:", bg=bg_color, fg=fg_color).grid(row=3, column=0, padx=10, pady=5)
163
- font_size_var = tk.StringVar()
164
- tk.Entry(modify_window, textvariable=font_size_var, bg=bg_color, fg=fg_color).grid(row=3, column=1, padx=10, pady=5)
165
-
166
- # Apply button
167
- apply_button = tk.Button(modify_window, text="Apply", command=apply_modifications, bg=bg_color, fg=fg_color)
168
- apply_button.grid(row=4, column=0, columnspan=2, pady=10)
137
+ canvas_widget.configure(bg=bg_color)
169
138
 
170
139
  # Create the context menu
171
140
  context_menu = tk.Menu(canvas_widget, tearoff=0, bg=bg_color, fg=fg_color)
172
- context_menu.add_command(label="Save Figure as PDF", command=lambda: save_figure_as_format('pdf'))
173
- context_menu.add_command(label="Save Figure as PNG", command=lambda: save_figure_as_format('png'))
174
- context_menu.add_command(label="Modify Figure", command=modify_figure)
141
+ context_menu.add_command(label="Save Figure as PDF", command=lambda: save_figure_as_format(fig, 'pdf'))
142
+ context_menu.add_command(label="Save Figure as PNG", command=lambda: save_figure_as_format(fig, 'png'))
143
+ context_menu.add_command(label="Modify Figure", command=lambda: modify_figure(fig))
144
+ context_menu.add_command(label="Reset Zoom", command=lambda: reset_zoom(fig)) # Add Reset Zoom option
145
+
146
+ def reset_zoom(fig):
147
+ global scale_factor
148
+ scale_factor = 1.0 # Reset the scale factor
149
+
150
+ for i, ax in enumerate(fig.get_axes()):
151
+ ax.set_xlim(original_xlim[i])
152
+ ax.set_ylim(original_ylim[i])
153
+ fig.canvas.draw_idle()
175
154
 
176
155
  def on_right_click(event):
177
156
  context_menu.post(event.x_root, event.y_root)
178
157
 
179
- new_canvas.get_tk_widget().bind("<Button-3>", on_right_click)
158
+ def on_hover(event):
159
+ widget_width = event.widget.winfo_width()
160
+ x_position = event.x
161
+
162
+ if x_position < widget_width / 2:
163
+ canvas_widget.config(cursor="hand2")
164
+ else:
165
+ canvas_widget.config(cursor="hand2")
166
+
167
+ def on_leave(event):
168
+ canvas_widget.config(cursor="arrow")
169
+
170
+ def flash_feedback(side):
171
+ flash = tk.Toplevel(canvas_widget.master)
172
+ flash.overrideredirect(True)
173
+ flash_width = int(canvas_widget.winfo_width() / 2)
174
+ flash_height = canvas_widget.winfo_height()
175
+ flash.configure(bg='white')
176
+ flash.attributes('-alpha', 0.9)
177
+
178
+ if side == "left":
179
+ flash.geometry(f"{flash_width}x{flash_height}+{canvas_widget.winfo_rootx()}+{canvas_widget.winfo_rooty()}")
180
+ else:
181
+ flash.geometry(f"{flash_width}x{flash_height}+{canvas_widget.winfo_rootx() + flash_width}+{canvas_widget.winfo_rooty()}")
182
+
183
+ flash.lift()
184
+
185
+ # Ensure the flash covers the correct area only
186
+ flash.update_idletasks()
187
+ flash.after(100, flash.destroy)
188
+
189
+ def on_click(event):
190
+ widget_width = event.widget.winfo_width()
191
+ x_position = event.x
192
+
193
+ if x_position < widget_width / 2:
194
+ #flash_feedback("left")
195
+ show_previous_figure()
196
+ else:
197
+ #flash_feedback("right")
198
+ show_next_figure()
199
+
200
+ def zoom(event):
201
+ nonlocal scale_factor
202
+
203
+ zoom_speed = 0.1 # Adjust the zoom speed for smoother experience
204
+
205
+ # Adjust zoom factor based on the operating system and mouse event
206
+ if event.num == 4 or event.delta > 0: # Scroll up
207
+ scale_factor *= (1 + zoom_speed)
208
+ elif event.num == 5 or event.delta < 0: # Scroll down
209
+ scale_factor /= (1 + zoom_speed)
210
+
211
+ # Get mouse position relative to the figure
212
+ x_mouse, y_mouse = event.x, event.y
213
+ x_ratio = x_mouse / canvas_widget.winfo_width()
214
+ y_ratio = y_mouse / canvas_widget.winfo_height()
215
+
216
+ for ax in fig.get_axes():
217
+ xlim = ax.get_xlim()
218
+ ylim = ax.get_ylim()
219
+
220
+ # Calculate the new limits
221
+ x_center = xlim[0] + x_ratio * (xlim[1] - xlim[0])
222
+ y_center = ylim[0] + (1 - y_ratio) * (ylim[1] - ylim[0])
223
+
224
+ x_range = (xlim[1] - xlim[0]) * scale_factor
225
+ y_range = (ylim[1] - ylim[0]) * scale_factor
226
+
227
+ ax.set_xlim([x_center - x_range * x_ratio, x_center + x_range * (1 - x_ratio)])
228
+ ax.set_ylim([y_center - y_range * (1 - y_ratio), y_center + y_range * y_ratio])
229
+
230
+ # Redraw the figure
231
+ fig.canvas.draw_idle()
232
+
233
+ # Bind events for hover, click interactions, and zoom
234
+ canvas_widget.bind("<Motion>", on_hover)
235
+ canvas_widget.bind("<Leave>", on_leave)
236
+ canvas_widget.bind("<Button-1>", on_click)
237
+ canvas_widget.bind("<Button-3>", on_right_click)
238
+
239
+ # Bind mouse wheel for zooming (cross-platform)
240
+ canvas_widget.bind("<MouseWheel>", zoom) # Windows
241
+ canvas_widget.bind("<Button-4>", zoom) # Linux/macOS Scroll Up
242
+ canvas_widget.bind("<Button-5>", zoom) # Linux/macOS Scroll Down
180
243
 
181
244
  def clear_unused_figures():
182
245
  global figures, figure_index
183
246
 
184
247
  lower_bound = max(0, figure_index - 20)
185
248
  upper_bound = min(len(figures), figure_index + 20)
186
-
187
249
  # Clear figures outside of the +/- 20 range
188
250
  figures = deque([fig for i, fig in enumerate(figures) if lower_bound <= i <= upper_bound])
189
-
190
251
  # Update the figure index after clearing
191
252
  figure_index = min(max(figure_index, 0), len(figures) - 1)
192
253
 
193
254
  def show_previous_figure():
194
- global figure_index, figures
255
+ global figure_index, figures, fig_queue
195
256
  if figure_index is not None and figure_index > 0:
196
257
  figure_index -= 1
197
258
  display_figure(figures[figure_index])
198
259
  clear_unused_figures()
199
260
 
200
261
  def show_next_figure():
201
- global figure_index, figures
262
+ global figure_index, figures, fig_queue
202
263
  if figure_index is not None and figure_index < len(figures) - 1:
203
264
  figure_index += 1
204
265
  display_figure(figures[figure_index])
205
266
  clear_unused_figures()
206
-
207
- def save_figure_as_format(fig, file_format):
208
- file_path = filedialog.asksaveasfilename(defaultextension=f".{file_format}", filetypes=[(f"{file_format.upper()} files", f"*.{file_format}"), ("All files", "*.*")])
209
- if file_path:
210
- try:
211
- fig.savefig(file_path, format=file_format)
212
- print(f"Figure saved as {file_format.upper()} at {file_path}")
213
- except Exception as e:
214
- print(f"Error saving figure: {e}")
215
-
216
- def modify_figure_properties(fig, x_width=None, y_height=None, line_width=None):
217
- """
218
- Modifies the properties of the figure, including axis dimensions and line widths.
219
-
220
- Parameters:
221
- - fig: The matplotlib figure object to modify.
222
- - x_width: Desired width for the x-axis (optional).
223
- - y_height: Desired height for the y-axis (optional).
224
- - line_width: Desired line width for all lines (optional).
225
- """
226
- for ax in fig.get_axes():
227
- # Scaling the figure
228
- if x_width is not None or y_height is not None:
229
- # Get the current axis limits
230
- current_xlim = ax.get_xlim()
231
- current_ylim = ax.get_ylim()
232
-
233
- # Set new limits
234
- if x_width is not None:
235
- scale_factor_x = x_width / (current_xlim[1] - current_xlim[0])
236
- else:
237
- scale_factor_x = 1
238
-
239
- if y_height is not None:
240
- scale_factor_y = y_height / (current_ylim[1] - current_ylim[0])
241
- else:
242
- scale_factor_y = 1
243
-
244
- # Adjust the figure size and elements proportionally
245
- fig.set_size_inches(fig.get_size_inches() * scale_factor_x * scale_factor_y, forward=True)
246
- ax.set_xlim(left=current_xlim[0] * scale_factor_x, right=current_xlim[1] * scale_factor_x)
247
- ax.set_ylim(bottom=current_ylim[0] * scale_factor_y, top=current_ylim[1] * scale_factor_y)
248
-
249
- # Adjust line width and other elements if specified
250
- if line_width is not None:
251
- for line in ax.get_lines():
252
- line.set_linewidth(line_width)
253
- for spine in ax.spines.values(): # Modify width of spines (e.g., scale bars)
254
- spine.set_linewidth(line_width)
255
- ax.tick_params(width=line_width) # Modify width of ticks
256
- for text in ax.get_xticklabels() + ax.get_yticklabels():
257
- text.set_fontsize(ax.get_xticklabels()[0].get_fontsize())
258
-
259
- fig.canvas.draw_idle()
267
+ elif figure_index == len(figures) - 1 and not fig_queue.empty():
268
+ fig = fig_queue.get_nowait()
269
+ figures.append(fig)
270
+ figure_index += 1
271
+ display_figure(fig)
260
272
 
261
273
  def set_globals(thread_control_var, q_var, console_output_var, parent_frame_var, vars_dict_var, canvas_var, canvas_widget_var, scrollable_frame_var, fig_queue_var, figures_var, figure_index_var, progress_bar_var, usage_bars_var, fig_memory_limit_var, figure_current_memory_usage_var):
262
274
  global thread_control, q, console_output, parent_frame, vars_dict, canvas, canvas_widget, scrollable_frame, fig_queue, figures, figure_index, progress_bar, usage_bars, fig_memory_limit, figure_current_memory_usage
@@ -416,7 +428,7 @@ def setup_plot_section(vertical_container):
416
428
  plot_frame.grid_columnconfigure(0, weight=1)
417
429
 
418
430
  canvas.draw()
419
- canvas.figure = figure
431
+ canvas.figure = figure # Ensure that the figure is linked to the canvas
420
432
  style_out = set_dark_style(ttk.Style())
421
433
 
422
434
  figure.patch.set_facecolor(style_out['bg_color'])
@@ -425,19 +437,6 @@ def setup_plot_section(vertical_container):
425
437
  widgets = [canvas_widget]
426
438
  style = ttk.Style(vertical_container)
427
439
  _ = set_dark_style(style, containers=containers, widgets=widgets)
428
-
429
- # Add navigation buttons using spacrButton
430
- button_frame = tk.Frame(plot_frame, bg=style_out['bg_color'])
431
- button_frame.grid(row=1, column=0, sticky='ew', pady=5)
432
-
433
- size_dict = set_element_size()
434
-
435
- btn_size = int(size_dict['btn_size']*0.75)
436
- prev_button = spacrButton(button_frame, text="Previous", command=show_previous_figure, bg=style_out['bg_color'], show_text=False, size=btn_size, animation=False)
437
- prev_button.pack(side='left', padx=5)
438
-
439
- next_button = spacrButton(button_frame, text="Next", command=show_next_figure, bg=style_out['bg_color'], show_text=False, size=btn_size, animation=False)
440
- next_button.pack(side='right', padx=5)
441
440
 
442
441
  return canvas, canvas_widget
443
442
 
@@ -842,7 +841,7 @@ def initiate_root(parent, settings_type='mask'):
842
841
  from .gui_utils import setup_frame
843
842
  from .settings import descriptions
844
843
 
845
- uppdate_frequency = 1000
844
+ uppdate_frequency = 100
846
845
 
847
846
  # Start tracemalloc and initialize global variables
848
847
  tracemalloc.start()
spacr/gui_elements.py CHANGED
@@ -2,6 +2,7 @@ import os, threading, time, sqlite3, webbrowser, pyautogui
2
2
  import tkinter as tk
3
3
  from tkinter import ttk
4
4
  import tkinter.font as tkFont
5
+ from tkinter import filedialog
5
6
  from tkinter import font
6
7
  from queue import Queue
7
8
  from tkinter import Label, Frame, Button
@@ -16,6 +17,7 @@ from skimage.draw import polygon, line
16
17
  from skimage.transform import resize
17
18
  from scipy.ndimage import binary_fill_holes, label
18
19
  from tkinter import ttk, scrolledtext
20
+ fig = None
19
21
 
20
22
  def set_element_size():
21
23
 
@@ -2081,6 +2083,7 @@ class AnnotateApp:
2081
2083
  print(f"median threshold measurement: {np.median(df[self.measurement])}")
2082
2084
  df = df[df[f'threshold_measurement_{idx}'] > thd]
2083
2085
  after = len(df)
2086
+
2084
2087
  elif isinstance(self.measurement, list):
2085
2088
  df['threshold_measurement'] = df[self.measurement[0]]/df[self.measurement[1]]
2086
2089
  print(f"mean threshold measurement: {np.mean(df['threshold_measurement'])}")
@@ -2089,6 +2092,7 @@ class AnnotateApp:
2089
2092
  after = len(df)
2090
2093
  self.measurement = 'threshold_measurement'
2091
2094
  print(f'Removed: {before-after} rows, retained {after}')
2095
+
2092
2096
  else:
2093
2097
  print(f"mean threshold measurement: {np.mean(df[self.measurement])}")
2094
2098
  print(f"median threshold measurement: {np.median(df[self.measurement])}")
@@ -2370,4 +2374,300 @@ def create_menu_bar(root):
2370
2374
  app_menu.add_command(label="Exit", command=root.quit)
2371
2375
 
2372
2376
  # Configure the menu for the root window
2373
- root.config(menu=menu_bar)
2377
+ root.config(menu=menu_bar)
2378
+
2379
+ def standardize_figure(fig):
2380
+ from .gui_elements import set_dark_style
2381
+ from matplotlib.font_manager import FontProperties
2382
+
2383
+ style_out = set_dark_style(ttk.Style())
2384
+ bg_color = style_out['bg_color']
2385
+ fg_color = style_out['fg_color']
2386
+ font_size = style_out['font_size']
2387
+ font_loader = style_out['font_loader']
2388
+
2389
+ # Get the custom font path from the font loader
2390
+ font_path = font_loader.font_path
2391
+ font_prop = FontProperties(fname=font_path, size=font_size)
2392
+
2393
+ """
2394
+ Standardizes the appearance of the figure:
2395
+ - Font size: from style
2396
+ - Font color: from style
2397
+ - Font family: custom OpenSans from font_loader
2398
+ - Removes top and right spines
2399
+ - Figure and subplot background: from style
2400
+ - Line width: 1
2401
+ - Line color: from style
2402
+ """
2403
+
2404
+ for ax in fig.get_axes():
2405
+ # Set font properties for title and labels
2406
+ ax.title.set_fontsize(font_size)
2407
+ ax.title.set_color(fg_color)
2408
+ ax.title.set_fontproperties(font_prop)
2409
+
2410
+ ax.xaxis.label.set_fontsize(font_size)
2411
+ ax.xaxis.label.set_color(fg_color)
2412
+ ax.xaxis.label.set_fontproperties(font_prop)
2413
+
2414
+ ax.yaxis.label.set_fontsize(font_size)
2415
+ ax.yaxis.label.set_color(fg_color)
2416
+ ax.yaxis.label.set_fontproperties(font_prop)
2417
+
2418
+ # Set font properties for tick labels
2419
+ for label in ax.get_xticklabels() + ax.get_yticklabels():
2420
+ label.set_fontsize(font_size)
2421
+ label.set_color(fg_color)
2422
+ label.set_fontproperties(font_prop)
2423
+
2424
+ # Remove top and right spines
2425
+ ax.spines['top'].set_visible(False)
2426
+ ax.spines['right'].set_visible(False)
2427
+ ax.spines['left'].set_visible(True)
2428
+ ax.spines['bottom'].set_visible(True)
2429
+
2430
+ # Set spine line width and color
2431
+ for spine in ax.spines.values():
2432
+ spine.set_linewidth(1)
2433
+ spine.set_edgecolor(fg_color)
2434
+
2435
+ # Set line width and color
2436
+ for line in ax.get_lines():
2437
+ line.set_linewidth(1)
2438
+ line.set_color(fg_color)
2439
+
2440
+ # Set subplot background color
2441
+ ax.set_facecolor(bg_color)
2442
+
2443
+ # Adjust the grid if needed
2444
+ ax.grid(True, color='gray', linestyle='--', linewidth=0.5)
2445
+
2446
+ # Set figure background color
2447
+ fig.patch.set_facecolor(bg_color)
2448
+
2449
+ fig.canvas.draw_idle()
2450
+
2451
+ def modify_figure_properties(fig, scale_x=None, scale_y=None, line_width=None, font_size=None, x_lim=None, y_lim=None, grid=False, legend=None, title=None, x_label_rotation=None, remove_axes=False, bg_color=None, text_color=None, line_color=None):
2452
+ """
2453
+ Modifies the properties of the figure, including scaling, line widths, font sizes, axis limits, x-axis label rotation, background color, text color, line color, and other common options.
2454
+
2455
+ Parameters:
2456
+ - fig: The Matplotlib figure object to modify.
2457
+ - scale_x: Scaling factor for the width of subplots (optional).
2458
+ - scale_y: Scaling factor for the height of subplots (optional).
2459
+ - line_width: Desired line width for all lines (optional).
2460
+ - font_size: Desired font size for all text (optional).
2461
+ - x_lim: Tuple specifying the x-axis limits (min, max) (optional).
2462
+ - y_lim: Tuple specifying the y-axis limits (min, max) (optional).
2463
+ - grid: Boolean to add grid lines to the plot (optional).
2464
+ - legend: Boolean to show/hide the legend (optional).
2465
+ - title: String to set as the title of the plot (optional).
2466
+ - x_label_rotation: Angle to rotate the x-axis labels (optional).
2467
+ - remove_axes: Boolean to remove or show the axes labels (optional).
2468
+ - bg_color: Color for the figure and subplot background (optional).
2469
+ - text_color: Color for all text in the figure (optional).
2470
+ - line_color: Color for all lines in the figure (optional).
2471
+ """
2472
+ if fig is None:
2473
+ print("Error: The figure provided is None.")
2474
+ return
2475
+
2476
+ for ax in fig.get_axes():
2477
+ # Rescale subplots if scaling factors are provided
2478
+ if scale_x is not None or scale_y is not None:
2479
+ bbox = ax.get_position()
2480
+ width = bbox.width * (scale_x if scale_x else 1)
2481
+ height = bbox.height * (scale_y if scale_y else 1)
2482
+ new_bbox = [bbox.x0, bbox.y0, width, height]
2483
+ ax.set_position(new_bbox)
2484
+
2485
+ # Set axis limits if provided
2486
+ if x_lim is not None:
2487
+ ax.set_xlim(x_lim)
2488
+ if y_lim is not None:
2489
+ ax.set_ylim(y_lim)
2490
+
2491
+ # Set grid visibility only
2492
+ ax.grid(grid)
2493
+
2494
+ # Adjust line width and color if specified
2495
+ if line_width is not None or line_color is not None:
2496
+ for line in ax.get_lines():
2497
+ if line_width is not None:
2498
+ line.set_linewidth(line_width)
2499
+ if line_color is not None:
2500
+ line.set_color(line_color)
2501
+ for spine in ax.spines.values(): # Modify width and color of spines (e.g., scale bars)
2502
+ if line_width is not None:
2503
+ spine.set_linewidth(line_width)
2504
+ if line_color is not None:
2505
+ spine.set_edgecolor(line_color)
2506
+ ax.tick_params(width=line_width, colors=text_color if text_color else 'black')
2507
+
2508
+ # Adjust font size if specified
2509
+ if font_size is not None:
2510
+ for label in ax.get_xticklabels() + ax.get_yticklabels():
2511
+ label.set_fontsize(font_size)
2512
+ ax.title.set_fontsize(font_size)
2513
+ ax.xaxis.label.set_fontsize(font_size)
2514
+ ax.yaxis.label.set_fontsize(font_size)
2515
+ if ax.legend_:
2516
+ for text in ax.legend_.get_texts():
2517
+ text.set_fontsize(font_size)
2518
+
2519
+ # Rotate x-axis labels if rotation is specified
2520
+ if x_label_rotation is not None:
2521
+ for label in ax.get_xticklabels():
2522
+ label.set_rotation(x_label_rotation)
2523
+ if 0 <= x_label_rotation <= 90:
2524
+ label.set_ha('center')
2525
+
2526
+ # Toggle axes labels visibility without affecting the grid or spines
2527
+ if remove_axes:
2528
+ ax.xaxis.set_visible(False)
2529
+ ax.yaxis.set_visible(False)
2530
+ else:
2531
+ ax.xaxis.set_visible(True)
2532
+ ax.yaxis.set_visible(True)
2533
+
2534
+ # Set text color if specified
2535
+ if text_color:
2536
+ ax.title.set_color(text_color)
2537
+ ax.xaxis.label.set_color(text_color)
2538
+ ax.yaxis.label.set_color(text_color)
2539
+ ax.tick_params(colors=text_color)
2540
+ for label in ax.get_xticklabels() + ax.get_yticklabels():
2541
+ label.set_color(text_color)
2542
+
2543
+ # Set background color for subplots if specified
2544
+ if bg_color:
2545
+ ax.set_facecolor(bg_color)
2546
+
2547
+ # Set figure background color if specified
2548
+ if bg_color:
2549
+ fig.patch.set_facecolor(bg_color)
2550
+
2551
+ fig.canvas.draw_idle()
2552
+
2553
+ def save_figure_as_format(fig, file_format):
2554
+ file_path = filedialog.asksaveasfilename(defaultextension=f".{file_format}", filetypes=[(f"{file_format.upper()} files", f"*.{file_format}"), ("All files", "*.*")])
2555
+ if file_path:
2556
+ try:
2557
+ fig.savefig(file_path, format=file_format)
2558
+ print(f"Figure saved as {file_format.upper()} at {file_path}")
2559
+ except Exception as e:
2560
+ print(f"Error saving figure: {e}")
2561
+
2562
+ def modify_figure(fig):
2563
+ from .gui_core import display_figure
2564
+ def apply_modifications():
2565
+ try:
2566
+ # Only apply changes if the fields are filled
2567
+ scale_x = float(scale_x_var.get()) if scale_x_var.get() else None
2568
+ scale_y = float(scale_y_var.get()) if scale_y_var.get() else None
2569
+ line_width = float(line_width_var.get()) if line_width_var.get() else None
2570
+ font_size = int(font_size_var.get()) if font_size_var.get() else None
2571
+ x_lim = eval(x_lim_var.get()) if x_lim_var.get() else None
2572
+ y_lim = eval(y_lim_var.get()) if y_lim_var.get() else None
2573
+ title = title_var.get() if title_var.get() else None
2574
+ bg_color = bg_color_var.get() if bg_color_var.get() else None
2575
+ text_color = text_color_var.get() if text_color_var.get() else None
2576
+ line_color = line_color_var.get() if line_color_var.get() else None
2577
+ x_label_rotation = int(x_label_rotation_var.get()) if x_label_rotation_var.get() else None
2578
+
2579
+ modify_figure_properties(
2580
+ fig,
2581
+ scale_x=scale_x,
2582
+ scale_y=scale_y,
2583
+ line_width=line_width,
2584
+ font_size=font_size,
2585
+ x_lim=x_lim,
2586
+ y_lim=y_lim,
2587
+ grid=grid_var.get(),
2588
+ legend=legend_var.get(),
2589
+ title=title,
2590
+ x_label_rotation=x_label_rotation,
2591
+ remove_axes=remove_axes_var.get(),
2592
+ bg_color=bg_color,
2593
+ text_color=text_color,
2594
+ line_color=line_color
2595
+ )
2596
+ display_figure(fig)
2597
+ except ValueError:
2598
+ print("Invalid input; please enter numeric values.")
2599
+
2600
+ def toggle_spleens():
2601
+ for ax in fig.get_axes():
2602
+ if spleens_var.get():
2603
+ ax.spines['top'].set_visible(False)
2604
+ ax.spines['right'].set_visible(False)
2605
+ ax.spines['left'].set_visible(True)
2606
+ ax.spines['bottom'].set_visible(True)
2607
+ ax.spines['top'].set_linewidth(2)
2608
+ ax.spines['right'].set_linewidth(2)
2609
+ else:
2610
+ ax.spines['top'].set_visible(True)
2611
+ ax.spines['right'].set_visible(True)
2612
+ display_figure(fig)
2613
+
2614
+ # Create a new window for user input
2615
+ modify_window = tk.Toplevel()
2616
+ modify_window.title("Modify Figure Properties")
2617
+
2618
+ # Apply dark style to the popup window
2619
+ style = ttk.Style()
2620
+ style.configure("TCheckbutton", background="#2E2E2E", foreground="white", selectcolor="blue")
2621
+
2622
+ modify_window.configure(bg="#2E2E2E")
2623
+
2624
+ # Create and style the input fields
2625
+ scale_x_var = tk.StringVar()
2626
+ scale_y_var = tk.StringVar()
2627
+ line_width_var = tk.StringVar()
2628
+ font_size_var = tk.StringVar()
2629
+ x_lim_var = tk.StringVar()
2630
+ y_lim_var = tk.StringVar()
2631
+ title_var = tk.StringVar()
2632
+ bg_color_var = tk.StringVar()
2633
+ text_color_var = tk.StringVar()
2634
+ line_color_var = tk.StringVar()
2635
+ x_label_rotation_var = tk.StringVar()
2636
+ remove_axes_var = tk.BooleanVar()
2637
+ grid_var = tk.BooleanVar()
2638
+ legend_var = tk.BooleanVar()
2639
+ spleens_var = tk.BooleanVar()
2640
+
2641
+ options = [
2642
+ ("Rescale X:", scale_x_var),
2643
+ ("Rescale Y:", scale_y_var),
2644
+ ("Line Width:", line_width_var),
2645
+ ("Font Size:", font_size_var),
2646
+ ("X Axis Limits (tuple):", x_lim_var),
2647
+ ("Y Axis Limits (tuple):", y_lim_var),
2648
+ ("Title:", title_var),
2649
+ ("X Label Rotation (degrees):", x_label_rotation_var),
2650
+ ("Background Color:", bg_color_var),
2651
+ ("Text Color:", text_color_var),
2652
+ ("Line Color:", line_color_var)
2653
+ ]
2654
+
2655
+ for i, (label_text, var) in enumerate(options):
2656
+ tk.Label(modify_window, text=label_text, bg="#2E2E2E", fg="white").grid(row=i, column=0, padx=10, pady=5)
2657
+ tk.Entry(modify_window, textvariable=var, bg="#2E2E2E", fg="white").grid(row=i, column=1, padx=10, pady=5)
2658
+
2659
+ checkboxes = [
2660
+ ("Grid", grid_var),
2661
+ ("Legend", legend_var),
2662
+ ("Spleens", spleens_var),
2663
+ ("Remove Axes", remove_axes_var)
2664
+ ]
2665
+
2666
+ for i, (label_text, var) in enumerate(checkboxes, start=len(options)):
2667
+ ttk.Checkbutton(modify_window, text=label_text, variable=var, style="TCheckbutton").grid(row=i, column=0, padx=10, pady=5, columnspan=2, sticky='w')
2668
+
2669
+ spleens_var.trace_add("write", lambda *args: toggle_spleens())
2670
+
2671
+ # Apply button
2672
+ apply_button = tk.Button(modify_window, text="Apply", command=apply_modifications, bg="#2E2E2E", fg="white")
2673
+ apply_button.grid(row=len(options) + len(checkboxes), column=0, columnspan=2, pady=10)
spacr/gui_utils.py CHANGED
@@ -76,6 +76,18 @@ def load_app(root, app_name, app_func):
76
76
  proceed_with_app(root, app_name, app_func)
77
77
 
78
78
  def parse_list(value):
79
+ """
80
+ Parses a string representation of a list and returns the parsed list.
81
+
82
+ Args:
83
+ value (str): The string representation of the list.
84
+
85
+ Returns:
86
+ list: The parsed list.
87
+
88
+ Raises:
89
+ ValueError: If the input value is not a valid list format or contains mixed types or unsupported types.
90
+ """
79
91
  try:
80
92
  parsed_value = ast.literal_eval(value)
81
93
  if isinstance(parsed_value, list):
@@ -93,7 +105,26 @@ def parse_list(value):
93
105
 
94
106
  # Usage example in your create_input_field function
95
107
  def create_input_field(frame, label_text, row, var_type='entry', options=None, default_value=None):
108
+ """
109
+ Create an input field in the specified frame.
110
+
111
+ Args:
112
+ frame (tk.Frame): The frame in which the input field will be created.
113
+ label_text (str): The text to be displayed as the label for the input field.
114
+ row (int): The row in which the input field will be placed.
115
+ var_type (str, optional): The type of input field to create. Defaults to 'entry'.
116
+ options (list, optional): The list of options for a combo box input field. Defaults to None.
117
+ default_value (str, optional): The default value for the input field. Defaults to None.
118
+
119
+ Returns:
120
+ tuple: A tuple containing the label, input widget, variable, and custom frame.
121
+
122
+ Raises:
123
+ Exception: If an error occurs while creating the input field.
124
+
125
+ """
96
126
  from .gui_elements import set_dark_style, set_element_size
127
+
97
128
  label_column = 0
98
129
  widget_column = 0 # Both label and widget will be in the same column
99
130
 
@@ -205,6 +236,12 @@ def annotate(settings):
205
236
 
206
237
  def generate_annotate_fields(frame):
207
238
  from .settings import set_annotate_default_settings
239
+ from .gui_elements import set_dark_style
240
+
241
+ style_out = set_dark_style(ttk.Style())
242
+ font_loader = style_out['font_loader']
243
+ font_size = style_out['font_size'] - 2
244
+
208
245
  vars_dict = {}
209
246
  settings = set_annotate_default_settings(settings={})
210
247
 
@@ -216,8 +253,8 @@ def generate_annotate_fields(frame):
216
253
 
217
254
  # Arrange input fields and labels
218
255
  for row, (name, data) in enumerate(vars_dict.items()):
219
- ttk.Label(frame, text=f"{name.replace('_', ' ').capitalize()}:",
220
- background="black", foreground="white").grid(row=row, column=0)
256
+ tk.Label(frame, text=f"{name.replace('_', ' ').capitalize()}:", bg=style_out['bg_color'], fg=style_out['fg_color'], font=font_loader.get_font(size=font_size)).grid(row=row, column=0)
257
+ #ttk.Label(frame, text=f"{name.replace('_', ' ').capitalize()}:", background="black", foreground="white").grid(row=row, column=0)
221
258
  if isinstance(data['value'], list):
222
259
  # Convert lists to comma-separated strings
223
260
  data['entry'].insert(0, ','.join(map(str, data['value'])))
spacr/plot.py CHANGED
@@ -125,7 +125,7 @@ def plot_image_mask_overlay(file, channels, cell_channel, nucleus_channel, patho
125
125
 
126
126
  return
127
127
 
128
- def plot_masks(batch, masks, flows, cmap='inferno', figuresize=20, nr=1, file_type='.npz', print_object_number=True):
128
+ def plot_masks(batch, masks, flows, cmap='inferno', figuresize=10, nr=1, file_type='.npz', print_object_number=True):
129
129
  """
130
130
  Plot the masks and flows for a given batch of images.
131
131
 
@@ -476,7 +476,7 @@ def _filter_objects_in_plot(stack, cell_mask_dim, nucleus_mask_dim, pathogen_mas
476
476
 
477
477
  return stack
478
478
 
479
- def plot_arrays(src, figuresize=50, cmap='inferno', nr=1, normalize=True, q1=1, q2=99):
479
+ def plot_arrays(src, figuresize=10, cmap='inferno', nr=1, normalize=True, q1=1, q2=99):
480
480
  """
481
481
  Plot randomly selected arrays from a given directory.
482
482
 
@@ -870,7 +870,7 @@ def _save_scimg_plot(src, nr_imgs=16, channel_indices=[0,1,2], um_per_pixel=0.1,
870
870
 
871
871
  return
872
872
 
873
- def _plot_cropped_arrays(stack, filename, figuresize=20, cmap='inferno', threshold=500):
873
+ def _plot_cropped_arrays(stack, filename, figuresize=10, cmap='inferno', threshold=500):
874
874
  """
875
875
  Plot cropped arrays.
876
876
 
@@ -997,7 +997,7 @@ def _display_gif(path):
997
997
  with open(path, 'rb') as file:
998
998
  display(ipyimage(file.read()))
999
999
 
1000
- def _plot_recruitment(df, df_type, channel_of_interest, target, columns=[], figuresize=50):
1000
+ def _plot_recruitment(df, df_type, channel_of_interest, target, columns=[], figuresize=10):
1001
1001
  """
1002
1002
  Plot recruitment data for different conditions and pathogens.
1003
1003
 
spacr/sequencing.py CHANGED
@@ -223,14 +223,10 @@ def save_to_hdf(queue, output_file, complevel=9, compression='zlib'):
223
223
  Save data from a queue to an HDF file.
224
224
 
225
225
  Parameters:
226
- - queue: Queue object
227
- The queue containing the data to be saved.
228
- - output_file: strs
229
- The path to the output HDF file.
230
- - complevel: int, optional
231
- The compression level to use (default is 9).
232
- - compression: str, optional
233
- The compression algorithm to use (default is 'zlib').
226
+ - queue: Queue object containing chunks of data to be saved
227
+ - output_file: Path to the output HDF file
228
+ - complevel: Compression level (default: 9)
229
+ - compression: Compression algorithm (default: 'zlib')
234
230
 
235
231
  Returns:
236
232
  None
spacr/utils.py CHANGED
@@ -1,4 +1,4 @@
1
- import sys, os, re, sqlite3, torch, torchvision, random, string, shutil, cv2, tarfile, glob, psutil, platform, gzip
1
+ import sys, os, re, sqlite3, torch, torchvision, random, string, shutil, cv2, tarfile, glob, psutil, platform, gzip, subprocess
2
2
 
3
3
  import numpy as np
4
4
  from cellpose import models as cp_models
@@ -3451,7 +3451,7 @@ def setup_plot(figuresize, black_background):
3451
3451
  fig, ax = plt.subplots(1, 1, figsize=(figuresize, figuresize))
3452
3452
  return fig, ax
3453
3453
 
3454
- def plot_clusters(ax, embedding, labels, colors, cluster_centers, plot_outlines, plot_points, smooth_lines, figuresize=50, dot_size=50, verbose=False):
3454
+ def plot_clusters(ax, embedding, labels, colors, cluster_centers, plot_outlines, plot_points, smooth_lines, figuresize=10, dot_size=50, verbose=False):
3455
3455
  unique_labels = np.unique(labels)
3456
3456
  for cluster_label, color, center in zip(unique_labels, colors, cluster_centers):
3457
3457
  cluster_data = embedding[labels == cluster_label]
@@ -4433,3 +4433,13 @@ def count_reads_in_fastq(fastq_file):
4433
4433
  for _ in f:
4434
4434
  count += 1
4435
4435
  return count // 4
4436
+
4437
+
4438
+ # Function to determine the CUDA version
4439
+ def get_cuda_version():
4440
+ try:
4441
+ output = subprocess.check_output(['nvcc', '--version'], stderr=subprocess.STDOUT).decode('utf-8')
4442
+ if 'release' in output:
4443
+ return output.split('release ')[1].split(',')[0].replace('.', '')
4444
+ except (subprocess.CalledProcessError, FileNotFoundError):
4445
+ return None
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: spacr
3
- Version: 0.2.61
3
+ Version: 0.2.66
4
4
  Summary: Spatial phenotype analysis of crisp screens (SpaCr)
5
5
  Home-page: https://github.com/EinarOlafsson/spacr
6
6
  Author: Einar Birnir Olafsson
@@ -9,49 +9,51 @@ Classifier: Programming Language :: Python :: 3
9
9
  Classifier: License :: OSI Approved :: MIT License
10
10
  Classifier: Operating System :: OS Independent
11
11
  License-File: LICENSE
12
- Requires-Dist: torch <3.0,>=2.0
13
- Requires-Dist: torchvision <1.0,>=0.1
14
- Requires-Dist: torch-geometric <3.0,>=2.5
15
- Requires-Dist: numpy <2.0,>=1.26.4
16
- Requires-Dist: pandas <3.0,>=2.2.1
17
- Requires-Dist: statsmodels <1.0,>=0.14.1
18
- Requires-Dist: scikit-image <1.0,>=0.22.0
19
- Requires-Dist: scikit-learn <2.0,>=1.4.1
20
- Requires-Dist: seaborn <1.0,>=0.13.2
21
- Requires-Dist: matplotlib <4.0,>=3.8.3
22
- Requires-Dist: shap <1.0,>=0.45.0
23
- Requires-Dist: pillow <11.0,>=10.2.0
24
- Requires-Dist: imageio <3.0,>=2.34.0
25
- Requires-Dist: scipy <2.0,>=1.12.0
26
- Requires-Dist: ipywidgets <9.0,>=8.1.2
27
- Requires-Dist: mahotas <2.0,>=1.4.13
28
- Requires-Dist: btrack <1.0,>=0.6.5
29
- Requires-Dist: trackpy <1.0,>=0.6.2
30
- Requires-Dist: cellpose <4.0,>=3.0.6
31
- Requires-Dist: IPython <9.0,>=8.18.1
32
- Requires-Dist: opencv-python-headless <5.0,>=4.9.0.80
33
- Requires-Dist: umap-learn <1.0,>=0.5.6
34
- Requires-Dist: ttkthemes <4.0,>=3.2.2
35
- Requires-Dist: xgboost <3.0,>=2.0.3
36
- Requires-Dist: PyWavelets <2.0,>=1.6.0
37
- Requires-Dist: torchcam <1.0,>=0.4.0
38
- Requires-Dist: ttf-opensans >=2020.10.30
39
- Requires-Dist: customtkinter <6.0,>=5.2.2
40
- Requires-Dist: biopython <2.0,>=1.80
41
- Requires-Dist: lxml <6.0,>=5.1.0
42
- Requires-Dist: psutil <6.0,>=5.9.8
43
- Requires-Dist: gputil <2.0,>=1.4.0
44
- Requires-Dist: gpustat <2.0,>=1.1.1
45
- Requires-Dist: pyautogui <1.0,>=0.9.54
46
- Requires-Dist: tables <4.0,>=3.8.0
47
- Requires-Dist: rapidfuzz <4.0,>=3.9
48
- Requires-Dist: huggingface-hub <0.25,>=0.24.0
12
+ Requires-Dist: torch<3.0,>=2.0
13
+ Requires-Dist: torchvision<1.0,>=0.1
14
+ Requires-Dist: torch-geometric<3.0,>=2.5
15
+ Requires-Dist: numpy<2.0,>=1.26.4
16
+ Requires-Dist: pandas<3.0,>=2.2.1
17
+ Requires-Dist: bottleneck<2.0,>=1.3.6
18
+ Requires-Dist: numexpr<3.0,>=2.8.4
19
+ Requires-Dist: statsmodels<1.0,>=0.14.1
20
+ Requires-Dist: scikit-image<1.0,>=0.22.0
21
+ Requires-Dist: scikit-learn<2.0,>=1.4.1
22
+ Requires-Dist: seaborn<1.0,>=0.13.2
23
+ Requires-Dist: matplotlib<4.0,>=3.8.3
24
+ Requires-Dist: shap<1.0,>=0.45.0
25
+ Requires-Dist: pillow<11.0,>=10.2.0
26
+ Requires-Dist: imageio<3.0,>=2.34.0
27
+ Requires-Dist: scipy<2.0,>=1.12.0
28
+ Requires-Dist: ipywidgets<9.0,>=8.1.2
29
+ Requires-Dist: mahotas<2.0,>=1.4.13
30
+ Requires-Dist: btrack<1.0,>=0.6.5
31
+ Requires-Dist: trackpy<1.0,>=0.6.2
32
+ Requires-Dist: cellpose<4.0,>=3.0.6
33
+ Requires-Dist: IPython<9.0,>=8.18.1
34
+ Requires-Dist: opencv-python-headless<5.0,>=4.9.0.80
35
+ Requires-Dist: umap-learn<1.0,>=0.5.6
36
+ Requires-Dist: ttkthemes<4.0,>=3.2.2
37
+ Requires-Dist: xgboost<3.0,>=2.0.3
38
+ Requires-Dist: PyWavelets<2.0,>=1.6.0
39
+ Requires-Dist: torchcam<1.0,>=0.4.0
40
+ Requires-Dist: ttf-opensans>=2020.10.30
41
+ Requires-Dist: customtkinter<6.0,>=5.2.2
42
+ Requires-Dist: biopython<2.0,>=1.80
43
+ Requires-Dist: lxml<6.0,>=5.1.0
44
+ Requires-Dist: psutil<6.0,>=5.9.8
45
+ Requires-Dist: gputil<2.0,>=1.4.0
46
+ Requires-Dist: gpustat<2.0,>=1.1.1
47
+ Requires-Dist: pyautogui<1.0,>=0.9.54
48
+ Requires-Dist: tables<4.0,>=3.8.0
49
+ Requires-Dist: rapidfuzz<4.0,>=3.9
50
+ Requires-Dist: huggingface-hub<0.25,>=0.24.0
49
51
  Provides-Extra: dev
50
- Requires-Dist: pytest <3.11,>=3.9 ; extra == 'dev'
52
+ Requires-Dist: pytest<3.11,>=3.9; extra == "dev"
51
53
  Provides-Extra: full
52
- Requires-Dist: opencv-python ; extra == 'full'
54
+ Requires-Dist: opencv-python; extra == "full"
53
55
  Provides-Extra: headless
54
- Requires-Dist: opencv-python-headless ; extra == 'headless'
56
+ Requires-Dist: opencv-python-headless; extra == "headless"
55
57
 
56
58
  .. |Documentation Status| image:: https://readthedocs.org/projects/spacr/badge/?version=latest
57
59
  :target: https://spacr.readthedocs.io/en/latest/?badge=latest
@@ -1,4 +1,4 @@
1
- spacr/__init__.py,sha256=pJ7Mm7Kb1DhHIdLmNgMILFVWJ9QAG47pT0M6wtiXl8E,1465
1
+ spacr/__init__.py,sha256=8NZIlJOY2OzRCFjXvqusFL7BfyEJwNqB2lL8QNB-Kgo,1141
2
2
  spacr/__main__.py,sha256=bkAJJD2kjIqOP-u1kLvct9jQQCeUXzlEjdgitwi1Lm8,75
3
3
  spacr/app_annotate.py,sha256=nEIL7Fle9CDKGo3sucG_03DgjUQt5W1M1IHBIpVBr08,2171
4
4
  spacr/app_classify.py,sha256=urTP_wlZ58hSyM5a19slYlBxN0PdC-9-ga0hvq8CGWc,165
@@ -11,20 +11,20 @@ spacr/chris.py,sha256=YlBjSgeZaY8HPy6jkrT_ISAnCMAKVfvCxF0I9eAZLFM,2418
11
11
  spacr/core.py,sha256=IDme9j7eeC_49KGaNk_xPOKtpxdcXKMhYtoo3xhjQMM,146502
12
12
  spacr/deep_spacr.py,sha256=a2YewgkQvLV-95NYJAutnojvJmX4S8z_wv6Tb-XIgUI,34484
13
13
  spacr/graph_learning.py,sha256=1tR-ZxvXE3dBz1Saw7BeVFcrsUFu9OlUZeZVifih9eo,13070
14
- spacr/gui.py,sha256=dSEQhzZgIOT7SOonbIp07-zXcLaEt6M7sRiIREpDv64,7226
15
- spacr/gui_core.py,sha256=8aoxVLwt8evl_mZG6xHxhRgf5nq35bfay12OOSJos5Q,40148
16
- spacr/gui_elements.py,sha256=z00Xk16TxqMUXKat0rGmw2DHDFzuXoY0C1Tlg6LZpEI,110662
17
- spacr/gui_utils.py,sha256=h84IcxKqcUZfatLybIMszc_xVVsBrdGKWzPdfV1oM3w,28474
14
+ spacr/gui.py,sha256=q8SBFiMeU6Sy3orpzHdsFxvURr5zv-S-9DOD3TEQ6ag,7445
15
+ spacr/gui_core.py,sha256=HXeMfvthY_G371o84Dcr59VLT6AOKQF8r_V9kVzg7h0,38745
16
+ spacr/gui_elements.py,sha256=7YLyIeK5JFqzevzEruvfQOrfDGOS9ZgD8ZE-dxywp3g,122706
17
+ spacr/gui_utils.py,sha256=1pZ9QAh6BCVb6BSXciU0V9qFWOSsTtCiC72iGXUdV0c,29941
18
18
  spacr/io.py,sha256=ZtVNbEom8X8p_KfsuWw0glGwLg6S0CfwwevDPGdfiSc,117342
19
19
  spacr/logger.py,sha256=7Zqr3TuuOQLWT32gYr2q1qvv7x0a2JhLANmZcnBXAW8,670
20
20
  spacr/measure.py,sha256=4rmzH_a5Y0s1qALVi6YRut3xpnkJXs5vzeTPCEf3QS8,54871
21
- spacr/plot.py,sha256=CICY2h6sNiY6bGKkw6ZYmro_FixXkKxZpIIOoSuMw94,73963
22
- spacr/sequencing.py,sha256=dt4urG5tL85qh2sGEi2F9rtOqBQR-eCfcqOvcAtQIzg,75849
21
+ spacr/plot.py,sha256=xVnbML7WpAEzdJdrLeYRk6aPinZSiV2dLAeu4mh7n0k,73963
22
+ spacr/sequencing.py,sha256=y7EB8226B0b0gnGXt6jqBaFVATrM1Y89v3rtHb8XR_k,75746
23
23
  spacr/settings.py,sha256=tDvTBWANeuI6YC_fH5vK2HOOuRgQXIkzyNKDmt1vL4c,67745
24
24
  spacr/sim.py,sha256=FveaVgBi3eypO2oVB5Dx-v0CC1Ny7UPfXkJiiRRodAk,71212
25
25
  spacr/sim_app.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
26
26
  spacr/timelapse.py,sha256=KMYCgHzf9LTZe-lWl5mvH2EjbKRE6OhpwdY13wEumGc,39504
27
- spacr/utils.py,sha256=M0lbpquOIxJi4iMH2_GAu0iB7jysifPNW3wzNuH1V4I,188733
27
+ spacr/utils.py,sha256=R8PA8MyldBKQOvITo9f4oVFcKOMKv5gaD9T86T_LrEA,189120
28
28
  spacr/version.py,sha256=axH5tnGwtgSnJHb5IDhiu4Zjk5GhLyAEDRe-rnaoFOA,409
29
29
  spacr/resources/font/open_sans/OFL.txt,sha256=bGMoWBRrE2RcdzDiuYiB8A9OVFlJ0sA2imWwce2DAdo,4484
30
30
  "spacr/resources/font/open_sans/OpenSans-Italic-VariableFont_wdth,wght.ttf",sha256=QSoWv9h46CRX_fdlqFM3O2d3-PF3R1srnb4zUezcLm0,580280
@@ -92,9 +92,9 @@ spacr/resources/icons/umap.png,sha256=dOLF3DeLYy9k0nkUybiZMe1wzHQwLJFRmgccppw-8b
92
92
  spacr/resources/models/cp/toxo_plaque_cyto_e25000_X1120_Y1120.CP_model,sha256=z8BbHWZPRnE9D_BHO0fBREE85c1vkltDs-incs2ytXQ,26566572
93
93
  spacr/resources/models/cp/toxo_plaque_cyto_e25000_X1120_Y1120.CP_model_settings.csv,sha256=fBAGuL_B8ERVdVizO3BHozTDSbZUh1yFzsYK3wkQN68,420
94
94
  spacr/resources/models/cp/toxo_pv_lumen.CP_model,sha256=2y_CindYhmTvVwBH39SNILF3rI3x9SsRn6qrMxHy3l0,26562451
95
- spacr-0.2.61.dist-info/LICENSE,sha256=SR-2MeGc6SCM1UORJYyarSWY_A-JaOMFDj7ReSs9tRM,1083
96
- spacr-0.2.61.dist-info/METADATA,sha256=Bh2O70K6G8eMEuz-OQSr66GSsluRZG1mIqMVO6ycLAU,5259
97
- spacr-0.2.61.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
98
- spacr-0.2.61.dist-info/entry_points.txt,sha256=BMC0ql9aNNpv8lUZ8sgDLQMsqaVnX5L535gEhKUP5ho,296
99
- spacr-0.2.61.dist-info/top_level.txt,sha256=GJPU8FgwRXGzKeut6JopsSRY2R8T3i9lDgya42tLInY,6
100
- spacr-0.2.61.dist-info/RECORD,,
95
+ spacr-0.2.66.dist-info/LICENSE,sha256=SR-2MeGc6SCM1UORJYyarSWY_A-JaOMFDj7ReSs9tRM,1083
96
+ spacr-0.2.66.dist-info/METADATA,sha256=OFvnPazh5gN1lwOQNMGCca5fdhXteebOX26LnhaLui0,5291
97
+ spacr-0.2.66.dist-info/WHEEL,sha256=HiCZjzuy6Dw0hdX5R3LCFPDmFS4BWl8H-8W39XfmgX4,91
98
+ spacr-0.2.66.dist-info/entry_points.txt,sha256=BMC0ql9aNNpv8lUZ8sgDLQMsqaVnX5L535gEhKUP5ho,296
99
+ spacr-0.2.66.dist-info/top_level.txt,sha256=GJPU8FgwRXGzKeut6JopsSRY2R8T3i9lDgya42tLInY,6
100
+ spacr-0.2.66.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: bdist_wheel (0.43.0)
2
+ Generator: setuptools (72.2.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5