spacr 0.2.2__py3-none-any.whl → 0.2.3__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.
Files changed (95) hide show
  1. spacr/gui.py +2 -1
  2. spacr/gui_core.py +75 -34
  3. spacr/gui_elements.py +322 -57
  4. spacr/gui_utils.py +26 -32
  5. spacr/resources/icons/abort.png +0 -0
  6. spacr/resources/icons/classify.png +0 -0
  7. spacr/resources/icons/make_masks.png +0 -0
  8. spacr/resources/icons/mask.png +0 -0
  9. spacr/resources/icons/measure.png +0 -0
  10. spacr/resources/icons/ml_analyze.png +0 -0
  11. spacr/resources/icons/recruitment.png +0 -0
  12. spacr/resources/icons/regression.png +0 -0
  13. spacr/resources/icons/run.png +0 -0
  14. spacr/resources/icons/spacr_logo_rotation.gif +0 -0
  15. spacr/resources/icons/train_cellpose.png +0 -0
  16. spacr/resources/icons/umap.png +0 -0
  17. {spacr-0.2.2.dist-info → spacr-0.2.3.dist-info}/METADATA +1 -1
  18. spacr-0.2.3.dist-info/RECORD +58 -0
  19. spacr/alpha.py +0 -807
  20. spacr/annotate_app.py +0 -670
  21. spacr/annotate_app_v2.py +0 -670
  22. spacr/app_make_masks_v2.py +0 -686
  23. spacr/classify_app.py +0 -201
  24. spacr/cli.py +0 -41
  25. spacr/foldseek.py +0 -779
  26. spacr/get_alfafold_structures.py +0 -72
  27. spacr/gui_2.py +0 -157
  28. spacr/gui_annotate.py +0 -145
  29. spacr/gui_classify_app.py +0 -201
  30. spacr/gui_make_masks_app.py +0 -927
  31. spacr/gui_make_masks_app_v2.py +0 -688
  32. spacr/gui_mask_app.py +0 -249
  33. spacr/gui_measure_app.py +0 -246
  34. spacr/gui_run.py +0 -58
  35. spacr/gui_sim_app.py +0 -0
  36. spacr/gui_wrappers.py +0 -149
  37. spacr/icons/abort.png +0 -0
  38. spacr/icons/abort.svg +0 -1
  39. spacr/icons/download.png +0 -0
  40. spacr/icons/download.svg +0 -1
  41. spacr/icons/download_for_offline_100dp_E8EAED_FILL0_wght100_GRAD-25_opsz48.png +0 -0
  42. spacr/icons/download_for_offline_100dp_E8EAED_FILL0_wght100_GRAD-25_opsz48.svg +0 -1
  43. spacr/icons/logo_spacr.png +0 -0
  44. spacr/icons/make_masks.png +0 -0
  45. spacr/icons/make_masks.svg +0 -1
  46. spacr/icons/map_barcodes.png +0 -0
  47. spacr/icons/map_barcodes.svg +0 -1
  48. spacr/icons/mask.png +0 -0
  49. spacr/icons/mask.svg +0 -1
  50. spacr/icons/measure.png +0 -0
  51. spacr/icons/measure.svg +0 -1
  52. spacr/icons/play_circle_100dp_E8EAED_FILL0_wght100_GRAD-25_opsz48.png +0 -0
  53. spacr/icons/play_circle_100dp_E8EAED_FILL0_wght100_GRAD-25_opsz48.svg +0 -1
  54. spacr/icons/run.png +0 -0
  55. spacr/icons/run.svg +0 -1
  56. spacr/icons/sequencing.png +0 -0
  57. spacr/icons/sequencing.svg +0 -1
  58. spacr/icons/settings.png +0 -0
  59. spacr/icons/settings.svg +0 -1
  60. spacr/icons/settings_100dp_E8EAED_FILL0_wght100_GRAD-25_opsz48.png +0 -0
  61. spacr/icons/settings_100dp_E8EAED_FILL0_wght100_GRAD-25_opsz48.svg +0 -1
  62. spacr/icons/stop_circle_100dp_E8EAED_FILL0_wght100_GRAD-25_opsz48.png +0 -0
  63. spacr/icons/stop_circle_100dp_E8EAED_FILL0_wght100_GRAD-25_opsz48.svg +0 -1
  64. spacr/icons/theater_comedy_100dp_E8EAED_FILL0_wght100_GRAD200_opsz48.png +0 -0
  65. spacr/icons/theater_comedy_100dp_E8EAED_FILL0_wght100_GRAD200_opsz48.svg +0 -1
  66. spacr/make_masks_app.py +0 -929
  67. spacr/make_masks_app_v2.py +0 -688
  68. spacr/mask_app.py +0 -249
  69. spacr/measure_app.py +0 -246
  70. spacr/models/cp/toxo_plaque_cyto_e25000_X1120_Y1120.CP_model +0 -0
  71. spacr/models/cp/toxo_plaque_cyto_e25000_X1120_Y1120.CP_model_settings.csv +0 -23
  72. spacr/models/cp/toxo_pv_lumen.CP_model +0 -0
  73. spacr/old_code.py +0 -358
  74. spacr/resources/icons/abort.svg +0 -1
  75. spacr/resources/icons/annotate.svg +0 -1
  76. spacr/resources/icons/classify.svg +0 -1
  77. spacr/resources/icons/download.svg +0 -1
  78. spacr/resources/icons/icon.psd +0 -0
  79. spacr/resources/icons/make_masks.svg +0 -1
  80. spacr/resources/icons/map_barcodes.svg +0 -1
  81. spacr/resources/icons/mask.svg +0 -1
  82. spacr/resources/icons/measure.svg +0 -1
  83. spacr/resources/icons/run.svg +0 -1
  84. spacr/resources/icons/run_2.png +0 -0
  85. spacr/resources/icons/run_2.svg +0 -1
  86. spacr/resources/icons/sequencing.svg +0 -1
  87. spacr/resources/icons/settings.svg +0 -1
  88. spacr/resources/icons/train_cellpose.svg +0 -1
  89. spacr/test_gui.py +0 -0
  90. spacr-0.2.2.dist-info/RECORD +0 -126
  91. /spacr/resources/icons/{cellpose.png → cellpose_all.png} +0 -0
  92. {spacr-0.2.2.dist-info → spacr-0.2.3.dist-info}/LICENSE +0 -0
  93. {spacr-0.2.2.dist-info → spacr-0.2.3.dist-info}/WHEEL +0 -0
  94. {spacr-0.2.2.dist-info → spacr-0.2.3.dist-info}/entry_points.txt +0 -0
  95. {spacr-0.2.2.dist-info → spacr-0.2.3.dist-info}/top_level.txt +0 -0
