spacr 0.1.81__tar.gz → 0.2.0__tar.gz
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-0.1.81/spacr.egg-info → spacr-0.2.0}/PKG-INFO +1 -1
- {spacr-0.1.81 → spacr-0.2.0}/setup.py +2 -2
- {spacr-0.1.81 → spacr-0.2.0}/spacr/__init__.py +6 -2
- {spacr-0.1.81 → spacr-0.2.0}/spacr/app_annotate.py +6 -5
- {spacr-0.1.81 → spacr-0.2.0}/spacr/app_make_masks.py +8 -15
- {spacr-0.1.81 → spacr-0.2.0}/spacr/core.py +1 -1
- spacr-0.2.0/spacr/gui.py +157 -0
- {spacr-0.1.81 → spacr-0.2.0}/spacr/gui_core.py +113 -67
- {spacr-0.1.81 → spacr-0.2.0}/spacr/gui_elements.py +233 -87
- {spacr-0.1.81 → spacr-0.2.0}/spacr/gui_utils.py +3 -3
- spacr-0.2.0/spacr/resources/icons/abort.png +0 -0
- spacr-0.2.0/spacr/resources/icons/annotate.png +0 -0
- spacr-0.2.0/spacr/resources/icons/cellpose_masks.png +0 -0
- spacr-0.2.0/spacr/resources/icons/classify.png +0 -0
- spacr-0.2.0/spacr/resources/icons/default.png +0 -0
- spacr-0.2.0/spacr/resources/icons/download.png +0 -0
- spacr-0.2.0/spacr/resources/icons/logo_spacr.png +0 -0
- spacr-0.2.0/spacr/resources/icons/make_masks.png +0 -0
- spacr-0.2.0/spacr/resources/icons/map_barcodes.png +0 -0
- spacr-0.2.0/spacr/resources/icons/mask.png +0 -0
- spacr-0.2.0/spacr/resources/icons/measure.png +0 -0
- spacr-0.2.0/spacr/resources/icons/regression.png +0 -0
- spacr-0.2.0/spacr/resources/icons/run.png +0 -0
- spacr-0.2.0/spacr/resources/icons/sequencing.png +0 -0
- spacr-0.2.0/spacr/resources/icons/settings.png +0 -0
- spacr-0.2.0/spacr/resources/icons/train_cellpose.png +0 -0
- spacr-0.2.0/spacr/resources/icons/umap.png +0 -0
- {spacr-0.1.81 → spacr-0.2.0}/spacr/settings.py +12 -12
- {spacr-0.1.81 → spacr-0.2.0/spacr.egg-info}/PKG-INFO +1 -1
- {spacr-0.1.81 → spacr-0.2.0}/spacr.egg-info/SOURCES.txt +20 -3
- spacr-0.1.81/spacr/gui.py +0 -176
- {spacr-0.1.81 → spacr-0.2.0}/LICENSE +0 -0
- {spacr-0.1.81 → spacr-0.2.0}/MANIFEST.in +0 -0
- {spacr-0.1.81 → spacr-0.2.0}/README.rst +0 -0
- {spacr-0.1.81 → spacr-0.2.0}/setup.cfg +0 -0
- {spacr-0.1.81 → spacr-0.2.0}/spacr/__main__.py +0 -0
- {spacr-0.1.81 → spacr-0.2.0}/spacr/app_classify.py +0 -0
- {spacr-0.1.81 → spacr-0.2.0}/spacr/app_mask.py +0 -0
- {spacr-0.1.81 → spacr-0.2.0}/spacr/app_measure.py +0 -0
- {spacr-0.1.81 → spacr-0.2.0}/spacr/app_sequencing.py +0 -0
- {spacr-0.1.81 → spacr-0.2.0}/spacr/app_umap.py +0 -0
- {spacr-0.1.81 → spacr-0.2.0}/spacr/chris.py +0 -0
- {spacr-0.1.81 → spacr-0.2.0}/spacr/deep_spacr.py +0 -0
- {spacr-0.1.81 → spacr-0.2.0}/spacr/graph_learning.py +0 -0
- {spacr-0.1.81 → spacr-0.2.0}/spacr/io.py +0 -0
- {spacr-0.1.81 → spacr-0.2.0}/spacr/logger.py +0 -0
- {spacr-0.1.81 → spacr-0.2.0}/spacr/measure.py +0 -0
- {spacr-0.1.81 → spacr-0.2.0}/spacr/plot.py +0 -0
- {spacr-0.1.81/spacr → spacr-0.2.0/spacr/resources}/models/cp/toxo_plaque_cyto_e25000_X1120_Y1120.CP_model +0 -0
- {spacr-0.1.81/spacr → spacr-0.2.0/spacr/resources}/models/cp/toxo_plaque_cyto_e25000_X1120_Y1120.CP_model_settings.csv +0 -0
- {spacr-0.1.81/spacr → spacr-0.2.0/spacr/resources}/models/cp/toxo_pv_lumen.CP_model +0 -0
- {spacr-0.1.81 → spacr-0.2.0}/spacr/sequencing.py +0 -0
- {spacr-0.1.81 → spacr-0.2.0}/spacr/sim.py +0 -0
- {spacr-0.1.81 → spacr-0.2.0}/spacr/sim_app.py +0 -0
- {spacr-0.1.81 → spacr-0.2.0}/spacr/timelapse.py +0 -0
- {spacr-0.1.81 → spacr-0.2.0}/spacr/utils.py +0 -0
- {spacr-0.1.81 → spacr-0.2.0}/spacr/version.py +0 -0
- {spacr-0.1.81 → spacr-0.2.0}/spacr.egg-info/dependency_links.txt +0 -0
- {spacr-0.1.81 → spacr-0.2.0}/spacr.egg-info/entry_points.txt +0 -0
- {spacr-0.1.81 → spacr-0.2.0}/spacr.egg-info/requires.txt +0 -0
- {spacr-0.1.81 → spacr-0.2.0}/spacr.egg-info/top_level.txt +0 -0
- {spacr-0.1.81 → spacr-0.2.0}/tests/test_annotate_app.py +0 -0
- {spacr-0.1.81 → spacr-0.2.0}/tests/test_core.py +0 -0
- {spacr-0.1.81 → spacr-0.2.0}/tests/test_gui_classify_app.py +0 -0
- {spacr-0.1.81 → spacr-0.2.0}/tests/test_gui_mask_app.py +0 -0
- {spacr-0.1.81 → spacr-0.2.0}/tests/test_gui_measure_app.py +0 -0
- {spacr-0.1.81 → spacr-0.2.0}/tests/test_gui_sim_app.py +0 -0
- {spacr-0.1.81 → spacr-0.2.0}/tests/test_gui_utils.py +0 -0
- {spacr-0.1.81 → spacr-0.2.0}/tests/test_io.py +0 -0
- {spacr-0.1.81 → spacr-0.2.0}/tests/test_mask_app.py +0 -0
- {spacr-0.1.81 → spacr-0.2.0}/tests/test_measure.py +0 -0
- {spacr-0.1.81 → spacr-0.2.0}/tests/test_plot.py +0 -0
- {spacr-0.1.81 → spacr-0.2.0}/tests/test_sim.py +0 -0
- {spacr-0.1.81 → spacr-0.2.0}/tests/test_timelapse.py +0 -0
- {spacr-0.1.81 → spacr-0.2.0}/tests/test_train.py +0 -0
- {spacr-0.1.81 → spacr-0.2.0}/tests/test_umap.py +0 -0
- {spacr-0.1.81 → spacr-0.2.0}/tests/test_utils.py +0 -0
@@ -50,7 +50,7 @@ dependencies = [
|
|
50
50
|
|
51
51
|
setup(
|
52
52
|
name="spacr",
|
53
|
-
version="0.
|
53
|
+
version="0.2.0",
|
54
54
|
author="Einar Birnir Olafsson",
|
55
55
|
author_email="olafsson@med.umich.com",
|
56
56
|
description="Spatial phenotype analysis of crisp screens (SpaCr)",
|
@@ -58,7 +58,7 @@ setup(
|
|
58
58
|
url="https://github.com/EinarOlafsson/spacr",
|
59
59
|
packages=find_packages(exclude=["tests.*", "tests"]),
|
60
60
|
include_package_data=True,
|
61
|
-
package_data={'spacr': ['models/cp/*'],},
|
61
|
+
package_data={'spacr': ['resources/models/cp/*', 'resources/icons/*'],},
|
62
62
|
install_requires=dependencies,
|
63
63
|
entry_points={
|
64
64
|
'console_scripts': [
|
@@ -16,8 +16,8 @@ from . import app_annotate
|
|
16
16
|
from . import gui_utils
|
17
17
|
from . import gui_elements
|
18
18
|
from . import gui_core
|
19
|
-
from . import
|
20
|
-
from . import
|
19
|
+
from . import gui
|
20
|
+
from . import gui
|
21
21
|
from . import app_make_masks
|
22
22
|
from . import app_mask
|
23
23
|
from . import app_measure
|
@@ -40,6 +40,10 @@ __all__ = [
|
|
40
40
|
"deep_spacr",
|
41
41
|
"app_annotate",
|
42
42
|
"gui_utils",
|
43
|
+
"gui_elements",
|
44
|
+
"gui_core",
|
45
|
+
"gui",
|
46
|
+
"gui",
|
43
47
|
"app_make_masks",
|
44
48
|
"app_mask",
|
45
49
|
"app_measure",
|
@@ -1,15 +1,16 @@
|
|
1
1
|
import tkinter as tk
|
2
|
+
from tkinter import ttk
|
2
3
|
from .gui import MainApp
|
4
|
+
from .gui_elements import set_dark_style
|
3
5
|
|
4
6
|
def initiate_annotation_app(parent_frame):
|
5
7
|
from .gui_utils import generate_annotate_fields, annotate_app
|
6
8
|
# Set up the settings window
|
7
9
|
settings_window = tk.Toplevel(parent_frame)
|
8
10
|
settings_window.title("Annotation Settings")
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
settings_frame = tk.Frame(settings_window, bg='black') # Set the background color to black
|
11
|
+
style_out = set_dark_style(ttk.Style())
|
12
|
+
settings_window.configure(bg=style_out['bg_color'])
|
13
|
+
settings_frame = tk.Frame(settings_window, bg=style_out['bg_color'])
|
13
14
|
settings_frame.pack(fill=tk.BOTH, expand=True)
|
14
15
|
vars_dict = generate_annotate_fields(settings_frame)
|
15
16
|
|
@@ -41,7 +42,7 @@ def initiate_annotation_app(parent_frame):
|
|
41
42
|
settings_window.destroy()
|
42
43
|
annotate_app(parent_frame, settings)
|
43
44
|
|
44
|
-
start_button = tk.Button(settings_window, text="Start Annotation", command=start_annotation_app, bg='
|
45
|
+
start_button = tk.Button(settings_window, text="Start Annotation", command=start_annotation_app, bg=style_out['bg_color'], fg=style_out['bg_color'])
|
45
46
|
start_button.pack(pady=10)
|
46
47
|
|
47
48
|
def start_annotate_app():
|
@@ -3,26 +3,22 @@ from tkinter import ttk
|
|
3
3
|
from .gui import MainApp
|
4
4
|
|
5
5
|
def initiate_make_mask_app(parent_frame):
|
6
|
-
from .gui_elements import
|
7
|
-
# Set up the settings window
|
6
|
+
from .gui_elements import ModifyMaskApp, set_dark_style
|
8
7
|
settings_window = tk.Toplevel(parent_frame)
|
9
8
|
settings_window.title("Make Masks Settings")
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
settings_frame = tk.Frame(settings_window, bg='black') # Set the background color to black
|
9
|
+
style_out = set_dark_style(ttk.Style())
|
10
|
+
settings_window.configure(bg=style_out['bg_color'])
|
11
|
+
settings_frame = tk.Frame(settings_window, bg=style_out['bg_color'])
|
14
12
|
settings_frame.pack(fill=tk.BOTH, expand=True)
|
15
13
|
|
16
14
|
vars_dict = {
|
17
15
|
'folder_path': ttk.Entry(settings_frame),
|
18
16
|
'scale_factor': ttk.Entry(settings_frame)
|
19
17
|
}
|
20
|
-
|
21
|
-
# Arrange input fields and labels
|
22
18
|
row = 0
|
23
19
|
for name, entry in vars_dict.items():
|
24
20
|
ttk.Label(settings_frame, text=f"{name.replace('_', ' ').capitalize()}:",
|
25
|
-
background=
|
21
|
+
background=style_out['bg_color'], foreground=style_out['fg_color']).grid(row=row, column=0)
|
26
22
|
entry.grid(row=row, column=1)
|
27
23
|
row += 1
|
28
24
|
|
@@ -32,15 +28,12 @@ def initiate_make_mask_app(parent_frame):
|
|
32
28
|
try:
|
33
29
|
scale_factor = float(vars_dict['scale_factor'].get())
|
34
30
|
except ValueError:
|
35
|
-
scale_factor = None
|
36
|
-
|
37
|
-
# Convert empty strings to None
|
31
|
+
scale_factor = None
|
38
32
|
folder_path = folder_path if folder_path != '' else None
|
39
|
-
|
40
33
|
settings_window.destroy()
|
41
|
-
|
34
|
+
ModifyMaskApp(parent_frame, folder_path, scale_factor)
|
42
35
|
|
43
|
-
run_button = tk.Button(settings_window, text="Start Make Masks", command=start_make_mask_app, bg='
|
36
|
+
run_button = tk.Button(settings_window, text="Start Make Masks", command=start_make_mask_app, bg=style_out['bg_color'], fg=style_out['fg_color'])
|
44
37
|
run_button.pack(pady=10)
|
45
38
|
|
46
39
|
def start_make_mask_app():
|
@@ -1738,7 +1738,7 @@ def preprocess_generate_masks(src, settings={}):
|
|
1738
1738
|
if os.path.exists(os.path.join(src,'measurements')):
|
1739
1739
|
_pivot_counts_table(db_path=os.path.join(src,'measurements', 'measurements.db'))
|
1740
1740
|
|
1741
|
-
#
|
1741
|
+
#Concatenate stack with masks
|
1742
1742
|
_load_and_concatenate_arrays(src, settings['channels'], settings['cell_channel'], settings['nucleus_channel'], settings['pathogen_channel'])
|
1743
1743
|
|
1744
1744
|
if settings['plot']:
|
spacr-0.2.0/spacr/gui.py
ADDED
@@ -0,0 +1,157 @@
|
|
1
|
+
import tkinter as tk
|
2
|
+
from tkinter import ttk
|
3
|
+
from PIL import Image, ImageTk, ImageDraw
|
4
|
+
import os
|
5
|
+
from multiprocessing import set_start_method
|
6
|
+
from .gui_elements import spacrButton, create_menu_bar, set_dark_style
|
7
|
+
from .gui_core import initiate_root
|
8
|
+
|
9
|
+
class MainApp(tk.Tk):
|
10
|
+
def __init__(self, default_app=None):
|
11
|
+
super().__init__()
|
12
|
+
width = self.winfo_screenwidth()
|
13
|
+
height = self.winfo_screenheight()
|
14
|
+
self.geometry(f"{width}x{height}")
|
15
|
+
self.title("SpaCr GUI Collection")
|
16
|
+
self.configure(bg='#333333') # Set window background to dark gray
|
17
|
+
|
18
|
+
# Initialize style and apply dark style to the main window
|
19
|
+
style = ttk.Style()
|
20
|
+
self.color_settings = set_dark_style(style, parent_frame=self)
|
21
|
+
self.main_buttons = {} # Initialize main_buttons dictionary here
|
22
|
+
self.additional_buttons = {} # Initialize additional_buttons dictionary here
|
23
|
+
|
24
|
+
self.main_gui_apps = {
|
25
|
+
"Mask": (lambda frame: initiate_root(frame, 'mask'), "Generate cellpose masks for cells, nuclei and pathogen images."),
|
26
|
+
"Measure": (lambda frame: initiate_root(frame, 'measure'), "Measure single object intensity and morphological feature. Crop and save single object image"),
|
27
|
+
"Annotate": (lambda frame: initiate_root(frame, 'annotate'), "Annotation single object images on a grid. Annotations are saved to database."),
|
28
|
+
"Make Masks": (lambda frame: initiate_root(frame, 'make_masks'), "Adjust pre-existing Cellpose models to your specific dataset for improved performance"),
|
29
|
+
"Classify": (lambda frame: initiate_root(frame, 'classify'), "Train Torch Convolutional Neural Networks (CNNs) or Transformers to classify single object images."),
|
30
|
+
}
|
31
|
+
|
32
|
+
self.additional_gui_apps = {
|
33
|
+
"Sequencing": (lambda frame: initiate_root(frame, 'sequencing'), "Analyze sequencing data."),
|
34
|
+
"Umap": (lambda frame: initiate_root(frame, 'umap'), "Generate UMAP embeddings with datapoints represented as images."),
|
35
|
+
"Train Cellpose": (lambda frame: initiate_root(frame, 'train_cellpose'), "Train custom Cellpose models."),
|
36
|
+
"ML Analyze": (lambda frame: initiate_root(frame, 'ml_analyze'), "Machine learning analysis of data."),
|
37
|
+
"Cellpose Masks": (lambda frame: initiate_root(frame, 'cellpose_masks'), "Generate Cellpose masks."),
|
38
|
+
"Cellpose All": (lambda frame: initiate_root(frame, 'cellpose_all'), "Run Cellpose on all images."),
|
39
|
+
"Map Barcodes": (lambda frame: initiate_root(frame, 'map_barcodes'), "Map barcodes to data."),
|
40
|
+
"Regression": (lambda frame: initiate_root(frame, 'regression'), "Perform regression analysis."),
|
41
|
+
"Recruitment": (lambda frame: initiate_root(frame, 'recruitment'), "Analyze recruitment data.")
|
42
|
+
}
|
43
|
+
|
44
|
+
self.selected_app = tk.StringVar()
|
45
|
+
self.create_widgets()
|
46
|
+
|
47
|
+
if default_app in self.main_gui_apps:
|
48
|
+
self.load_app(default_app, self.main_gui_apps[default_app][0])
|
49
|
+
elif default_app in self.additional_gui_apps:
|
50
|
+
self.load_app(default_app, self.additional_gui_apps[default_app][0])
|
51
|
+
|
52
|
+
def create_widgets(self):
|
53
|
+
# Create the menu bar
|
54
|
+
create_menu_bar(self)
|
55
|
+
|
56
|
+
# Create a canvas to hold the selected app and other elements
|
57
|
+
self.canvas = tk.Canvas(self, highlightthickness=0)
|
58
|
+
self.canvas.grid(row=0, column=0, sticky="nsew")
|
59
|
+
self.grid_rowconfigure(0, weight=1)
|
60
|
+
self.grid_columnconfigure(0, weight=1)
|
61
|
+
|
62
|
+
# Create a frame inside the canvas to hold the main content
|
63
|
+
self.content_frame = tk.Frame(self.canvas)
|
64
|
+
self.content_frame.grid(row=0, column=0, sticky="nsew")
|
65
|
+
|
66
|
+
# Center the content frame within the canvas
|
67
|
+
self.canvas.create_window((self.winfo_screenwidth() // 2, self.winfo_screenheight() // 2), window=self.content_frame, anchor="center")
|
68
|
+
|
69
|
+
# Apply dark style to canvas and content_frame
|
70
|
+
set_dark_style(ttk.Style(), containers=[self.canvas, self.content_frame])
|
71
|
+
|
72
|
+
# Create startup screen with buttons for each main GUI app and drop-down for additional apps
|
73
|
+
self.create_startup_screen()
|
74
|
+
|
75
|
+
def create_startup_screen(self):
|
76
|
+
self.clear_frame(self.content_frame)
|
77
|
+
|
78
|
+
# Create frames for the grids
|
79
|
+
main_buttons_frame = tk.Frame(self.content_frame)
|
80
|
+
main_buttons_frame.pack(pady=10)
|
81
|
+
set_dark_style(ttk.Style(), containers=[main_buttons_frame])
|
82
|
+
|
83
|
+
additional_buttons_frame = tk.Frame(self.content_frame)
|
84
|
+
additional_buttons_frame.pack(pady=10)
|
85
|
+
set_dark_style(ttk.Style(), containers=[additional_buttons_frame])
|
86
|
+
|
87
|
+
# Create a frame for the description below the icon grids
|
88
|
+
description_frame = tk.Frame(self.content_frame, height=70) # Increased height to 70
|
89
|
+
description_frame.pack(fill=tk.X, pady=10)
|
90
|
+
description_frame.pack_propagate(False) # Prevent the frame from resizing based on its content
|
91
|
+
set_dark_style(ttk.Style(), containers=[description_frame])
|
92
|
+
|
93
|
+
# Use a Label widget to display descriptions
|
94
|
+
self.description_label = tk.Label(description_frame, text="", wraplength=800, justify="center", font=('Helvetica', 12), fg=self.color_settings['fg_color'], bg=self.color_settings['bg_color'])
|
95
|
+
self.description_label.pack(fill=tk.BOTH, pady=10)
|
96
|
+
|
97
|
+
# Load the logo image and place it in the main apps row
|
98
|
+
logo_button = spacrButton(main_buttons_frame, text="SpaCr", command=lambda: self.load_app("logo_spacr", initiate_root), icon_name="logo_spacr", size=100, show_text=False)
|
99
|
+
logo_button.grid(row=0, column=0, padx=5, pady=5)
|
100
|
+
self.main_buttons[logo_button] = "SpaCr: An advanced application suite for cellpose masks, measurements, annotations, and more."
|
101
|
+
|
102
|
+
# Create icon buttons for the main apps
|
103
|
+
for i, (app_name, app_data) in enumerate(self.main_gui_apps.items()):
|
104
|
+
app_func, app_desc = app_data
|
105
|
+
button = spacrButton(main_buttons_frame, text=app_name, command=lambda app_name=app_name, app_func=app_func: self.load_app(app_name, app_func), icon_name=app_name.lower(), size=100, show_text=False)
|
106
|
+
button.grid(row=0, column=i + 1, padx=5, pady=5)
|
107
|
+
self.main_buttons[button] = app_desc
|
108
|
+
|
109
|
+
# Create icon buttons for the additional apps
|
110
|
+
for i, (app_name, app_data) in enumerate(self.additional_gui_apps.items()):
|
111
|
+
app_func, app_desc = app_data
|
112
|
+
button = spacrButton(additional_buttons_frame, text=app_name, command=lambda app_name=app_name, app_func=app_func: self.load_app(app_name, app_func), icon_name=app_name.lower(), size=75, show_text=False)
|
113
|
+
button.grid(row=0, column=i, padx=5, pady=5) # Ensure all icons are in a single row
|
114
|
+
self.additional_buttons[button] = app_desc
|
115
|
+
|
116
|
+
# Update description initially
|
117
|
+
self.update_description()
|
118
|
+
|
119
|
+
def update_description(self):
|
120
|
+
# Check all buttons and update description if any has the active color
|
121
|
+
for button, desc in {**self.main_buttons, **self.additional_buttons}.items():
|
122
|
+
if button.canvas.itemcget(button.button_bg, "fill") == self.color_settings['active_color']:
|
123
|
+
self.show_description(desc)
|
124
|
+
return
|
125
|
+
self.clear_description()
|
126
|
+
|
127
|
+
def show_description(self, description):
|
128
|
+
if self.description_label.winfo_exists():
|
129
|
+
self.description_label.config(text=description)
|
130
|
+
self.description_label.update_idletasks() # Ensure the label updates immediately
|
131
|
+
|
132
|
+
def clear_description(self):
|
133
|
+
if self.description_label.winfo_exists():
|
134
|
+
self.description_label.config(text="")
|
135
|
+
self.description_label.update_idletasks() # Ensure the label updates immediately
|
136
|
+
|
137
|
+
def load_app(self, app_name, app_func):
|
138
|
+
# Clear the current content frame
|
139
|
+
self.clear_frame(self.canvas)
|
140
|
+
|
141
|
+
# Initialize the selected app
|
142
|
+
app_frame = tk.Frame(self.canvas)
|
143
|
+
app_frame.pack(fill=tk.BOTH, expand=True)
|
144
|
+
set_dark_style(ttk.Style(), containers=[app_frame])
|
145
|
+
app_func(app_frame)
|
146
|
+
|
147
|
+
def clear_frame(self, frame):
|
148
|
+
for widget in frame.winfo_children():
|
149
|
+
widget.destroy()
|
150
|
+
|
151
|
+
def gui_app():
|
152
|
+
app = MainApp()
|
153
|
+
app.mainloop()
|
154
|
+
|
155
|
+
if __name__ == "__main__":
|
156
|
+
set_start_method('spawn', force=True)
|
157
|
+
gui_app()
|
@@ -17,7 +17,7 @@ except AttributeError:
|
|
17
17
|
pass
|
18
18
|
|
19
19
|
from .settings import set_default_train_test_model, get_measure_crop_settings, set_default_settings_preprocess_generate_masks, get_analyze_reads_default_settings, set_default_umap_image_settings
|
20
|
-
from .gui_elements import
|
20
|
+
from .gui_elements import spacrButton, spacrLabel, spacrFrame, spacrDropdownMenu ,set_dark_style, set_default_font
|
21
21
|
|
22
22
|
# Define global variables
|
23
23
|
q = None
|
@@ -231,25 +231,43 @@ def import_settings(settings_type='mask'):
|
|
231
231
|
vars_dict = hide_all_settings(vars_dict, categories=None)
|
232
232
|
|
233
233
|
def convert_settings_dict_for_gui(settings):
|
234
|
+
from torchvision import models as torch_models
|
235
|
+
torchvision_models = [name for name, obj in torch_models.__dict__.items() if callable(obj)]
|
236
|
+
chans = ['0', '1', '2', '3', '4', '5', '6', '7', '8', None]
|
237
|
+
chans_v2 = [0, 1, 2, 3, None]
|
234
238
|
variables = {}
|
235
239
|
special_cases = {
|
236
240
|
'metadata_type': ('combo', ['cellvoyager', 'cq1', 'nikon', 'zeis', 'custom'], 'cellvoyager'),
|
237
241
|
'channels': ('combo', ['[0,1,2,3]', '[0,1,2]', '[0,1]', '[0]'], '[0,1,2,3]'),
|
238
|
-
'
|
239
|
-
'
|
240
|
-
'
|
241
|
-
|
242
|
+
'channel_dims': ('combo', ['[0,1,2,3]', '[0,1,2]', '[0,1]', '[0]'], '[0,1,2,3]'),
|
243
|
+
'cell_mask_dim': ('combo', chans, None),
|
244
|
+
'cell_chann_dim': ('combo', chans, None),
|
245
|
+
'nucleus_mask_dim': ('combo', chans, None),
|
246
|
+
'nucleus_chann_dim': ('combo', chans, None),
|
247
|
+
'pathogen_mask_dim': ('combo', chans, None),
|
248
|
+
'pathogen_chann_dim': ('combo', chans, None),
|
249
|
+
'crop_mode': ('combo', ['cell', 'nucleus', 'pathogen', '[cell, nucleus, pathogen]', '[cell,nucleus, pathogen]'], ['cell']),
|
242
250
|
'magnification': ('combo', [20, 40, 60], 20),
|
243
|
-
'nucleus_channel': ('combo',
|
244
|
-
'cell_channel': ('combo',
|
245
|
-
'
|
251
|
+
'nucleus_channel': ('combo', chans_v2, None),
|
252
|
+
'cell_channel': ('combo', chans_v2, None),
|
253
|
+
'channel_of_interest': ('combo', chans_v2, None),
|
254
|
+
'pathogen_channel': ('combo', chans_v2, None),
|
246
255
|
'timelapse_mode': ('combo', ['trackpy', 'btrack'], 'trackpy'),
|
256
|
+
'train_mode': ('combo', ['erm', 'irm'], 'erm'),
|
257
|
+
'clustering': ('combo', ['dbscan', 'kmean'], 'dbscan'),
|
258
|
+
'reduction_method': ('combo', ['umap', 'tsne'], 'umap'),
|
259
|
+
'model_name': ('combo', ['cyto', 'cyto_2', 'cyto_3', 'nuclei'], 'cyto'),
|
260
|
+
'regression_type': ('combo', ['ols','gls','wls','rlm','glm','mixed','quantile','logit','probit','poisson','lasso','ridge'], 'ols'),
|
247
261
|
'timelapse_objects': ('combo', ['cell', 'nucleus', 'pathogen', 'cytoplasm', None], None),
|
248
|
-
'model_type': ('combo',
|
262
|
+
'model_type': ('combo', torchvision_models, 'resnet50'),
|
249
263
|
'optimizer_type': ('combo', ['adamw', 'adam'], 'adamw'),
|
250
264
|
'schedule': ('combo', ['reduce_lr_on_plateau', 'step_lr'], 'reduce_lr_on_plateau'),
|
251
265
|
'loss_type': ('combo', ['focal_loss', 'binary_cross_entropy_with_logits'], 'focal_loss'),
|
252
266
|
'normalize_by': ('combo', ['fov', 'png'], 'png'),
|
267
|
+
'agg_type': ('combo', ['mean', 'median'], 'mean'),
|
268
|
+
'grouping': ('combo', ['mean', 'median'], 'mean'),
|
269
|
+
'min_max': ('combo', ['allq', 'all'], 'allq'),
|
270
|
+
'transform': ('combo', ['log', 'sqrt', 'square', None], None)
|
253
271
|
}
|
254
272
|
|
255
273
|
for key, value in settings.items():
|
@@ -271,17 +289,16 @@ def convert_settings_dict_for_gui(settings):
|
|
271
289
|
|
272
290
|
def setup_settings_panel(vertical_container, settings_type='mask', window_dimensions=[500, 1000]):
|
273
291
|
global vars_dict, scrollable_frame
|
274
|
-
from .settings import
|
292
|
+
from .settings import get_identify_masks_finetune_default_settings, set_default_analyze_screen, set_default_settings_preprocess_generate_masks, get_measure_crop_settings, set_default_train_test_model, get_analyze_reads_default_settings, set_default_umap_image_settings, generate_fields, get_perform_regression_default_settings, get_train_cellpose_default_settings, get_map_barcodes_default_settings, get_analyze_recruitment_default_settings, get_check_cellpose_models_default_settings
|
275
293
|
|
276
|
-
width = (window_dimensions[0])//6
|
294
|
+
width = (window_dimensions[0]) // 6
|
277
295
|
height = window_dimensions[1]
|
278
296
|
|
279
|
-
|
280
|
-
settings_frame = tk.Frame(vertical_container, bg='black', height=height, width=width)
|
297
|
+
settings_frame = tk.Frame(vertical_container)
|
281
298
|
vertical_container.add(settings_frame, stretch="always")
|
282
|
-
settings_label = spacrLabel(settings_frame, text="Settings",
|
299
|
+
settings_label = spacrLabel(settings_frame, text="Settings", anchor='center', justify='center', align="center")
|
283
300
|
settings_label.grid(row=0, column=0, pady=10, padx=10)
|
284
|
-
scrollable_frame = spacrFrame(settings_frame
|
301
|
+
scrollable_frame = spacrFrame(settings_frame)
|
285
302
|
scrollable_frame.grid(row=1, column=0, sticky="nsew")
|
286
303
|
settings_frame.grid_rowconfigure(1, weight=1)
|
287
304
|
settings_frame.grid_columnconfigure(0, weight=1)
|
@@ -310,24 +327,18 @@ def setup_settings_panel(vertical_container, settings_type='mask', window_dimens
|
|
310
327
|
settings = get_perform_regression_default_settings(settings={})
|
311
328
|
elif settings_type == 'recruitment':
|
312
329
|
settings = get_analyze_recruitment_default_settings(settings={})
|
313
|
-
#elif settings_type == 'simulation':
|
314
|
-
# settings = set_default_
|
315
|
-
#elif settings_type == 'cellpose_dataset':
|
316
|
-
# settings = set_default_
|
317
|
-
#elif settings_type == 'plaques':
|
318
|
-
# settings = set_default_
|
319
|
-
#elif settings_type == 'cellpose_compare':
|
320
|
-
# settings = set_default_
|
321
|
-
#elif settings_type == 'vision_scores':
|
322
|
-
# settings = set_default_
|
323
|
-
#elif settings_type == 'vision_dataset':
|
324
|
-
# settings = set_default_
|
325
330
|
else:
|
326
331
|
raise ValueError(f"Invalid settings type: {settings_type}")
|
327
332
|
|
328
|
-
|
329
333
|
variables = convert_settings_dict_for_gui(settings)
|
330
334
|
vars_dict = generate_fields(variables, scrollable_frame)
|
335
|
+
|
336
|
+
containers = [settings_frame]
|
337
|
+
widgets = [settings_label, scrollable_frame]
|
338
|
+
|
339
|
+
style = ttk.Style(vertical_container)
|
340
|
+
_ = set_dark_style(style, containers=containers, widgets=widgets)
|
341
|
+
|
331
342
|
print("Settings panel setup complete")
|
332
343
|
return scrollable_frame, vars_dict
|
333
344
|
|
@@ -335,45 +346,58 @@ def setup_plot_section(vertical_container):
|
|
335
346
|
global canvas, canvas_widget
|
336
347
|
plot_frame = tk.PanedWindow(vertical_container, orient=tk.VERTICAL)
|
337
348
|
vertical_container.add(plot_frame, stretch="always")
|
338
|
-
figure = Figure(figsize=(30, 4), dpi=100
|
349
|
+
figure = Figure(figsize=(30, 4), dpi=100)
|
339
350
|
plot = figure.add_subplot(111)
|
340
351
|
plot.plot([], []) # This creates an empty plot.
|
341
352
|
plot.axis('off')
|
342
353
|
canvas = FigureCanvasTkAgg(figure, master=plot_frame)
|
343
|
-
canvas.get_tk_widget().configure(cursor='arrow',
|
354
|
+
canvas.get_tk_widget().configure(cursor='arrow', highlightthickness=0)
|
344
355
|
canvas_widget = canvas.get_tk_widget()
|
345
356
|
plot_frame.add(canvas_widget, stretch="always")
|
346
357
|
canvas.draw()
|
347
358
|
canvas.figure = figure
|
359
|
+
style_out = set_dark_style(ttk.Style())
|
360
|
+
|
361
|
+
figure.patch.set_facecolor(style_out['bg_color'])
|
362
|
+
plot.set_facecolor(style_out['bg_color'])
|
363
|
+
containers = [plot_frame]
|
364
|
+
widgets = [canvas_widget]
|
365
|
+
style = ttk.Style(vertical_container)
|
366
|
+
_ = set_dark_style(style, containers=containers, widgets=widgets)
|
348
367
|
return canvas, canvas_widget
|
349
368
|
|
350
369
|
def setup_console(vertical_container):
|
351
370
|
global console_output
|
352
|
-
|
353
|
-
console_frame = tk.Frame(vertical_container, bg='black')
|
371
|
+
console_frame = tk.Frame(vertical_container)
|
354
372
|
vertical_container.add(console_frame, stretch="always")
|
355
|
-
console_label = spacrLabel(console_frame, text="Console",
|
373
|
+
console_label = spacrLabel(console_frame, text="Console", anchor='center', justify='center', align="center")
|
356
374
|
console_label.grid(row=0, column=0, pady=10, padx=10)
|
357
|
-
console_output = scrolledtext.ScrolledText(console_frame, height=10
|
375
|
+
console_output = scrolledtext.ScrolledText(console_frame, height=10)
|
358
376
|
console_output.grid(row=1, column=0, sticky="nsew")
|
359
377
|
console_frame.grid_rowconfigure(1, weight=1)
|
360
378
|
console_frame.grid_columnconfigure(0, weight=1)
|
361
|
-
|
379
|
+
containers = [console_frame]
|
380
|
+
widgets = [console_label, console_output]
|
381
|
+
style = ttk.Style(vertical_container)
|
382
|
+
_ = set_dark_style(style, containers=containers, widgets=widgets)
|
362
383
|
return console_output
|
363
384
|
|
364
385
|
def setup_progress_frame(vertical_container):
|
365
386
|
global progress_output
|
366
|
-
progress_frame = tk.Frame(vertical_container
|
387
|
+
progress_frame = tk.Frame(vertical_container)
|
367
388
|
vertical_container.add(progress_frame, stretch="always")
|
368
|
-
label_frame = tk.Frame(progress_frame
|
389
|
+
label_frame = tk.Frame(progress_frame)
|
369
390
|
label_frame.grid(row=0, column=0, sticky="ew", pady=(5, 0), padx=10)
|
370
|
-
progress_label = spacrLabel(label_frame, text="Processing: 0%",
|
391
|
+
progress_label = spacrLabel(label_frame, text="Processing: 0%", font=('Helvetica', 12), anchor='w', justify='left', align="left")
|
371
392
|
progress_label.grid(row=0, column=0, sticky="w")
|
372
|
-
progress_output = scrolledtext.ScrolledText(progress_frame, height=10
|
393
|
+
progress_output = scrolledtext.ScrolledText(progress_frame, height=10)
|
373
394
|
progress_output.grid(row=1, column=0, sticky="nsew")
|
374
395
|
progress_frame.grid_rowconfigure(1, weight=1)
|
375
396
|
progress_frame.grid_columnconfigure(0, weight=1)
|
376
|
-
|
397
|
+
containers = [progress_frame, label_frame]
|
398
|
+
widgets = [progress_label, progress_output]
|
399
|
+
style = ttk.Style(vertical_container)
|
400
|
+
_ = set_dark_style(style, containers=containers, widgets=widgets)
|
377
401
|
return progress_output
|
378
402
|
|
379
403
|
def download_hug_dataset():
|
@@ -459,60 +483,78 @@ def download_dataset(repo_id, subfolder, local_dir=None, retries=5, delay=5):
|
|
459
483
|
|
460
484
|
raise Exception("Failed to download files after multiple attempts.")
|
461
485
|
|
462
|
-
def setup_button_section(horizontal_container, settings_type='mask',
|
486
|
+
def setup_button_section(horizontal_container, settings_type='mask', window_dimensions=[500, 1000], run=True, abort=True, download=True, import_btn=True):
|
463
487
|
global button_frame, button_scrollable_frame, run_button, abort_button, download_dataset_button, import_button, q, fig_queue, vars_dict
|
464
488
|
from .settings import descriptions
|
465
489
|
|
466
|
-
width = (window_dimensions[0])//8
|
490
|
+
width = (window_dimensions[0]) // 8
|
467
491
|
height = window_dimensions[1]
|
468
492
|
|
469
|
-
button_frame = tk.Frame(horizontal_container
|
493
|
+
button_frame = tk.Frame(horizontal_container)
|
470
494
|
horizontal_container.add(button_frame, stretch="always", sticky="nsew")
|
471
495
|
button_frame.grid_rowconfigure(0, weight=0)
|
472
496
|
button_frame.grid_rowconfigure(1, weight=1)
|
473
497
|
button_frame.grid_columnconfigure(0, weight=1)
|
474
498
|
|
475
|
-
categories_label = spacrLabel(button_frame, text="Categories",
|
499
|
+
categories_label = spacrLabel(button_frame, text="Categories", anchor='center', justify='center', align="center")
|
476
500
|
categories_label.grid(row=0, column=0, pady=10, padx=10)
|
477
|
-
button_scrollable_frame = spacrFrame(button_frame
|
501
|
+
button_scrollable_frame = spacrFrame(button_frame)
|
478
502
|
button_scrollable_frame.grid(row=1, column=0, sticky="nsew")
|
479
503
|
|
504
|
+
widgets = [categories_label, button_scrollable_frame.scrollable_frame]
|
505
|
+
|
480
506
|
btn_col = 0
|
481
507
|
btn_row = 1
|
482
|
-
|
508
|
+
|
483
509
|
if run:
|
484
|
-
run_button = spacrButton(button_scrollable_frame.scrollable_frame, text="
|
510
|
+
run_button = spacrButton(button_scrollable_frame.scrollable_frame, text="run", command=lambda: start_process(q, fig_queue, settings_type))
|
485
511
|
run_button.grid(row=btn_row, column=btn_col, pady=5, padx=5, sticky='ew')
|
512
|
+
widgets.append(run_button)
|
486
513
|
btn_row += 1
|
487
514
|
|
488
515
|
if abort and settings_type in ['mask', 'measure', 'classify', 'sequencing', 'umap']:
|
489
|
-
abort_button = spacrButton(button_scrollable_frame.scrollable_frame, text="
|
516
|
+
abort_button = spacrButton(button_scrollable_frame.scrollable_frame, text="abort", command=initiate_abort)
|
490
517
|
abort_button.grid(row=btn_row, column=btn_col, pady=5, padx=5, sticky='ew')
|
518
|
+
widgets.append(abort_button)
|
491
519
|
btn_row += 1
|
492
520
|
|
493
521
|
if download and settings_type in ['mask']:
|
494
|
-
download_dataset_button = spacrButton(button_scrollable_frame.scrollable_frame, text="
|
522
|
+
download_dataset_button = spacrButton(button_scrollable_frame.scrollable_frame, text="download", command=download_hug_dataset)
|
495
523
|
download_dataset_button.grid(row=btn_row, column=btn_col, pady=5, padx=5, sticky='ew')
|
524
|
+
widgets.append(download_dataset_button)
|
496
525
|
btn_row += 1
|
497
526
|
|
498
527
|
if import_btn:
|
499
|
-
import_button = spacrButton(button_scrollable_frame.scrollable_frame, text="
|
528
|
+
import_button = spacrButton(button_scrollable_frame.scrollable_frame, text="settings", command=lambda: import_settings(settings_type))
|
500
529
|
import_button.grid(row=btn_row, column=btn_col, pady=5, padx=5, sticky='ew')
|
530
|
+
widgets.append(import_button)
|
501
531
|
|
502
|
-
# Call toggle_settings after vars_dict is initialized
|
503
532
|
if vars_dict is not None:
|
504
533
|
toggle_settings(button_scrollable_frame)
|
505
534
|
|
506
|
-
|
507
|
-
description_frame = tk.Frame(horizontal_container, bg='black', height=height, width=width)
|
535
|
+
description_frame = tk.Frame(horizontal_container)
|
508
536
|
horizontal_container.add(description_frame, stretch="always", sticky="nsew")
|
509
|
-
description_frame.grid_columnconfigure(0, weight=1)
|
510
|
-
|
511
|
-
|
537
|
+
description_frame.grid_columnconfigure(0, weight=1)
|
538
|
+
description_frame.grid_rowconfigure(0, weight=1) # Add this line to make the row expandable
|
539
|
+
|
540
|
+
description_label = tk.Label(description_frame, text="Module Description", anchor='nw', justify='left', wraplength=width - 50)
|
541
|
+
description_label.grid(row=0, column=0, pady=50, padx=20, sticky='nsew')
|
512
542
|
description_text = descriptions.get(settings_type, "No description available for this module.")
|
513
543
|
description_label.config(text=description_text)
|
514
544
|
|
515
|
-
|
545
|
+
def update_wraplength(event):
|
546
|
+
new_width = event.width - 40 # Adjust as needed
|
547
|
+
description_label.config(wraplength=new_width)
|
548
|
+
|
549
|
+
description_label.bind('<Configure>', update_wraplength)
|
550
|
+
|
551
|
+
containers = [button_frame, description_frame]
|
552
|
+
widgets.extend([description_label])
|
553
|
+
|
554
|
+
style = ttk.Style(horizontal_container)
|
555
|
+
_ = set_dark_style(style, containers=containers, widgets=widgets)
|
556
|
+
|
557
|
+
return button_frame, button_scrollable_frame, description_frame, description_label
|
516
558
|
|
517
559
|
def hide_all_settings(vars_dict, categories):
|
518
560
|
"""
|
@@ -561,7 +603,6 @@ def toggle_settings(button_scrollable_frame):
|
|
561
603
|
def on_category_select(selected_category):
|
562
604
|
if selected_category == "Select Category":
|
563
605
|
return
|
564
|
-
#print(f"Selected category: {selected_category}")
|
565
606
|
if selected_category in categories:
|
566
607
|
toggle_category(categories[selected_category])
|
567
608
|
if selected_category in active_categories:
|
@@ -569,12 +610,12 @@ def toggle_settings(button_scrollable_frame):
|
|
569
610
|
else:
|
570
611
|
active_categories.add(selected_category)
|
571
612
|
category_dropdown.update_styles(active_categories)
|
572
|
-
category_var.set("Select Category")
|
613
|
+
category_var.set("Select Category")
|
573
614
|
|
574
615
|
category_var = tk.StringVar()
|
575
616
|
non_empty_categories = [category for category, settings in categories.items() if any(setting in vars_dict for setting in settings)]
|
576
617
|
category_dropdown = spacrDropdownMenu(button_scrollable_frame.scrollable_frame, category_var, non_empty_categories, command=on_category_select)
|
577
|
-
category_dropdown.grid(row=
|
618
|
+
category_dropdown.grid(row=5, column=0, sticky="ew", pady=2, padx=2)
|
578
619
|
vars_dict = hide_all_settings(vars_dict, categories)
|
579
620
|
|
580
621
|
def process_fig_queue():
|
@@ -627,24 +668,29 @@ def set_globals(q_var, console_output_var, parent_frame_var, vars_dict_var, canv
|
|
627
668
|
progress_label = progress_label_var
|
628
669
|
fig_queue = fig_queue_var
|
629
670
|
|
671
|
+
def create_containers(parent_frame):
|
672
|
+
vertical_container = tk.PanedWindow(parent_frame, orient=tk.VERTICAL)
|
673
|
+
horizontal_container = tk.PanedWindow(vertical_container, orient=tk.HORIZONTAL)
|
674
|
+
settings_frame = tk.Frame(horizontal_container)
|
675
|
+
return vertical_container, horizontal_container, settings_frame
|
676
|
+
|
630
677
|
def setup_frame(parent_frame):
|
631
678
|
style = ttk.Style(parent_frame)
|
632
|
-
|
679
|
+
vertical_container, horizontal_container, settings_frame = create_containers(parent_frame)
|
680
|
+
containers = [vertical_container, horizontal_container, settings_frame]
|
681
|
+
|
682
|
+
set_dark_style(style, parent_frame, containers)
|
633
683
|
set_default_font(parent_frame, font_name="Helvetica", size=8)
|
634
|
-
|
635
|
-
parent_frame.grid_rowconfigure(0, weight=1)
|
636
|
-
parent_frame.grid_columnconfigure(0, weight=1)
|
637
|
-
vertical_container = tk.PanedWindow(parent_frame, orient=tk.VERTICAL, bg='black')
|
684
|
+
|
638
685
|
vertical_container.grid(row=0, column=0, sticky=tk.NSEW)
|
639
|
-
horizontal_container = tk.PanedWindow(vertical_container, orient=tk.HORIZONTAL, bg='black')
|
640
686
|
vertical_container.add(horizontal_container, stretch="always")
|
641
687
|
horizontal_container.grid_columnconfigure(0, weight=1)
|
642
688
|
horizontal_container.grid_columnconfigure(1, weight=1)
|
643
|
-
settings_frame = tk.Frame(horizontal_container, bg='black')
|
644
689
|
settings_frame.grid_rowconfigure(0, weight=0)
|
645
690
|
settings_frame.grid_rowconfigure(1, weight=1)
|
646
691
|
settings_frame.grid_columnconfigure(0, weight=1)
|
647
692
|
horizontal_container.add(settings_frame, stretch="always", sticky="nsew")
|
693
|
+
|
648
694
|
return parent_frame, vertical_container, horizontal_container
|
649
695
|
|
650
696
|
def initiate_root(parent, settings_type='mask'):
|