spacr 0.1.11__py3-none-any.whl → 0.1.16__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 +12 -14
- spacr/app_annotate.py +538 -0
- spacr/app_classify.py +206 -0
- spacr/app_make_masks.py +928 -0
- spacr/app_make_masks_v2.py +686 -0
- spacr/app_mask.py +253 -0
- spacr/app_measure.py +253 -0
- spacr/gui.py +15 -17
- spacr/gui_utils.py +152 -106
- spacr/make_masks_app.py +3 -1
- {spacr-0.1.11.dist-info → spacr-0.1.16.dist-info}/METADATA +12 -26
- {spacr-0.1.11.dist-info → spacr-0.1.16.dist-info}/RECORD +16 -10
- spacr-0.1.16.dist-info/entry_points.txt +8 -0
- spacr-0.1.11.dist-info/entry_points.txt +0 -9
- {spacr-0.1.11.dist-info → spacr-0.1.16.dist-info}/LICENSE +0 -0
- {spacr-0.1.11.dist-info → spacr-0.1.16.dist-info}/WHEEL +0 -0
- {spacr-0.1.11.dist-info → spacr-0.1.16.dist-info}/top_level.txt +0 -0
spacr/gui_utils.py
CHANGED
@@ -10,7 +10,6 @@ from torchvision import models
|
|
10
10
|
|
11
11
|
from tkinter import font as tkFont
|
12
12
|
|
13
|
-
|
14
13
|
from .logger import log_function_call
|
15
14
|
|
16
15
|
try:
|
@@ -65,11 +64,11 @@ def load_app(root, app_name, app_func):
|
|
65
64
|
app_func(root.content_frame)
|
66
65
|
|
67
66
|
def create_menu_bar(root):
|
68
|
-
from .
|
69
|
-
from .
|
70
|
-
from .
|
71
|
-
from .
|
72
|
-
from .
|
67
|
+
from .app_mask import initiate_mask_root
|
68
|
+
from .app_measure import initiate_measure_root
|
69
|
+
from .app_annotate import initiate_annotation_app_root
|
70
|
+
from .app_make_masks import initiate_mask_app_root
|
71
|
+
from .app_classify import initiate_classify_root
|
73
72
|
|
74
73
|
gui_apps = {
|
75
74
|
"Mask": initiate_mask_root,
|
@@ -96,6 +95,42 @@ def create_menu_bar(root):
|
|
96
95
|
# Configure the menu for the root window
|
97
96
|
root.config(menu=menu_bar)
|
98
97
|
|
98
|
+
def proceed_with_app(root, app_name, app_func):
|
99
|
+
|
100
|
+
from .app_mask import gui_mask
|
101
|
+
from .app_measure import gui_measure
|
102
|
+
from .app_annotate import gui_annotate
|
103
|
+
from .app_make_masks import gui_make_masks
|
104
|
+
from .app_classify import gui_classify
|
105
|
+
from .gui import gui_app
|
106
|
+
|
107
|
+
# Clear the current content frame
|
108
|
+
if hasattr(root, 'content_frame'):
|
109
|
+
for widget in root.content_frame.winfo_children():
|
110
|
+
widget.destroy()
|
111
|
+
else:
|
112
|
+
root.content_frame = tk.Frame(root)
|
113
|
+
root.content_frame.grid(row=1, column=0, sticky="nsew")
|
114
|
+
root.grid_rowconfigure(1, weight=1)
|
115
|
+
root.grid_columnconfigure(0, weight=1)
|
116
|
+
|
117
|
+
# Initialize the new app in the content frame
|
118
|
+
if app_name == "Main App":
|
119
|
+
root.destroy() # Close the current window
|
120
|
+
gui_app() # Open the main app window
|
121
|
+
elif app_name == "Mask":
|
122
|
+
gui_mask()
|
123
|
+
elif app_name == "Measure":
|
124
|
+
gui_measure()
|
125
|
+
elif app_name == "Annotate":
|
126
|
+
gui_annotate()
|
127
|
+
elif app_name == "Make Masks":
|
128
|
+
gui_make_masks()
|
129
|
+
elif app_name == "Classify":
|
130
|
+
gui_classify()
|
131
|
+
else:
|
132
|
+
raise ValueError(f"Invalid app name: {app_name}")
|
133
|
+
|
99
134
|
def load_app(root, app_name, app_func):
|
100
135
|
# Cancel all scheduled after tasks
|
101
136
|
if hasattr(root, 'after_tasks'):
|
@@ -103,35 +138,24 @@ def load_app(root, app_name, app_func):
|
|
103
138
|
root.after_cancel(task)
|
104
139
|
root.after_tasks = []
|
105
140
|
|
106
|
-
def proceed_with_app():
|
107
|
-
# Clear the current content frame
|
108
|
-
if hasattr(root, 'content_frame'):
|
109
|
-
for widget in root.content_frame.winfo_children():
|
110
|
-
widget.destroy()
|
111
|
-
else:
|
112
|
-
root.content_frame = tk.Frame(root)
|
113
|
-
root.content_frame.grid(row=1, column=0, sticky="nsew")
|
114
|
-
root.grid_rowconfigure(1, weight=1)
|
115
|
-
root.grid_columnconfigure(0, weight=1)
|
116
|
-
|
117
|
-
# Initialize the new app in the content frame
|
118
|
-
app_func(root.content_frame)
|
119
|
-
|
120
141
|
# Exit functionality only for the annotation app
|
121
142
|
if app_name != "Annotate" and hasattr(root, 'current_app_exit_func'):
|
122
143
|
root.next_app_func = proceed_with_app
|
144
|
+
root.next_app_args = (app_name, app_func) # Ensure correct arguments
|
123
145
|
root.current_app_exit_func()
|
124
146
|
else:
|
125
|
-
proceed_with_app()
|
147
|
+
proceed_with_app(root, app_name, app_func)
|
126
148
|
|
127
149
|
def create_menu_bar(root):
|
128
|
-
from .
|
129
|
-
from .
|
130
|
-
from .
|
131
|
-
from .
|
132
|
-
from .
|
150
|
+
from .app_mask import initiate_mask_root
|
151
|
+
from .app_measure import initiate_measure_root
|
152
|
+
from .app_annotate import initiate_annotation_app_root
|
153
|
+
from .app_make_masks import initiate_mask_app_root
|
154
|
+
from .app_classify import initiate_classify_root
|
155
|
+
from .gui import gui_app
|
133
156
|
|
134
157
|
gui_apps = {
|
158
|
+
"Main App": gui_app,
|
135
159
|
"Mask": initiate_mask_root,
|
136
160
|
"Measure": initiate_measure_root,
|
137
161
|
"Annotate": initiate_annotation_app_root,
|
@@ -162,14 +186,19 @@ class CustomButton(tk.Frame):
|
|
162
186
|
self.text = text
|
163
187
|
self.command = command
|
164
188
|
|
165
|
-
|
189
|
+
# Detect screen height and calculate button dimensions
|
190
|
+
screen_height = self.winfo_screenheight()
|
191
|
+
button_height = screen_height // 50
|
192
|
+
button_width = button_height * 3
|
193
|
+
|
194
|
+
self.canvas = tk.Canvas(self, width=button_width, height=button_height, highlightthickness=0, bg="black")
|
166
195
|
self.canvas.grid(row=0, column=0)
|
167
196
|
|
168
|
-
self.button_bg = self.create_rounded_rectangle(0, 0,
|
197
|
+
self.button_bg = self.create_rounded_rectangle(0, 0, button_width, button_height, radius=20, fill="#800080")
|
169
198
|
|
170
199
|
# Use the passed font or default to Helvetica if not provided
|
171
200
|
self.font_style = font if font else tkFont.Font(family="Helvetica", size=12, weight=tkFont.NORMAL)
|
172
|
-
self.button_text = self.canvas.create_text(
|
201
|
+
self.button_text = self.canvas.create_text(button_width // 2, button_height // 2, text=self.text, fill="white", font=self.font_style)
|
173
202
|
|
174
203
|
self.bind("<Enter>", self.on_enter)
|
175
204
|
self.bind("<Leave>", self.on_leave)
|
@@ -307,38 +336,6 @@ def set_default_font(root, font_name="Helvetica", size=12):
|
|
307
336
|
root.option_add("*TLabel.Font", default_font)
|
308
337
|
root.option_add("*TEntry.Font", default_font)
|
309
338
|
|
310
|
-
def check_and_download_font_v1():
|
311
|
-
font_name = "Helvetica"
|
312
|
-
font_dir = "fonts"
|
313
|
-
font_path = os.path.join(font_dir, "OpenSans-Regular.ttf")
|
314
|
-
|
315
|
-
# Check if the font is already available
|
316
|
-
available_fonts = list(tkFont.families())
|
317
|
-
if font_name not in available_fonts:
|
318
|
-
print(f"Font '{font_name}' not found. Downloading...")
|
319
|
-
if not os.path.exists(font_dir):
|
320
|
-
os.makedirs(font_dir)
|
321
|
-
|
322
|
-
if not os.path.exists(font_path):
|
323
|
-
url = "https://github.com/google/fonts/blob/main/apache/opensans/OpenSans-Regular.ttf?raw=true"
|
324
|
-
response = requests.get(url)
|
325
|
-
with open(font_path, "wb") as f:
|
326
|
-
f.write(response.content)
|
327
|
-
|
328
|
-
# Load the font
|
329
|
-
try:
|
330
|
-
tkFont.nametofont("TkDefaultFont").configure(family=font_name, size=10)
|
331
|
-
tkFont.nametofont("TkTextFont").configure(family=font_name, size=10)
|
332
|
-
tkFont.nametofont("TkHeadingFont").configure(family=font_name, size=12)
|
333
|
-
except tk.TclError:
|
334
|
-
tkFont.nametofont("TkDefaultFont").configure(family="Helvetica", size=10)
|
335
|
-
tkFont.nametofont("TkTextFont").configure(family="Helvetica", size=10)
|
336
|
-
tkFont.nametofont("TkHeadingFont").configure(family="Helvetica", size=12)
|
337
|
-
else:
|
338
|
-
tkFont.nametofont("TkDefaultFont").configure(family=font_name, size=10)
|
339
|
-
tkFont.nametofont("TkTextFont").configure(family=font_name, size=10)
|
340
|
-
tkFont.nametofont("TkHeadingFont").configure(family=font_name, size=12)
|
341
|
-
|
342
339
|
def check_and_download_font():
|
343
340
|
font_name = "Helvetica"
|
344
341
|
font_dir = "fonts"
|
@@ -356,8 +353,6 @@ def check_and_download_font():
|
|
356
353
|
response = requests.get(url)
|
357
354
|
with open(font_path, "wb") as f:
|
358
355
|
f.write(response.content)
|
359
|
-
|
360
|
-
# Load the font
|
361
356
|
try:
|
362
357
|
tkFont.nametofont("TkDefaultFont").configure(family=font_name, size=10)
|
363
358
|
tkFont.nametofont("TkTextFont").configure(family=font_name, size=10)
|
@@ -371,32 +366,39 @@ def check_and_download_font():
|
|
371
366
|
tkFont.nametofont("TkTextFont").configure(family=font_name, size=10)
|
372
367
|
tkFont.nametofont("TkHeadingFont").configure(family=font_name, size=12)
|
373
368
|
|
374
|
-
def
|
375
|
-
|
376
|
-
|
377
|
-
style.configure('
|
378
|
-
style.configure('TCombobox', fieldbackground='#000000', background='#000000', foreground='#ffffff', font=font_style)
|
369
|
+
def set_dark_style_v1(style):
|
370
|
+
font_style = tkFont.Font(family="Helvetica", size=10)
|
371
|
+
style.configure('TEntry', padding='5 5 5 5', borderwidth=1, relief='solid', fieldbackground='black', foreground='#ffffff', font=font_style)
|
372
|
+
style.configure('TCombobox', fieldbackground='black', background='black', foreground='#ffffff', font=font_style)
|
379
373
|
style.configure('Custom.TButton', padding='10 10 10 10', borderwidth=1, relief='solid', background='#008080', foreground='#ffffff', font=font_style)
|
380
374
|
style.map('Custom.TButton',
|
381
375
|
background=[('active', '#66b2b2'), ('disabled', '#004d4d'), ('!disabled', '#008080')],
|
382
376
|
foreground=[('active', '#ffffff'), ('disabled', '#888888')])
|
383
|
-
style.configure('Custom.TLabel', padding='5 5 5 5', borderwidth=1, relief='flat', background='
|
384
|
-
style.configure('TCheckbutton', background='
|
377
|
+
style.configure('Custom.TLabel', padding='5 5 5 5', borderwidth=1, relief='flat', background='black', foreground='#ffffff', font=font_style)
|
378
|
+
style.configure('TCheckbutton', background='black', foreground='#ffffff', indicatoron=False, relief='flat', font=font_style)
|
385
379
|
style.map('TCheckbutton', background=[('selected', '#555555'), ('active', '#555555')])
|
386
380
|
|
387
|
-
def
|
381
|
+
def set_dark_style(style):
|
388
382
|
font_style = tkFont.Font(family="Helvetica", size=10)
|
389
|
-
style.configure('TEntry', padding='5 5 5 5', borderwidth=1, relief='solid', fieldbackground='
|
390
|
-
style.configure('TCombobox', fieldbackground='
|
391
|
-
style.configure('Custom.TButton', padding='10 10 10 10', borderwidth=1, relief='solid', background='#008080', foreground='#ffffff', font=font_style)
|
383
|
+
style.configure('TEntry', padding='5 5 5 5', borderwidth=1, relief='solid', fieldbackground='black', foreground='#ffffff', font=font_style) # Entry
|
384
|
+
style.configure('TCombobox', fieldbackground='black', background='black', foreground='#ffffff', font=font_style) # Combobox
|
385
|
+
style.configure('Custom.TButton', padding='10 10 10 10', borderwidth=1, relief='solid', background='#008080', foreground='#ffffff', font=font_style) # Custom Button
|
392
386
|
style.map('Custom.TButton',
|
393
387
|
background=[('active', '#66b2b2'), ('disabled', '#004d4d'), ('!disabled', '#008080')],
|
394
388
|
foreground=[('active', '#ffffff'), ('disabled', '#888888')])
|
395
|
-
style.configure('Custom.TLabel', padding='5 5 5 5', borderwidth=1, relief='flat', background='
|
396
|
-
style.configure('TCheckbutton', background='
|
389
|
+
style.configure('Custom.TLabel', padding='5 5 5 5', borderwidth=1, relief='flat', background='black', foreground='#ffffff', font=font_style) # Custom Label
|
390
|
+
style.configure('TCheckbutton', background='black', foreground='#ffffff', indicatoron=False, relief='flat', font=font_style) # Checkbutton
|
397
391
|
style.map('TCheckbutton', background=[('selected', '#555555'), ('active', '#555555')])
|
398
|
-
|
399
|
-
|
392
|
+
style.configure('TLabel', background='black', foreground='#ffffff', font=font_style) # Label
|
393
|
+
style.configure('TFrame', background='black') # Frame
|
394
|
+
style.configure('TPanedwindow', background='black') # PanedWindow
|
395
|
+
style.configure('TNotebook', background='black', tabmargins=[2, 5, 2, 0]) # Notebook
|
396
|
+
style.configure('TNotebook.Tab', background='black', foreground='#ffffff', padding=[5, 5], font=font_style)
|
397
|
+
style.map('TNotebook.Tab', background=[('selected', '#555555'), ('active', '#555555')])
|
398
|
+
style.configure('TButton', background='black', foreground='#ffffff', padding='5 5 5 5', font=font_style) # Button (regular)
|
399
|
+
style.map('TButton', background=[('active', '#555555'), ('disabled', '#333333')])
|
400
|
+
style.configure('Vertical.TScrollbar', background='black', troughcolor='black', bordercolor='black') # Scrollbar
|
401
|
+
style.configure('Horizontal.TScrollbar', background='black', troughcolor='black', bordercolor='black')
|
400
402
|
|
401
403
|
def read_settings_from_csv(csv_file_path):
|
402
404
|
settings = {}
|
@@ -435,36 +437,45 @@ def disable_interactivity(fig):
|
|
435
437
|
for handler_id in list(handlers.keys()):
|
436
438
|
fig.canvas.mpl_disconnect(handler_id)
|
437
439
|
|
438
|
-
class
|
440
|
+
class ScrollableFrame_v1(ttk.Frame):
|
439
441
|
def __init__(self, container, *args, bg='black', **kwargs):
|
440
442
|
super().__init__(container, *args, **kwargs)
|
441
|
-
self.configure(style='TFrame')
|
442
|
-
|
443
|
-
|
443
|
+
self.configure(style='TFrame')
|
444
|
+
screen_width = self.winfo_screenwidth()
|
445
|
+
frame_width = screen_width // 4 # Set the frame width to 1/4th of the screen width
|
446
|
+
canvas = tk.Canvas(self, bg=bg, width=frame_width) # Set canvas background to match dark mode
|
444
447
|
scrollbar = ttk.Scrollbar(self, orient="vertical", command=canvas.yview)
|
445
|
-
|
446
|
-
self.scrollable_frame = ttk.Frame(canvas, style='TFrame') # Ensure it uses the styled frame
|
448
|
+
self.scrollable_frame = ttk.Frame(canvas, style='TFrame', padding=5) # Ensure it uses the styled frame
|
447
449
|
self.scrollable_frame.bind(
|
448
450
|
"<Configure>",
|
449
451
|
lambda e: canvas.configure(scrollregion=canvas.bbox("all"))
|
450
452
|
)
|
451
|
-
|
452
453
|
canvas.create_window((0, 0), window=self.scrollable_frame, anchor="nw")
|
453
454
|
canvas.configure(yscrollcommand=scrollbar.set)
|
454
|
-
|
455
455
|
canvas.pack(side="left", fill="both", expand=True)
|
456
456
|
scrollbar.pack(side="right", fill="y")
|
457
457
|
|
458
|
-
class
|
459
|
-
def __init__(self,
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
458
|
+
class ScrollableFrame(ttk.Frame):
|
459
|
+
def __init__(self, container, width=None, *args, bg='black', **kwargs):
|
460
|
+
super().__init__(container, *args, **kwargs)
|
461
|
+
self.configure(style='TFrame')
|
462
|
+
if width is None:
|
463
|
+
screen_width = self.winfo_screenwidth()
|
464
|
+
width = screen_width // 4
|
465
|
+
canvas = tk.Canvas(self, bg=bg, width=width)
|
466
|
+
scrollbar = ttk.Scrollbar(self, orient="vertical", command=canvas.yview)
|
467
|
+
|
468
|
+
self.scrollable_frame = ttk.Frame(canvas, style='TFrame')
|
469
|
+
self.scrollable_frame.bind(
|
470
|
+
"<Configure>",
|
471
|
+
lambda e: canvas.configure(scrollregion=canvas.bbox("all"))
|
472
|
+
)
|
473
|
+
canvas.create_window((0, 0), window=self.scrollable_frame, anchor="nw")
|
474
|
+
canvas.configure(yscrollcommand=scrollbar.set)
|
475
|
+
canvas.pack(side="left", fill="both", expand=True)
|
476
|
+
scrollbar.pack(side="right", fill="y")
|
477
|
+
for child in self.scrollable_frame.winfo_children():
|
478
|
+
child.configure(bg='black')
|
468
479
|
|
469
480
|
class StdoutRedirector:
|
470
481
|
def __init__(self, text_widget):
|
@@ -767,7 +778,7 @@ def create_input_field(frame, label_text, row, var_type='entry', options=None, d
|
|
767
778
|
return (label, entry, var) # Return both the label and the entry, and the variable
|
768
779
|
elif var_type == 'check':
|
769
780
|
var = tk.BooleanVar(value=default_value) # Set default value (True/False)
|
770
|
-
check = ToggleSwitch(frame, text=
|
781
|
+
check = ToggleSwitch(frame, text="", variable=var) # Use ToggleSwitch class
|
771
782
|
check.grid(column=1, row=row, sticky=tk.W, padx=5)
|
772
783
|
return (label, check, var) # Return both the label and the checkbutton, and the variable
|
773
784
|
elif var_type == 'combo':
|
@@ -780,10 +791,43 @@ def create_input_field(frame, label_text, row, var_type='entry', options=None, d
|
|
780
791
|
else:
|
781
792
|
var = None # Placeholder in case of an undefined var_type
|
782
793
|
return (label, None, var)
|
794
|
+
|
795
|
+
def convert_settings_dict_for_gui(settings):
|
796
|
+
variables = {}
|
797
|
+
special_cases = {
|
798
|
+
'metadata_type': ('combo', ['cellvoyager', 'cq1', 'nikon', 'zeis', 'custom'], 'cellvoyager'),
|
799
|
+
'channels': ('combo', ['[0,1,2,3]', '[0,1,2]', '[0,1]', '[0]'], '[0,1,2,3]'),
|
800
|
+
'magnification': ('combo', [20, 40, 60], 20),
|
801
|
+
'nucleus_channel': ('combo', [0, 1, 2, 3, None], None),
|
802
|
+
'cell_channel': ('combo', [0, 1, 2, 3, None], None),
|
803
|
+
'pathogen_channel': ('combo', [0, 1, 2, 3, None], None),
|
804
|
+
'timelapse_mode': ('combo', ['trackpy', 'btrack'], 'trackpy'),
|
805
|
+
'timelapse_objects': ('combo', ['cell', 'nucleus', 'pathogen', 'cytoplasm', None], None),
|
806
|
+
'model_type': ('combo', ['resnet50', 'other_model'], 'resnet50'),
|
807
|
+
'optimizer_type': ('combo', ['adamw', 'adam'], 'adamw'),
|
808
|
+
'schedule': ('combo', ['reduce_lr_on_plateau', 'step_lr'], 'reduce_lr_on_plateau'),
|
809
|
+
'loss_type': ('combo', ['focal_loss', 'binary_cross_entropy_with_logits'], 'focal_loss'),
|
810
|
+
'normalize_by': ('combo', ['fov', 'png'], 'png'),
|
811
|
+
}
|
812
|
+
for key, value in settings.items():
|
813
|
+
if key in special_cases:
|
814
|
+
variables[key] = special_cases[key]
|
815
|
+
elif isinstance(value, bool):
|
816
|
+
variables[key] = ('check', None, value)
|
817
|
+
elif isinstance(value, int) or isinstance(value, float):
|
818
|
+
variables[key] = ('entry', None, value)
|
819
|
+
elif isinstance(value, str):
|
820
|
+
variables[key] = ('entry', None, value)
|
821
|
+
elif value is None:
|
822
|
+
variables[key] = ('entry', None, value)
|
823
|
+
elif isinstance(value, list):
|
824
|
+
variables[key] = ('entry', None, str(value))
|
825
|
+
return variables
|
783
826
|
|
784
827
|
def mask_variables():
|
785
828
|
variables = {
|
786
|
-
'src': ('entry', None, '/
|
829
|
+
'src': ('entry', None, 'path/to/images'),
|
830
|
+
'pathogen_model': ('entry', None, 'path/to/model'),
|
787
831
|
'metadata_type': ('combo', ['cellvoyager', 'cq1', 'nikon', 'zeis', 'custom'], 'cellvoyager'),
|
788
832
|
'custom_regex': ('entry', None, None),
|
789
833
|
'experiment': ('entry', None, 'exp'),
|
@@ -793,14 +837,17 @@ def mask_variables():
|
|
793
837
|
'nucleus_background': ('entry', None, 100),
|
794
838
|
'nucleus_Signal_to_noise': ('entry', None, 5),
|
795
839
|
'nucleus_CP_prob': ('entry', None, 0),
|
840
|
+
'remove_background_nucleus': ('check', None, False),
|
796
841
|
'cell_channel': ('combo', [0,1,2,3, None], 3),
|
797
842
|
'cell_background': ('entry', None, 100),
|
798
843
|
'cell_Signal_to_noise': ('entry', None, 5),
|
799
844
|
'cell_CP_prob': ('entry', None, 0),
|
845
|
+
'remove_background_cell': ('check', None, False),
|
800
846
|
'pathogen_channel': ('combo', [0,1,2,3, None], 2),
|
801
847
|
'pathogen_background': ('entry', None, 100),
|
802
848
|
'pathogen_Signal_to_noise': ('entry', None, 3),
|
803
849
|
'pathogen_CP_prob': ('entry', None, 0),
|
850
|
+
'remove_background_pathogen': ('check', None, False),
|
804
851
|
'preprocess': ('check', None, True),
|
805
852
|
'masks': ('check', None, True),
|
806
853
|
'examples_to_plot': ('entry', None, 1),
|
@@ -816,7 +863,7 @@ def mask_variables():
|
|
816
863
|
'fps': ('entry', None, 2),
|
817
864
|
'remove_background': ('check', None, True),
|
818
865
|
'lower_quantile': ('entry', None, 0.01),
|
819
|
-
'merge': ('check', None, False),
|
866
|
+
#'merge': ('check', None, False),
|
820
867
|
'normalize_plots': ('check', None, True),
|
821
868
|
'all_to_mip': ('check', None, False),
|
822
869
|
'pick_slice': ('check', None, False),
|
@@ -825,6 +872,11 @@ def mask_variables():
|
|
825
872
|
'plot': ('check', None, True),
|
826
873
|
'workers': ('entry', None, 30),
|
827
874
|
'verbose': ('check', None, True),
|
875
|
+
'filter': ('check', None, True),
|
876
|
+
'merge_pathogens': ('check', None, True),
|
877
|
+
'adjust_cells': ('check', None, True),
|
878
|
+
'test_images': ('entry', None, 10),
|
879
|
+
'random_test': ('check', None, True),
|
828
880
|
}
|
829
881
|
return variables
|
830
882
|
|
@@ -845,7 +897,7 @@ def add_mask_gui_defaults(settings):
|
|
845
897
|
|
846
898
|
def generate_fields(variables, scrollable_frame):
|
847
899
|
vars_dict = {}
|
848
|
-
row =
|
900
|
+
row = 5
|
849
901
|
tooltips = {
|
850
902
|
"src": "Path to the folder containing the images.",
|
851
903
|
"metadata_type": "Type of metadata to expect in the images. This will determine how the images are processed. If 'custom' is selected, you can provide a custom regex pattern to extract metadata from the image names",
|
@@ -967,12 +1019,6 @@ def create_dark_mode(root, style, console_output):
|
|
967
1019
|
if console_output != None:
|
968
1020
|
console_output.config(bg=dark_bg, fg=light_text, insertbackground=light_text) #, font=("Helvetica", 12)
|
969
1021
|
root.configure(bg=dark_bg)
|
970
|
-
|
971
|
-
def set_dark_style(style):
|
972
|
-
style.configure('TFrame', background='black')
|
973
|
-
style.configure('TLabel', background='black', foreground='white')
|
974
|
-
style.configure('TEntry', background='black', foreground='white')
|
975
|
-
style.configure('TCheckbutton', background='black', foreground='white')
|
976
1022
|
|
977
1023
|
##@log_function_call
|
978
1024
|
def main_thread_update_function(root, q, fig_queue, canvas_widget, progress_label):
|
spacr/make_masks_app.py
CHANGED
@@ -905,7 +905,9 @@ def initiate_mask_app_root(parent_frame):
|
|
905
905
|
|
906
906
|
def gui_make_masks():
|
907
907
|
root = tk.Tk()
|
908
|
-
root.
|
908
|
+
width = root.winfo_screenwidth()
|
909
|
+
height = root.winfo_screenheight()
|
910
|
+
root.geometry(f"{width}x{height}")
|
909
911
|
root.title("Mask Application")
|
910
912
|
|
911
913
|
# Clear previous content if any
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: spacr
|
3
|
-
Version: 0.1.
|
3
|
+
Version: 0.1.16
|
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,7 +9,6 @@ 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: dgl ==0.9.1
|
13
12
|
Requires-Dist: torch <3.0,>=2.2.1
|
14
13
|
Requires-Dist: torchvision <1.0,>=0.17.1
|
15
14
|
Requires-Dist: torch-geometric <3.0,>=2.5.1
|
@@ -40,12 +39,8 @@ Requires-Dist: ttf-opensans >=2020.10.30
|
|
40
39
|
Requires-Dist: customtkinter <6.0,>=5.2.2
|
41
40
|
Requires-Dist: biopython <2.0,>=1.80
|
42
41
|
Requires-Dist: lxml <6.0,>=5.1.0
|
43
|
-
Requires-Dist: qtpy <2.5,>=2.4.1
|
44
|
-
Requires-Dist: superqt <0.7,>=0.6.7
|
45
|
-
Requires-Dist: pyqt6 <6.8,>=6.7.1
|
46
|
-
Requires-Dist: pyqtgraph <0.14,>=0.13.7
|
47
42
|
Provides-Extra: dev
|
48
|
-
Requires-Dist: pytest
|
43
|
+
Requires-Dist: pytest <3.11,>=3.9 ; extra == 'dev'
|
49
44
|
Provides-Extra: full
|
50
45
|
Requires-Dist: opencv-python ; extra == 'full'
|
51
46
|
Provides-Extra: headless
|
@@ -67,7 +62,7 @@ Requires-Dist: opencv-python-headless ; extra == 'headless'
|
|
67
62
|
SpaCr
|
68
63
|
=====
|
69
64
|
|
70
|
-
Spatial phenotype analysis of CRISPR-Cas9 screens (SpaCr). The spatial organization of organelles and proteins within cells constitutes a key level of functional regulation. In the context of infectious disease, the spatial relationships between host cell structures and intracellular pathogens are critical to
|
65
|
+
Spatial phenotype analysis of CRISPR-Cas9 screens (SpaCr). The spatial organization of organelles and proteins within cells constitutes a key level of functional regulation. In the context of infectious disease, the spatial relationships between host cell structures and intracellular pathogens are critical to understanding host clearance mechanisms and how pathogens evade them. SpaCr is a Python-based software package for generating single-cell image data for deep-learning sub-cellular/cellular phenotypic classification from pooled genetic CRISPR-Cas9 screens. SpaCr provides a flexible toolset to extract single-cell images and measurements from high-content cell painting experiments, train deep-learning models to classify cellular/subcellular phenotypes, simulate, and analyze pooled CRISPR-Cas9 imaging screens.
|
71
66
|
|
72
67
|
Features
|
73
68
|
--------
|
@@ -76,9 +71,9 @@ Features
|
|
76
71
|
|
77
72
|
- **Object Measurements:** Measurements for each object including scikit-image-regionprops, intensity percentiles, shannon-entropy, pearsons and manders correlations, homogeneity, and radial distribution. Measurements are saved to a SQL database in object-level tables.
|
78
73
|
|
79
|
-
- **Crop Images:**
|
74
|
+
- **Crop Images:** Save objects (cells, nuclei, pathogen, cytoplasm) as images. Object image paths are saved in a SQL database.
|
80
75
|
|
81
|
-
- **Train CNNs or Transformers:** Train Torch
|
76
|
+
- **Train CNNs or Transformers:** Train Torch models to classify single object images.
|
82
77
|
|
83
78
|
- **Manual Annotation:** Supports manual annotation of single-cell images and segmentation to refine training datasets for training CNNs/Transformers or cellpose, respectively.
|
84
79
|
|
@@ -95,29 +90,20 @@ Features
|
|
95
90
|
Installation
|
96
91
|
------------
|
97
92
|
|
98
|
-
|
93
|
+
If using Windows, switch to Linux—it's free, open-source, and better.
|
99
94
|
|
100
|
-
|
101
|
-
~~~~~~
|
95
|
+
Before installing SpaCr on OSX ensure OpenMP is installed::
|
102
96
|
|
103
|
-
|
97
|
+
brew install libomp
|
104
98
|
|
105
|
-
(Tkinter is included with the standard Python installation on macOS
|
106
|
-
|
107
|
-
On Linux:
|
108
|
-
|
109
|
-
::
|
99
|
+
SpaCr GUI requires Tkinter. On Linux, ensure Tkinter is installed. (Tkinter is included with the standard Python installation on macOS and Windows)::
|
110
100
|
|
111
101
|
sudo apt-get install python3-tk
|
112
102
|
|
113
|
-
Install
|
114
|
-
|
115
|
-
::
|
103
|
+
Install SpaCr with pip::
|
116
104
|
|
117
105
|
pip install spacr
|
118
106
|
|
119
|
-
Run
|
120
|
-
|
121
|
-
::
|
107
|
+
Run SpaCr GUI::
|
122
108
|
|
123
|
-
|
109
|
+
spacr
|
@@ -1,8 +1,14 @@
|
|
1
|
-
spacr/__init__.py,sha256=
|
1
|
+
spacr/__init__.py,sha256=xu2zNv8A523YvDACynkThH2CYqN5mafsu9lfKGjMmIM,1278
|
2
2
|
spacr/__main__.py,sha256=bkAJJD2kjIqOP-u1kLvct9jQQCeUXzlEjdgitwi1Lm8,75
|
3
3
|
spacr/alpha.py,sha256=Y95sLEfpK2OSYKRn3M8eUOU33JJeXfV8zhrC4KnwSTY,35244
|
4
4
|
spacr/annotate_app.py,sha256=imQ7ZEXDyM6ce1dxZ1xUS1-KequuF_NCI4xCaPLjvco,29275
|
5
5
|
spacr/annotate_app_v2.py,sha256=imQ7ZEXDyM6ce1dxZ1xUS1-KequuF_NCI4xCaPLjvco,29275
|
6
|
+
spacr/app_annotate.py,sha256=27NzovmbcSa-zdqo9WrFfBcggybhVQmKbgSBDTFnSvU,23588
|
7
|
+
spacr/app_classify.py,sha256=7UKRGW245Chtxc_oCmyS-4omQpffvzzBvsHmC5ey4v8,8665
|
8
|
+
spacr/app_make_masks.py,sha256=ksggY0xBWt7Fgbd451JOabA064kcjiDm8MTslUq1FLo,45088
|
9
|
+
spacr/app_make_masks_v2.py,sha256=csZbUFhOfdHCQ1Wi21bgC1PG8ll5InMqUVmY3-90xlc,30543
|
10
|
+
spacr/app_mask.py,sha256=dDZyIlI71vSMqBT3tC9I3BN8J0kxRf9-h5gBiI7pWZk,11357
|
11
|
+
spacr/app_measure.py,sha256=jOhtqpO6BQSEpeUZA3taR9jThmo0J7BXMq1URzrdyjA,10841
|
6
12
|
spacr/chris.py,sha256=YlBjSgeZaY8HPy6jkrT_ISAnCMAKVfvCxF0I9eAZLFM,2418
|
7
13
|
spacr/classify_app.py,sha256=Zi15ryc1ocYitRF4kyxlC27XxGyzfSPdvj2d6ZrSh7E,8446
|
8
14
|
spacr/cli.py,sha256=507jfOOEV8BoL4eeUcblvH-iiDHdBrEVJLu1ghAAPSc,1800
|
@@ -11,7 +17,7 @@ spacr/deep_spacr.py,sha256=N0o7ILD2p1FTfU4DFxnpjs00xjLhwib-ev0XGqA6muU,37035
|
|
11
17
|
spacr/foldseek.py,sha256=YIP1d4Ci6CeA9jSyiv-HTDbNmAmcSM9Y_DaOs7wYzLY,33546
|
12
18
|
spacr/get_alfafold_structures.py,sha256=ehx_MQgb12k3hFecP6cYVlm5TLO8iWjgevy8ESyS3cw,3544
|
13
19
|
spacr/graph_learning.py,sha256=1tR-ZxvXE3dBz1Saw7BeVFcrsUFu9OlUZeZVifih9eo,13070
|
14
|
-
spacr/gui.py,sha256=
|
20
|
+
spacr/gui.py,sha256=xyf2bmAck8OrbYlvNLpY6rs4EuhuCOxff3f8ZcEZHBQ,6594
|
15
21
|
spacr/gui_2.py,sha256=ZAI5quQYbhQJ40vK0NCqU_UMSPLkpfeQpomBWUSM0fc,6946
|
16
22
|
spacr/gui_annotate.py,sha256=ugBksLGOHdtOLlEuRyyc59TrkYKu3rDf8JxEgiBSVao,6536
|
17
23
|
spacr/gui_classify_app.py,sha256=Zi15ryc1ocYitRF4kyxlC27XxGyzfSPdvj2d6ZrSh7E,8446
|
@@ -20,10 +26,10 @@ spacr/gui_make_masks_app_v2.py,sha256=X3izTBXdCZDlkVe-fbG-jmCQtcAbmK0OIivjyWaLhu
|
|
20
26
|
spacr/gui_mask_app.py,sha256=mhTl_XzXLFl8Tx3WYEMpdYB_qw9u5JJa0EdkvlcIzAE,10706
|
21
27
|
spacr/gui_measure_app.py,sha256=_C1-XFL5HSquUEEbM_NcxdvHx-socPFCx85MBG4d6xo,10598
|
22
28
|
spacr/gui_sim_app.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
23
|
-
spacr/gui_utils.py,sha256=
|
29
|
+
spacr/gui_utils.py,sha256=emUGYxxk9LOsYk2ozLc6mfglzeb4WqBwYhXwitLLJBA,58746
|
24
30
|
spacr/io.py,sha256=IoERqSwoxJrInYl-E0WfwFOEDZXFdJofk5DmpbyLGWM,112077
|
25
31
|
spacr/logger.py,sha256=7Zqr3TuuOQLWT32gYr2q1qvv7x0a2JhLANmZcnBXAW8,670
|
26
|
-
spacr/make_masks_app.py,sha256=
|
32
|
+
spacr/make_masks_app.py,sha256=iGaTwhowoe2JMOSOf8bJwQZTooRhLQx7KO0ewnAmqDY,45138
|
27
33
|
spacr/make_masks_app_v2.py,sha256=X3izTBXdCZDlkVe-fbG-jmCQtcAbmK0OIivjyWaLhug,30576
|
28
34
|
spacr/mask_app.py,sha256=mhTl_XzXLFl8Tx3WYEMpdYB_qw9u5JJa0EdkvlcIzAE,10706
|
29
35
|
spacr/measure.py,sha256=0FRsHF5ftar4JZ0B_6Nq-NlyP5t6aiO0IrskyikIBEE,55000
|
@@ -40,9 +46,9 @@ spacr/version.py,sha256=axH5tnGwtgSnJHb5IDhiu4Zjk5GhLyAEDRe-rnaoFOA,409
|
|
40
46
|
spacr/models/cp/toxo_plaque_cyto_e25000_X1120_Y1120.CP_model,sha256=z8BbHWZPRnE9D_BHO0fBREE85c1vkltDs-incs2ytXQ,26566572
|
41
47
|
spacr/models/cp/toxo_plaque_cyto_e25000_X1120_Y1120.CP_model_settings.csv,sha256=fBAGuL_B8ERVdVizO3BHozTDSbZUh1yFzsYK3wkQN68,420
|
42
48
|
spacr/models/cp/toxo_pv_lumen.CP_model,sha256=2y_CindYhmTvVwBH39SNILF3rI3x9SsRn6qrMxHy3l0,26562451
|
43
|
-
spacr-0.1.
|
44
|
-
spacr-0.1.
|
45
|
-
spacr-0.1.
|
46
|
-
spacr-0.1.
|
47
|
-
spacr-0.1.
|
48
|
-
spacr-0.1.
|
49
|
+
spacr-0.1.16.dist-info/LICENSE,sha256=SR-2MeGc6SCM1UORJYyarSWY_A-JaOMFDj7ReSs9tRM,1083
|
50
|
+
spacr-0.1.16.dist-info/METADATA,sha256=-VoJLJbzVVNvGhVmWA2uh5DydW0W4KjiCnz5WYwgLlQ,5004
|
51
|
+
spacr-0.1.16.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
|
52
|
+
spacr-0.1.16.dist-info/entry_points.txt,sha256=e6tBSk-bac5ypML_iWIROnQ-hDSLZT_sGpGviPNHG4g,277
|
53
|
+
spacr-0.1.16.dist-info/top_level.txt,sha256=GJPU8FgwRXGzKeut6JopsSRY2R8T3i9lDgya42tLInY,6
|
54
|
+
spacr-0.1.16.dist-info/RECORD,,
|
@@ -0,0 +1,8 @@
|
|
1
|
+
[console_scripts]
|
2
|
+
annotate = spacr.app_annotate:gui_annotate
|
3
|
+
classify = spacr.app_classify:gui_classify
|
4
|
+
make_masks = spacr.app_make_mask:gui_make_masks
|
5
|
+
mask = spacr.app_mask:gui_mask
|
6
|
+
measure = spacr.app_measure:gui_measure
|
7
|
+
sim = spacr.app_sim:gui_sim
|
8
|
+
spacr = spacr.gui:gui_app
|
@@ -1,9 +0,0 @@
|
|
1
|
-
[console_scripts]
|
2
|
-
annotate = spacr.annotate_app_v2:gui_annotate
|
3
|
-
classify = spacr.gui_classify_app:gui_classify
|
4
|
-
gui = spacr.gui:gui_app
|
5
|
-
make_masks = spacr.gui_make_mask_app:gui_make_masks
|
6
|
-
make_masks2 = spacr.gui_make_mask_app_v2:gui_make_masks
|
7
|
-
mask = spacr.gui_mask_app:gui_mask
|
8
|
-
measure = spacr.gui_measure_app:gui_measure
|
9
|
-
sim = spacr.gui_sim_app:gui_sim
|
File without changes
|
File without changes
|
File without changes
|