spacr/gui_elements.py CHANGED
@@ -15,19 +15,20 @@ from skimage.draw import polygon, line
15
15
  from skimage.transform import resize
16
16
  from scipy.ndimage import binary_fill_holes, label
17
17
  from tkinter import ttk, scrolledtext
18
- import platform
19
18
 
20
- def set_dark_style(style, parent_frame=None, containers=None, widgets=None, font_family="Arial", font_size=12, bg_color='black', fg_color='white', active_color='blue', inactive_color='dark_gray'):
19
+ def set_default_font(root, font_name="Arial", size=12):
20
+ default_font = (font_name, size)
21
+ root.option_add("*Font", default_font)
22
+ root.option_add("*TButton.Font", default_font)
23
+ root.option_add("*TLabel.Font", default_font)
24
+ root.option_add("*TEntry.Font", default_font)
21
25
 
22
- if platform.system() == 'Darwin':
23
- bg_color = '#313131'
24
- else:
25
- bg_color = '#000000'
26
+ def set_dark_style(style, parent_frame=None, containers=None, widgets=None, font_family="Arial", font_size=12, bg_color='black', fg_color='white', active_color='blue', inactive_color='dark_gray'):
26
27
 
27
28
  if active_color == 'teal':
28
29
  active_color = '#008080'
29
30
  if inactive_color == 'dark_gray':
30
- inactive_color = '#050505'
31
+ inactive_color = '#2B2B2B' # '#333333' #'#050505'
31
32
  if bg_color == 'black':
32
33
  bg_color = '#000000'
33
34
  if fg_color == 'white':
@@ -35,27 +36,39 @@ def set_dark_style(style, parent_frame=None, containers=None, widgets=None, font
35
36
  if active_color == 'blue':
36
37
  active_color = '#007BFF'
37
38
 
39
+ padding = '5 5 5 5'
38
40
  font_style = tkFont.Font(family=font_family, size=font_size)
39
- style.configure('TEntry', padding='5 5 5 5', borderwidth=1, relief='solid', fieldbackground=bg_color, foreground=fg_color, font=font_style)
40
- style.configure('TCombobox', fieldbackground=bg_color, background=bg_color, foreground=fg_color, selectbackground=bg_color, selectforeground=fg_color, font=font_style)
41
- style.map('TCombobox', fieldbackground=[('readonly', bg_color)], foreground=[('readonly', fg_color)], selectbackground=[('readonly', bg_color)], selectforeground=[('readonly', fg_color)])
42
- style.configure('Custom.TButton', background=bg_color, foreground=fg_color, bordercolor=fg_color, focusthickness=3, focuscolor=fg_color, font=(font_family, font_size))
43
- style.map('Custom.TButton', background=[('active', active_color), ('!active', bg_color)], foreground=[('active', fg_color), ('!active', fg_color)], bordercolor=[('active', fg_color), ('!active', fg_color)])
44
- style.configure('Custom.TLabel', padding='5 5 5 5', borderwidth=1, relief='flat', background=bg_color, foreground=fg_color, font=font_style)
45
- style.configure('Spacr.TCheckbutton', background=bg_color, foreground=fg_color, indicatoron=False, relief='flat', font="15")
46
- style.map('Spacr.TCheckbutton', background=[('selected', bg_color), ('active', bg_color)], foreground=[('selected', fg_color), ('active', fg_color)])
47
- style.configure('TLabel', background=bg_color, foreground=fg_color, font=font_style)
41
+
42
+ style.theme_use('clam')
43
+
44
+ style.configure('TEntry', padding=padding)
45
+ style.configure('TCombobox', padding=padding)
46
+ style.configure('Spacr.TEntry', padding=padding)
47
+ style.configure('TEntry', padding=padding)
48
+ style.configure('Spacr.TEntry', padding=padding)
49
+ style.configure('Custom.TLabel', padding=padding)
50
+ #style.configure('Spacr.TCheckbutton', padding=padding)
51
+ style.configure('TButton', padding=padding)
52
+
48
53
  style.configure('TFrame', background=bg_color)
49
54
  style.configure('TPanedwindow', background=bg_color)
50
- style.configure('TNotebook', background=bg_color, tabmargins=[2, 5, 2, 0])
51
- style.configure('TNotebook.Tab', background=bg_color, foreground=fg_color, padding=[5, 5], font=font_style)
52
- style.map('TNotebook.Tab', background=[('selected', active_color), ('active', active_color)], foreground=[('selected', fg_color), ('active', fg_color)])
53
- style.configure('TButton', background=bg_color, foreground=fg_color, padding='5 5 5 5', font=font_style)
54
- style.map('TButton', background=[('active', active_color), ('disabled', inactive_color)])
55
- style.configure('Vertical.TScrollbar', background=bg_color, troughcolor=bg_color, bordercolor=bg_color)
56
- style.configure('Horizontal.TScrollbar', background=bg_color, troughcolor=bg_color, bordercolor=bg_color)
57
- style.configure('Custom.TLabelFrame', font=(font_family, font_size, 'bold'), background=bg_color, foreground='white', relief='solid', borderwidth=1)
58
- style.configure('Custom.TLabelFrame.Label', background=bg_color, foreground='white', font=(font_family, font_size, 'bold'))
55
+ style.configure('TLabel', background=bg_color, foreground=fg_color, font=font_style)
56
+
57
+
58
+ #style.configure('Custom.TLabel', padding='5 5 5 5', borderwidth=1, relief='flat', background=bg_color, foreground=fg_color, font=font_style)
59
+ #style.configure('Spacr.TCheckbutton', background=bg_color, foreground=fg_color, indicatoron=False, relief='flat', font="15")
60
+ #style.map('Spacr.TCheckbutton', background=[('selected', bg_color), ('active', bg_color)], foreground=[('selected', fg_color), ('active', fg_color)])
61
+
62
+
63
+ #style.configure('TNotebook', background=bg_color, tabmargins=[2, 5, 2, 0])
64
+ #style.configure('TNotebook.Tab', background=bg_color, foreground=fg_color, padding=[5, 5], font=font_style)
65
+ #style.map('TNotebook.Tab', background=[('selected', active_color), ('active', active_color)], foreground=[('selected', fg_color), ('active', fg_color)])
66
+ #style.configure('TButton', background=bg_color, foreground=fg_color, padding='5 5 5 5', font=font_style)
67
+ #style.map('TButton', background=[('active', active_color), ('disabled', inactive_color)])
68
+ #style.configure('Vertical.TScrollbar', background=bg_color, troughcolor=bg_color, bordercolor=bg_color)
69
+ #style.configure('Horizontal.TScrollbar', background=bg_color, troughcolor=bg_color, bordercolor=bg_color)
70
+ #style.configure('Custom.TLabelFrame', font=(font_family, font_size, 'bold'), background=bg_color, foreground='white', relief='solid', borderwidth=1)
71
+ #style.configure('Custom.TLabelFrame.Label', background=bg_color, foreground='white', font=(font_family, font_size, 'bold'))
59
72
 
60
73
  if parent_frame:
61
74
  parent_frame.configure(bg=bg_color)
@@ -86,20 +99,245 @@ def set_dark_style(style, parent_frame=None, containers=None, widgets=None, font
86
99
 
87
100
  return {'font_family': font_family, 'font_size': font_size, 'bg_color': bg_color, 'fg_color': fg_color, 'active_color': active_color, 'inactive_color': inactive_color}
88
101
 
89
- def set_default_font(root, font_name="Arial", size=12):
90
- default_font = (font_name, size)
91
- root.option_add("*Font", default_font)
92
- root.option_add("*TButton.Font", default_font)
93
- root.option_add("*TLabel.Font", default_font)
94
- root.option_add("*TEntry.Font", default_font)
102
+ class spacrEntry(tk.Frame):
103
+ def __init__(self, parent, textvariable=None, outline=False, *args, **kwargs):
104
+ super().__init__(parent, *args, **kwargs)
105
+
106
+ # Set dark style
107
+ style_out = set_dark_style(ttk.Style())
108
+ self.bg_color = style_out['inactive_color']
109
+ self.active_color = style_out['active_color']
110
+ self.fg_color = style_out['fg_color']
111
+ self.outline = outline
112
+ self.font_family = style_out['font_family']
113
+ self.font_size = style_out['font_size']
114
+
115
+ # Set the background color of the frame
116
+ self.configure(bg=style_out['bg_color'])
117
+
118
+ # Create a canvas for the rounded rectangle background
119
+ self.canvas_width = 220 # Adjusted for padding
120
+ self.canvas_height = 40 # Adjusted for padding
121
+ self.canvas = tk.Canvas(self, width=self.canvas_width, height=self.canvas_height, bd=0, highlightthickness=0, relief='ridge', bg=style_out['bg_color'])
122
+ self.canvas.pack()
123
+
124
+ self.entry = tk.Entry(self, textvariable=textvariable, bd=0, highlightthickness=0, fg=self.fg_color, font=(self.font_family, self.font_size), bg=self.bg_color)
125
+ self.entry.place(relx=0.5, rely=0.5, anchor=tk.CENTER, width=190, height=20) # Centered positioning
126
+
127
+ # Bind events to change the background color on focus
128
+ self.entry.bind("<FocusIn>", self.on_focus_in)
129
+ self.entry.bind("<FocusOut>", self.on_focus_out)
130
+
131
+ self.draw_rounded_rectangle(self.bg_color)
132
+
133
+ def draw_rounded_rectangle(self, color):
134
+ radius = 15 # Increased radius for more rounded corners
135
+ x0, y0 = 10, 5
136
+ x1, y1 = 210, 35
137
+ self.canvas.delete("all")
138
+ self.canvas.create_arc((x0, y0, x0 + radius, y0 + radius), start=90, extent=90, fill=color, outline=color)
139
+ self.canvas.create_arc((x1 - radius, y0, x1, y0 + radius), start=0, extent=90, fill=color, outline=color)
140
+ self.canvas.create_arc((x0, y1 - radius, x0 + radius, y1), start=180, extent=90, fill=color, outline=color)
141
+ self.canvas.create_arc((x1 - radius, y1 - radius, x1, y1), start=270, extent=90, fill=color, outline=color)
142
+ self.canvas.create_rectangle((x0 + radius / 2, y0, x1 - radius / 2, y1), fill=color, outline=color)
143
+ self.canvas.create_rectangle((x0, y0 + radius / 2, x1, y1 - radius / 2), fill=color, outline=color)
144
+
145
+ def on_focus_in(self, event):
146
+ self.draw_rounded_rectangle(self.active_color)
147
+ self.entry.config(bg=self.active_color)
148
+
149
+ def on_focus_out(self, event):
150
+ self.draw_rounded_rectangle(self.bg_color)
151
+ self.entry.config(bg=self.bg_color)
152
+
153
+ class spacrCheck(tk.Frame):
154
+ def __init__(self, parent, text="", variable=None, *args, **kwargs):
155
+ super().__init__(parent, *args, **kwargs)
156
+
157
+ style_out = set_dark_style(ttk.Style())
158
+ self.bg_color = style_out['bg_color']
159
+ self.active_color = style_out['active_color']
160
+ self.fg_color = style_out['fg_color']
161
+ self.inactive_color = style_out['inactive_color']
162
+ self.variable = variable
163
+
164
+ self.configure(bg=self.bg_color)
165
+
166
+ # Create a canvas for the rounded square background
167
+ self.canvas_width = 20
168
+ self.canvas_height = 20
169
+ self.canvas = tk.Canvas(self, width=self.canvas_width, height=self.canvas_height, bd=0, highlightthickness=0, relief='ridge', bg=self.bg_color)
170
+ self.canvas.pack()
171
+
172
+ # Draw the initial rounded square based on the variable's value
173
+ self.draw_rounded_square(self.active_color if self.variable.get() else self.inactive_color)
174
+
175
+ # Bind variable changes to update the checkbox
176
+ self.variable.trace_add('write', self.update_check)
177
+
178
+ # Bind click event to toggle the variable
179
+ self.canvas.bind("<Button-1>", self.toggle_variable)
180
+
181
+ def draw_rounded_square(self, color):
182
+ radius = 5 # Adjust the radius for more rounded corners
183
+ x0, y0 = 2, 2
184
+ x1, y1 = 18, 18
185
+ self.canvas.delete("all")
186
+ self.canvas.create_arc((x0, y0, x0 + radius, y0 + radius), start=90, extent=90, fill=color, outline=self.fg_color)
187
+ self.canvas.create_arc((x1 - radius, y0, x1, y0 + radius), start=0, extent=90, fill=color, outline=self.fg_color)
188
+ self.canvas.create_arc((x0, y1 - radius, x0 + radius, y1), start=180, extent=90, fill=color, outline=self.fg_color)
189
+ self.canvas.create_arc((x1 - radius, y1 - radius, x1, y1), start=270, extent=90, fill=color, outline=self.fg_color)
190
+ self.canvas.create_rectangle((x0 + radius / 2, y0, x1 - radius / 2, y1), fill=color, outline=color)
191
+ self.canvas.create_rectangle((x0, y0 + radius / 2, x1, y1 - radius / 2), fill=color, outline=color)
192
+ self.canvas.create_line(x0 + radius / 2, y0, x1 - radius / 2, y0, fill=self.fg_color)
193
+ self.canvas.create_line(x0 + radius / 2, y1, x1 - radius / 2, y1, fill=self.fg_color)
194
+ self.canvas.create_line(x0, y0 + radius / 2, x0, y1 - radius / 2, fill=self.fg_color)
195
+ self.canvas.create_line(x1, y0 + radius / 2, x1, y1 - radius / 2, fill=self.fg_color)
196
+
197
+ def update_check(self, *args):
198
+ self.draw_rounded_square(self.active_color if self.variable.get() else self.inactive_color)
199
+
200
+ def toggle_variable(self, event):
201
+ self.variable.set(not self.variable.get())
202
+
203
+ class spacrCombo(tk.Frame):
204
+ def __init__(self, parent, textvariable=None, values=None, *args, **kwargs):
205
+ super().__init__(parent, *args, **kwargs)
206
+
207
+ # Set dark style
208
+ style_out = set_dark_style(ttk.Style())
209
+ self.bg_color = style_out['bg_color']
210
+ self.active_color = style_out['active_color']
211
+ self.fg_color = style_out['fg_color']
212
+ self.inactive_color = style_out['inactive_color']
213
+ self.font_family = style_out['font_family']
214
+ self.font_size = style_out['font_size']
215
+
216
+ self.values = values or []
217
+
218
+ # Create a canvas for the rounded rectangle background
219
+ self.canvas_width = 220 # Adjusted for padding
220
+ self.canvas_height = 40 # Adjusted for padding
221
+ self.canvas = tk.Canvas(self, width=self.canvas_width, height=self.canvas_height, bd=0, highlightthickness=0, relief='ridge', bg=self.bg_color)
222
+ self.canvas.pack()
223
+
224
+ self.var = textvariable if textvariable else tk.StringVar()
225
+ self.selected_value = self.var.get()
226
+
227
+ # Create the label to display the selected value
228
+ self.label = tk.Label(self, text=self.selected_value, bg=self.inactive_color, fg=self.fg_color, font=(self.font_family, self.font_size))
229
+ self.label.place(relx=0.5, rely=0.5, anchor=tk.CENTER)
230
+
231
+ # Bind events to open the dropdown menu
232
+ self.canvas.bind("<Button-1>", self.on_click)
233
+ self.label.bind("<Button-1>", self.on_click)
234
+
235
+ self.draw_rounded_rectangle(self.inactive_color)
236
+
237
+ self.dropdown_menu = None
238
+
239
+ def draw_rounded_rectangle(self, color):
240
+ radius = 15 # Increased radius for more rounded corners
241
+ x0, y0 = 10, 5
242
+ x1, y1 = 210, 35
243
+ self.canvas.delete("all")
244
+ self.canvas.create_arc((x0, y0, x0 + radius, y0 + radius), start=90, extent=90, fill=color, outline=color)
245
+ self.canvas.create_arc((x1 - radius, y0, x1, y0 + radius), start=0, extent=90, fill=color, outline=color)
246
+ self.canvas.create_arc((x0, y1 - radius, x0 + radius, y1), start=180, extent=90, fill=color, outline=color)
247
+ self.canvas.create_arc((x1 - radius, y1 - radius, x1, y1), start=270, extent=90, fill=color, outline=color)
248
+ self.canvas.create_rectangle((x0 + radius / 2, y0, x1 - radius / 2, y1), fill=color, outline=color)
249
+ self.canvas.create_rectangle((x0, y0 + radius / 2, x1, y1 - radius / 2), fill=color, outline=color)
250
+ self.label.config(bg=color) # Update label background to match rectangle color
251
+
252
+ def on_click(self, event):
253
+ if self.dropdown_menu is None:
254
+ self.open_dropdown()
255
+ else:
256
+ self.close_dropdown()
257
+
258
+ def open_dropdown(self):
259
+ self.draw_rounded_rectangle(self.active_color)
260
+
261
+ self.dropdown_menu = tk.Toplevel(self)
262
+ self.dropdown_menu.wm_overrideredirect(True)
263
+
264
+ x, y, width, height = self.winfo_rootx(), self.winfo_rooty(), self.winfo_width(), self.winfo_height()
265
+ self.dropdown_menu.geometry(f"{width}x{len(self.values) * 30}+{x}+{y + height}")
266
+
267
+ for index, value in enumerate(self.values):
268
+ display_text = value if value is not None else 'None'
269
+ item = tk.Label(self.dropdown_menu, text=display_text, bg=self.inactive_color, fg=self.fg_color, font=(self.font_family, self.font_size), anchor='w')
270
+ item.pack(fill='both')
271
+ item.bind("<Button-1>", lambda e, v=value: self.on_select(v))
272
+ item.bind("<Enter>", lambda e, w=item: w.config(bg=self.active_color))
273
+ item.bind("<Leave>", lambda e, w=item: w.config(bg=self.inactive_color))
274
+
275
+ def close_dropdown(self):
276
+ self.draw_rounded_rectangle(self.inactive_color)
277
+
278
+ if self.dropdown_menu:
279
+ self.dropdown_menu.destroy()
280
+ self.dropdown_menu = None
281
+
282
+ def on_select(self, value):
283
+ display_text = value if value is not None else 'None'
284
+ self.var.set(value)
285
+ self.label.config(text=display_text)
286
+ self.selected_value = value
287
+ self.close_dropdown()
288
+
289
+ def set(self, value):
290
+ display_text = value if value is not None else 'None'
291
+ self.var.set(value)
292
+ self.label.config(text=display_text)
293
+ self.selected_value = value
95
294
 
96
295
  class spacrDropdownMenu(tk.OptionMenu):
97
296
  def __init__(self, parent, variable, options, command=None, **kwargs):
98
297
  self.variable = variable
99
- self.variable.set("Select Category")
298
+ self.variable.set("Settings Category")
100
299
  super().__init__(parent, self.variable, *options, command=command, **kwargs)
101
300
  self.update_styles()
102
301
 
302
+ # Hide the original button
303
+ self.configure(highlightthickness=0, relief='flat', bg='#2B2B2B', fg='#2B2B2B')
304
+
305
+ # Create custom button
306
+ self.create_custom_button()
307
+
308
+ def create_custom_button(self):
309
+ self.canvas_width = self.winfo_reqwidth() # Use the required width of the widget
310
+ self.canvas_height = 40 # Adjust the height as needed
311
+ self.canvas = tk.Canvas(self, width=self.canvas_width, height=self.canvas_height, bd=0, highlightthickness=0, relief='ridge', bg='#2B2B2B')
312
+ self.canvas.pack()
313
+ self.label = tk.Label(self.canvas, text="Settings Category", bg='#2B2B2B', fg='#ffffff', font=('Arial', 12))
314
+ self.label.place(relx=0.5, rely=0.5, anchor=tk.CENTER)
315
+ self.draw_rounded_rectangle('#2B2B2B')
316
+
317
+ # Bind the click event to open the dropdown menu
318
+ self.canvas.bind("<Button-1>", self.on_click)
319
+ self.label.bind("<Button-1>", self.on_click)
320
+
321
+ def draw_rounded_rectangle(self, color):
322
+ radius = 15
323
+ x0, y0 = 10, 5
324
+ x1, y1 = self.canvas_width - 10, self.canvas_height - 5 # Adjust based on canvas size
325
+ self.canvas.delete("all")
326
+ self.canvas.create_arc((x0, y0, x0 + radius, y0 + radius), start=90, extent=90, fill=color, outline=color)
327
+ self.canvas.create_arc((x1 - radius, y0, x1, y0 + radius), start=0, extent=90, fill=color, outline=color)
328
+ self.canvas.create_arc((x0, y1 - radius, x0 + radius, y1), start=180, extent=90, fill=color, outline=color)
329
+ self.canvas.create_arc((x1 - radius, y1 - radius, x1, y1), start=270, extent=90, fill=color, outline=color)
330
+ self.canvas.create_rectangle((x0 + radius / 2, y0, x1 - radius / 2, y1), fill=color, outline=color)
331
+ self.canvas.create_rectangle((x0, y0 + radius / 2, x1, y1 - radius / 2), fill=color, outline=color)
332
+ self.label.config(bg=color) # Update label background to match rectangle color
333
+
334
+ def on_click(self, event):
335
+ self.post_menu()
336
+
337
+ def post_menu(self):
338
+ x, y, width, height = self.winfo_rootx(), self.winfo_rooty(), self.winfo_width(), self.winfo_height()
339
+ self.menu.post(x, y + height)
340
+
103
341
  def update_styles(self, active_categories=None):
104
342
  style = ttk.Style()
105
343
  style_out = set_dark_style(style, widgets=[self])
@@ -124,6 +362,31 @@ class spacrCheckbutton(ttk.Checkbutton):
124
362
  style = ttk.Style()
125
363
  _ = set_dark_style(style, widgets=[self])
126
364
 
365
+ class spacrProgressBar(ttk.Progressbar):
366
+ def __init__(self, parent, *args, **kwargs):
367
+ super().__init__(parent, *args, **kwargs)
368
+
369
+ # Get the style colors
370
+ style_out = set_dark_style(ttk.Style())
371
+ self.inactive_color = style_out['inactive_color']
372
+ self.bg_color = style_out['bg_color']
373
+ self.active_color = style_out['active_color']
374
+
375
+ # Configure the style for the progress bar
376
+ self.style = ttk.Style()
377
+ self.style.configure(
378
+ "spacr.Horizontal.TProgressbar",
379
+ troughcolor=self.bg_color,
380
+ background=self.active_color,
381
+ thickness=20,
382
+ troughrelief='flat',
383
+ borderwidth=0
384
+ )
385
+ self.configure(style="spacr.Horizontal.TProgressbar")
386
+
387
+ # Set initial value to 0
388
+ self['value'] = 0
389
+
127
390
  class spacrFrame(ttk.Frame):
128
391
  def __init__(self, container, width=None, *args, bg='black', **kwargs):
129
392
  super().__init__(container, *args, **kwargs)
@@ -196,7 +459,7 @@ class spacrLabel(tk.Frame):
196
459
  self.canvas.itemconfig(self.label_text, text=text)
197
460
 
198
461
  class spacrButton(tk.Frame):
199
- def __init__(self, parent, text="", command=None, font=None, icon_name=None, size=50, show_text=True, outline=True, *args, **kwargs):
462
+ def __init__(self, parent, text="", command=None, font=None, icon_name=None, size=50, show_text=True, outline=False, *args, **kwargs):
200
463
  super().__init__(parent, *args, **kwargs)
201
464
 
202
465
  self.text = text.capitalize() # Capitalize only the first letter of the text
@@ -220,10 +483,12 @@ class spacrButton(tk.Frame):
220
483
  # Apply dark style and get color settings
221
484
  color_settings = set_dark_style(ttk.Style(), containers=[self], widgets=[self.canvas])
222
485
 
486
+ self.inactive_color = color_settings['inactive_color']
487
+
223
488
  if self.outline:
224
- self.button_bg = self.create_rounded_rectangle(2, 2, self.button_width + 2, self.size + 2, radius=20, fill=color_settings['bg_color'], outline=color_settings['fg_color'])
489
+ self.button_bg = self.create_rounded_rectangle(2, 2, self.button_width + 2, self.size + 2, radius=20, fill=self.inactive_color, outline=color_settings['fg_color'])
225
490
  else:
226
- self.button_bg = self.create_rounded_rectangle(2, 2, self.button_width + 2, self.size + 2, radius=20, fill=color_settings['bg_color'], outline=color_settings['bg_color'])
491
+ self.button_bg = self.create_rounded_rectangle(2, 2, self.button_width + 2, self.size + 2, radius=20, fill=self.inactive_color, outline=self.inactive_color)
227
492
 
228
493
  self.load_icon()
229
494
  self.font_style = font if font else ("Arial", 12) # Default font if not provided
@@ -238,7 +503,7 @@ class spacrButton(tk.Frame):
238
503
  self.canvas.bind("<Leave>", self.on_leave)
239
504
  self.canvas.bind("<Button-1>", self.on_click)
240
505
 
241
- self.bg_color = color_settings['bg_color']
506
+ self.bg_color = self.inactive_color
242
507
  self.active_color = color_settings['active_color']
243
508
  self.fg_color = color_settings['fg_color']
244
509
  self.is_zoomed_in = False # Track zoom state for smooth transitions
@@ -255,7 +520,7 @@ class spacrButton(tk.Frame):
255
520
  icon_image = Image.open(self.get_icon_path("default"))
256
521
  print(f'Icon not found: {icon_path}. Using default icon instead.')
257
522
 
258
- initial_size = int(self.size * 0.9) # Make the initial size slightly smaller
523
+ initial_size = int(self.size * 0.65) # 65% of button size initially
259
524
  self.original_icon_image = icon_image.resize((initial_size, initial_size), Image.Resampling.LANCZOS)
260
525
  self.icon_photo = ImageTk.PhotoImage(self.original_icon_image)
261
526
 
@@ -270,13 +535,13 @@ class spacrButton(tk.Frame):
270
535
  self.canvas.itemconfig(self.button_bg, fill=self.active_color)
271
536
  self.update_description(event)
272
537
  if not self.is_zoomed_in:
273
- self.animate_zoom(1.1) # Zoom in the icon by 10%
538
+ self.animate_zoom(0.85) # Zoom in the icon to 85% of button size
274
539
 
275
540
  def on_leave(self, event=None):
276
- self.canvas.itemconfig(self.button_bg, fill=self.bg_color)
541
+ self.canvas.itemconfig(self.button_bg, fill=self.inactive_color)
277
542
  self.clear_description(event)
278
543
  if self.is_zoomed_in:
279
- self.animate_zoom(1.0) # Reset the icon size
544
+ self.animate_zoom(0.65) # Reset the icon size to 65% of button size
280
545
 
281
546
  def on_click(self, event=None):
282
547
  if self.command:
@@ -321,7 +586,7 @@ class spacrButton(tk.Frame):
321
586
  parent = parent.master
322
587
 
323
588
  def animate_zoom(self, target_scale, steps=10, delay=10):
324
- current_scale = 1.1 if self.is_zoomed_in else 1.0
589
+ current_scale = 0.85 if self.is_zoomed_in else 0.65
325
590
  step_scale = (target_scale - current_scale) / steps
326
591
  self._animate_step(current_scale, step_scale, steps, delay)
327
592
 
@@ -335,13 +600,13 @@ class spacrButton(tk.Frame):
335
600
 
336
601
  def zoom_icon(self, scale_factor):
337
602
  # Resize the original icon image
338
- new_size = int(self.size * 0.9 * scale_factor)
603
+ new_size = int(self.size * scale_factor)
339
604
  resized_icon = self.original_icon_image.resize((new_size, new_size), Image.Resampling.LANCZOS)
340
605
  self.icon_photo = ImageTk.PhotoImage(resized_icon)
341
606
 
342
607
  # Update the icon on the canvas
343
608
  self.canvas.itemconfig(self.button_icon, image=self.icon_photo)
344
- self.canvas.image = self.icon_photo # Keep a reference to avoid garbage collection
609
+ self.canvas.image = self.icon_photo
345
610
 
346
611
  class spacrSwitch(ttk.Frame):
347
612
  def __init__(self, parent, text="", variable=None, command=None, *args, **kwargs):
@@ -1607,20 +1872,20 @@ class AnnotateApp:
1607
1872
  def create_menu_bar(root):
1608
1873
  from .gui import initiate_root
1609
1874
  gui_apps = {
1610
- "Mask": (lambda frame: initiate_root(frame, 'mask'), "Generate cellpose masks for cells, nuclei and pathogen images."),
1611
- "Measure": (lambda frame: initiate_root(frame, 'measure'), "Measure single object intensity and morphological feature. Crop and save single object image"),
1612
- "Annotate": (lambda frame: initiate_root(frame, 'annotate'), "Annotation single object images on a grid. Annotations are saved to database."),
1613
- "Make Masks": (lambda frame: initiate_root(frame, 'make_masks'), "Adjust pre-existing Cellpose models to your specific dataset for improved performance"),
1614
- "Classify": (lambda frame: initiate_root(frame, 'classify'), "Train Torch Convolutional Neural Networks (CNNs) or Transformers to classify single object images."),
1615
- "Sequencing": (lambda frame: initiate_root(frame, 'sequencing'), "Analyze sequencing data."),
1616
- "Umap": (lambda frame: initiate_root(frame, 'umap'), "Generate UMAP embeddings with datapoints represented as images."),
1617
- "Train Cellpose": (lambda frame: initiate_root(frame, 'train_cellpose'), "Train custom Cellpose models."),
1618
- "ML Analyze": (lambda frame: initiate_root(frame, 'ml_analyze'), "Machine learning analysis of data."),
1619
- "Cellpose Masks": (lambda frame: initiate_root(frame, 'cellpose_masks'), "Generate Cellpose masks."),
1620
- "Cellpose All": (lambda frame: initiate_root(frame, 'cellpose_all'), "Run Cellpose on all images."),
1621
- "Map Barcodes": (lambda frame: initiate_root(frame, 'map_barcodes'), "Map barcodes to data."),
1622
- "Regression": (lambda frame: initiate_root(frame, 'regression'), "Perform regression analysis."),
1623
- "Recruitment": (lambda frame: initiate_root(frame, 'recruitment'), "Analyze recruitment data.")
1875
+ "Mask": (lambda frame: initiate_root(frame, settings_type='mask'), "Generate cellpose masks for cells, nuclei and pathogen images."),
1876
+ "Measure": (lambda frame: initiate_root(frame, settings_type='measure'), "Measure single object intensity and morphological feature. Crop and save single object image"),
1877
+ "Annotate": (lambda frame: initiate_root(frame, settings_type='annotate'), "Annotation single object images on a grid. Annotations are saved to database."),
1878
+ "Make Masks": (lambda frame: initiate_root(frame, settings_type='make_masks'), "Adjust pre-existing Cellpose models to your specific dataset for improved performance"),
1879
+ "Classify": (lambda frame: initiate_root(frame, settings_type='classify'), "Train Torch Convolutional Neural Networks (CNNs) or Transformers to classify single object images."),
1880
+ "Sequencing": (lambda frame: initiate_root(frame, settings_type='sequencing'), "Analyze sequencing data."),
1881
+ "Umap": (lambda frame: initiate_root(frame, settings_type='umap'), "Generate UMAP embeddings with datapoints represented as images."),
1882
+ "Train Cellpose": (lambda frame: initiate_root(frame, settings_type='train_cellpose'), "Train custom Cellpose models."),
1883
+ "ML Analyze": (lambda frame: initiate_root(frame, settings_type='ml_analyze'), "Machine learning analysis of data."),
1884
+ "Cellpose Masks": (lambda frame: initiate_root(frame, settings_type='cellpose_masks'), "Generate Cellpose masks."),
1885
+ "Cellpose All": (lambda frame: initiate_root(frame, settings_type='cellpose_all'), "Run Cellpose on all images."),
1886
+ "Map Barcodes": (lambda frame: initiate_root(frame, settings_type='map_barcodes'), "Map barcodes to data."),
1887
+ "Regression": (lambda frame: initiate_root(frame, settings_type='regression'), "Perform regression analysis."),
1888
+ "Recruitment": (lambda frame: initiate_root(frame, settings_type='recruitment'), "Analyze recruitment data.")
1624
1889
  }
1625
1890
 
1626
1891
  def load_app_wrapper(app_name, app_func):
spacr/gui_utils.py CHANGED
@@ -3,20 +3,13 @@ import tkinter as tk
3
3
  from tkinter import ttk
4
4
 
5
5
  from . gui_core import initiate_root
6
- from .gui_elements import spacrLabel, spacrCheckbutton, AnnotateApp
6
+ from .gui_elements import spacrLabel, spacrCheckbutton, AnnotateApp, spacrEntry, spacrCheck, spacrCombo, set_default_font
7
7
 
8
8
  try:
9
9
  ctypes.windll.shcore.SetProcessDpiAwareness(True)
10
10
  except AttributeError:
11
11
  pass
12
12
 
13
- def set_default_font(root, font_name="Helvetica", size=12):
14
- default_font = (font_name, size)
15
- root.option_add("*Font", default_font)
16
- root.option_add("*TButton.Font", default_font)
17
- root.option_add("*TLabel.Font", default_font)
18
- root.option_add("*TEntry.Font", default_font)
19
-
20
13
  def proceed_with_app_v1(root, app_name, app_func):
21
14
  from .gui import gui_app
22
15
 
@@ -98,6 +91,7 @@ def parse_list(value):
98
91
  except (ValueError, SyntaxError) as e:
99
92
  raise ValueError(f"Invalid format for list: {value}. Error: {e}")
100
93
 
94
+ # Usage example in your create_input_field function
101
95
  def create_input_field(frame, label_text, row, var_type='entry', options=None, default_value=None):
102
96
  label_column = 0
103
97
  widget_column = 1
@@ -107,22 +101,22 @@ def create_input_field(frame, label_text, row, var_type='entry', options=None, d
107
101
  frame.grid_columnconfigure(widget_column, weight=1) # Allow the widget column to expand
108
102
 
109
103
  # Right-align the label text and the label itself
110
- label = spacrLabel(frame, text=label_text, background="black", foreground="white", anchor='e', justify='right')
104
+ label = ttk.Label(frame, text=label_text, background="black", foreground="white", anchor='e', justify='right')
111
105
  label.grid(column=label_column, row=row, sticky=tk.E, padx=(5, 2), pady=5) # Align label to the right
112
106
 
113
107
  if var_type == 'entry':
114
108
  var = tk.StringVar(value=default_value) # Set default value
115
- entry = ttk.Entry(frame, textvariable=var, style='TEntry') # Apply TEntry style for entries
109
+ entry = spacrEntry(frame, textvariable=var, outline=False)
116
110
  entry.grid(column=widget_column, row=row, sticky=tk.W, padx=(2, 5), pady=5) # Align widget to the left
117
111
  return (label, entry, var) # Return both the label and the entry, and the variable
118
112
  elif var_type == 'check':
119
113
  var = tk.BooleanVar(value=default_value) # Set default value (True/False)
120
- check = spacrCheckbutton(frame, text="", variable=var, style='TCheckbutton')
114
+ check = spacrCheck(frame, text="", variable=var)
121
115
  check.grid(column=widget_column, row=row, sticky=tk.W, padx=(2, 5), pady=5) # Align widget to the left
122
116
  return (label, check, var) # Return both the label and the checkbutton, and the variable
123
117
  elif var_type == 'combo':
124
118
  var = tk.StringVar(value=default_value) # Set default value
125
- combo = ttk.Combobox(frame, textvariable=var, values=options, style='TCombobox') # Apply TCombobox style
119
+ combo = spacrCombo(frame, textvariable=var, values=options) # Apply TCombobox style
126
120
  combo.grid(column=widget_column, row=row, sticky=tk.W, padx=(2, 5), pady=5) # Align widget to the left
127
121
  if default_value:
128
122
  combo.set(default_value)
@@ -158,32 +152,32 @@ def cancel_after_tasks(frame):
158
152
  frame.after_cancel(task)
159
153
  frame.after_tasks.clear()
160
154
 
161
- def main_thread_update_function(root, q, fig_queue, canvas_widget, progress_label):
155
+ def main_thread_update_function(root, q, fig_queue, canvas_widget):
162
156
  try:
163
- ansi_escape_pattern = re.compile(r'\x1B\[[0-?]*[ -/]*[@-~]')
157
+ #ansi_escape_pattern = re.compile(r'\x1B\[[0-?]*[ -/]*[@-~]')
164
158
  while not q.empty():
165
159
  message = q.get_nowait()
166
- clean_message = ansi_escape_pattern.sub('', message)
167
- if clean_message.startswith("Progress"):
168
- progress_label.config(text=clean_message)
169
- if clean_message.startswith("\rProgress"):
170
- progress_label.config(text=clean_message)
171
- elif clean_message.startswith("Successfully"):
172
- progress_label.config(text=clean_message)
173
- elif clean_message.startswith("Processing"):
174
- progress_label.config(text=clean_message)
175
- elif clean_message.startswith("scale"):
176
- pass
177
- elif clean_message.startswith("plot_cropped_arrays"):
178
- pass
179
- elif clean_message == "" or clean_message == "\r" or clean_message.strip() == "":
180
- pass
181
- else:
182
- print(clean_message)
160
+ #clean_message = ansi_escape_pattern.sub('', message)
161
+ #if clean_message.startswith("Progress"):
162
+ # progress_label.config(text=clean_message)
163
+ #if clean_message.startswith("\rProgress"):
164
+ # progress_label.config(text=clean_message)
165
+ #elif clean_message.startswith("Successfully"):
166
+ # progress_label.config(text=clean_message)
167
+ #elif clean_message.startswith("Processing"):
168
+ # progress_label.config(text=clean_message)
169
+ #elif clean_message.startswith("scale"):
170
+ # pass
171
+ #elif clean_message.startswith("plot_cropped_arrays"):
172
+ # pass
173
+ #elif clean_message == "" or clean_message == "\r" or clean_message.strip() == "":
174
+ # pass
175
+ #else:
176
+ # print(clean_message)
183
177
  except Exception as e:
184
178
  print(f"Error updating GUI canvas: {e}")
185
179
  finally:
186
- root.after(100, lambda: main_thread_update_function(root, q, fig_queue, canvas_widget, progress_label))
180
+ root.after(100, lambda: main_thread_update_function(root, q, fig_queue, canvas_widget))
187
181
 
188
182
  def annotate(settings):
189
183
  from .settings import set_annotate_default_settings
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: spacr
3
- Version: 0.2.2
3
+ Version: 0.2.3
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