spacr 0.1.0__py3-none-any.whl → 0.1.6__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 +19 -12
- spacr/annotate_app.py +258 -99
- spacr/annotate_app_v2.py +163 -4
- spacr/app_annotate.py +538 -0
- spacr/app_classify.py +8 -0
- spacr/app_make_masks.py +925 -0
- spacr/app_make_masks_v2.py +686 -0
- spacr/app_mask.py +8 -0
- spacr/app_measure.py +8 -0
- spacr/app_sequencing.py +8 -0
- spacr/app_umap.py +8 -0
- spacr/classify_app.py +201 -0
- spacr/core.py +8 -6
- spacr/deep_spacr.py +3 -1
- spacr/gui.py +50 -31
- spacr/gui_2.py +106 -36
- spacr/gui_annotate.py +145 -0
- spacr/gui_classify_app.py +22 -8
- spacr/gui_core.py +608 -0
- spacr/gui_elements.py +322 -0
- spacr/gui_make_masks_app.py +927 -0
- spacr/gui_make_masks_app_v2.py +688 -0
- spacr/gui_mask_app.py +42 -15
- spacr/gui_measure_app.py +46 -21
- spacr/gui_run.py +58 -0
- spacr/gui_utils.py +78 -967
- spacr/gui_wrappers.py +137 -0
- spacr/make_masks_app.py +929 -0
- spacr/make_masks_app_v2.py +688 -0
- spacr/mask_app.py +239 -915
- spacr/measure.py +24 -3
- spacr/measure_app.py +246 -0
- spacr/sequencing.py +1 -17
- spacr/settings.py +441 -6
- spacr/sim_app.py +0 -0
- spacr/utils.py +60 -7
- {spacr-0.1.0.dist-info → spacr-0.1.6.dist-info}/METADATA +13 -22
- spacr-0.1.6.dist-info/RECORD +60 -0
- spacr-0.1.6.dist-info/entry_points.txt +8 -0
- spacr-0.1.0.dist-info/RECORD +0 -40
- spacr-0.1.0.dist-info/entry_points.txt +0 -9
- {spacr-0.1.0.dist-info → spacr-0.1.6.dist-info}/LICENSE +0 -0
- {spacr-0.1.0.dist-info → spacr-0.1.6.dist-info}/WHEEL +0 -0
- {spacr-0.1.0.dist-info → spacr-0.1.6.dist-info}/top_level.txt +0 -0
spacr/gui_annotate.py
ADDED
@@ -0,0 +1,145 @@
|
|
1
|
+
import tkinter as tk
|
2
|
+
from tkinter import ttk
|
3
|
+
from tkinter import font as tkFont
|
4
|
+
from PIL import Image, ImageTk
|
5
|
+
import os
|
6
|
+
import requests
|
7
|
+
|
8
|
+
# Import your GUI apps
|
9
|
+
from .gui_mask_app import initiate_mask_root
|
10
|
+
from .gui_measure_app import initiate_measure_root
|
11
|
+
from .annotate_app import initiate_annotation_app_root
|
12
|
+
from .mask_app import initiate_mask_app_root
|
13
|
+
from .gui_classify_app import initiate_classify_root
|
14
|
+
|
15
|
+
from .gui_utils import CustomButton, style_text_boxes
|
16
|
+
|
17
|
+
class MainApp(tk.Tk):
|
18
|
+
def __init__(self):
|
19
|
+
super().__init__()
|
20
|
+
self.title("SpaCr GUI Collection")
|
21
|
+
self.geometry("1100x1500")
|
22
|
+
self.configure(bg="black")
|
23
|
+
#self.attributes('-fullscreen', True)
|
24
|
+
|
25
|
+
style = ttk.Style()
|
26
|
+
style_text_boxes(style)
|
27
|
+
|
28
|
+
self.gui_apps = {
|
29
|
+
"Mask": (initiate_mask_root, "Generate cellpose masks for cells, nuclei and pathogen images."),
|
30
|
+
"Measure": (initiate_measure_root, "Measure single object intensity and morphological feature. Crop and save single object image"),
|
31
|
+
"Annotate": (initiate_annotation_app_root, "Annotation single object images on a grid. Annotations are saved to database."),
|
32
|
+
"Make Masks": (initiate_mask_app_root, "Adjust pre-existing Cellpose models to your specific dataset for improved performance"),
|
33
|
+
"Classify": (initiate_classify_root, "Train Torch Convolutional Neural Networks (CNNs) or Transformers to classify single object images.")
|
34
|
+
}
|
35
|
+
|
36
|
+
self.selected_app = tk.StringVar()
|
37
|
+
self.create_widgets()
|
38
|
+
|
39
|
+
def create_widgets(self):
|
40
|
+
# Create the menu bar
|
41
|
+
#create_menu_bar(self)
|
42
|
+
# Create a canvas to hold the selected app and other elements
|
43
|
+
self.canvas = tk.Canvas(self, bg="black", highlightthickness=0, width=4000, height=4000)
|
44
|
+
self.canvas.grid(row=0, column=0, sticky="nsew")
|
45
|
+
self.grid_rowconfigure(0, weight=1)
|
46
|
+
self.grid_columnconfigure(0, weight=1)
|
47
|
+
# Create a frame inside the canvas to hold the main content
|
48
|
+
self.content_frame = tk.Frame(self.canvas, bg="black")
|
49
|
+
self.content_frame.pack(fill=tk.BOTH, expand=True)
|
50
|
+
# Create startup screen with buttons for each GUI app
|
51
|
+
self.create_startup_screen()
|
52
|
+
|
53
|
+
def create_startup_screen(self):
|
54
|
+
self.clear_frame(self.content_frame)
|
55
|
+
|
56
|
+
# Create a frame for the logo and description
|
57
|
+
logo_frame = tk.Frame(self.content_frame, bg="black")
|
58
|
+
logo_frame.pack(pady=20, expand=True)
|
59
|
+
|
60
|
+
# Load the logo image
|
61
|
+
if not self.load_logo(logo_frame):
|
62
|
+
tk.Label(logo_frame, text="Logo not found", bg="black", fg="white", font=('Helvetica', 24, tkFont.NORMAL)).pack(padx=10, pady=10)
|
63
|
+
|
64
|
+
# Add SpaCr text below the logo with padding for sharper text
|
65
|
+
tk.Label(logo_frame, text="SpaCr", bg="black", fg="#008080", font=('Helvetica', 24, tkFont.NORMAL)).pack(padx=10, pady=10)
|
66
|
+
|
67
|
+
# Create a frame for the buttons and descriptions
|
68
|
+
buttons_frame = tk.Frame(self.content_frame, bg="black")
|
69
|
+
buttons_frame.pack(pady=10, expand=True, padx=10)
|
70
|
+
|
71
|
+
for i, (app_name, app_data) in enumerate(self.gui_apps.items()):
|
72
|
+
app_func, app_desc = app_data
|
73
|
+
|
74
|
+
# Create custom button with text
|
75
|
+
button = CustomButton(buttons_frame, text=app_name, command=lambda app_name=app_name: self.load_app(app_name), font=('Helvetica', 12))
|
76
|
+
button.grid(row=i, column=0, pady=10, padx=10, sticky="w")
|
77
|
+
|
78
|
+
description_label = tk.Label(buttons_frame, text=app_desc, bg="black", fg="white", wraplength=800, justify="left", font=('Helvetica', 10, tkFont.NORMAL))
|
79
|
+
description_label.grid(row=i, column=1, pady=10, padx=10, sticky="w")
|
80
|
+
|
81
|
+
# Ensure buttons have a fixed width
|
82
|
+
buttons_frame.grid_columnconfigure(0, minsize=150)
|
83
|
+
# Ensure descriptions expand as needed
|
84
|
+
buttons_frame.grid_columnconfigure(1, weight=1)
|
85
|
+
|
86
|
+
def load_logo(self, frame):
|
87
|
+
def download_image(url, save_path):
|
88
|
+
try:
|
89
|
+
response = requests.get(url, stream=True)
|
90
|
+
response.raise_for_status() # Raise an HTTPError for bad responses
|
91
|
+
with open(save_path, 'wb') as f:
|
92
|
+
for chunk in response.iter_content(chunk_size=8192):
|
93
|
+
f.write(chunk)
|
94
|
+
return True
|
95
|
+
except requests.exceptions.RequestException as e:
|
96
|
+
print(f"Failed to download image from {url}: {e}")
|
97
|
+
return False
|
98
|
+
|
99
|
+
try:
|
100
|
+
img_path = os.path.join(os.path.dirname(__file__), 'logo_spacr.png')
|
101
|
+
print(f"Trying to load logo from {img_path}")
|
102
|
+
logo_image = Image.open(img_path)
|
103
|
+
except (FileNotFoundError, Image.UnidentifiedImageError):
|
104
|
+
print(f"File {img_path} not found or is not a valid image. Attempting to download from GitHub.")
|
105
|
+
if download_image('https://raw.githubusercontent.com/EinarOlafsson/spacr/main/spacr/logo_spacr.png', img_path):
|
106
|
+
try:
|
107
|
+
print(f"Downloaded file size: {os.path.getsize(img_path)} bytes")
|
108
|
+
logo_image = Image.open(img_path)
|
109
|
+
except Image.UnidentifiedImageError as e:
|
110
|
+
print(f"Downloaded file is not a valid image: {e}")
|
111
|
+
return False
|
112
|
+
else:
|
113
|
+
return False
|
114
|
+
except Exception as e:
|
115
|
+
print(f"An error occurred while loading the logo: {e}")
|
116
|
+
return False
|
117
|
+
try:
|
118
|
+
logo_image = logo_image.resize((800, 800), Image.Resampling.LANCZOS)
|
119
|
+
logo_photo = ImageTk.PhotoImage(logo_image)
|
120
|
+
logo_label = tk.Label(frame, image=logo_photo, bg="black")
|
121
|
+
logo_label.image = logo_photo # Keep a reference to avoid garbage collection
|
122
|
+
logo_label.pack()
|
123
|
+
return True
|
124
|
+
except Exception as e:
|
125
|
+
print(f"An error occurred while processing the logo image: {e}")
|
126
|
+
return False
|
127
|
+
|
128
|
+
def load_app(self, app_name):
|
129
|
+
selected_app_func, _ = self.gui_apps[app_name]
|
130
|
+
self.clear_frame(self.content_frame)
|
131
|
+
|
132
|
+
app_frame = tk.Frame(self.content_frame, bg="black")
|
133
|
+
app_frame.pack(fill=tk.BOTH, expand=True)
|
134
|
+
selected_app_func(app_frame)#, self.winfo_width(), self.winfo_height())
|
135
|
+
|
136
|
+
def clear_frame(self, frame):
|
137
|
+
for widget in frame.winfo_children():
|
138
|
+
widget.destroy()
|
139
|
+
|
140
|
+
def gui_app():
|
141
|
+
app = MainApp()
|
142
|
+
app.mainloop()
|
143
|
+
|
144
|
+
if __name__ == "__main__":
|
145
|
+
gui_app()
|
spacr/gui_classify_app.py
CHANGED
@@ -69,13 +69,13 @@ def import_settings(scrollable_frame):
|
|
69
69
|
vars_dict = generate_fields(new_settings, scrollable_frame)
|
70
70
|
|
71
71
|
#@log_function_call
|
72
|
-
def initiate_classify_root(parent_frame)
|
72
|
+
def initiate_classify_root(parent_frame):
|
73
73
|
global vars_dict, q, canvas, fig_queue, canvas_widget, thread_control
|
74
74
|
|
75
75
|
style = ttk.Style(parent_frame)
|
76
76
|
set_dark_style(style)
|
77
77
|
style_text_boxes(style)
|
78
|
-
set_default_font(parent_frame, font_name="
|
78
|
+
set_default_font(parent_frame, font_name="Helvetica", size=8)
|
79
79
|
|
80
80
|
parent_frame.configure(bg='#333333')
|
81
81
|
parent_frame.grid_rowconfigure(0, weight=1)
|
@@ -131,11 +131,11 @@ def initiate_classify_root(parent_frame):#, width, height):
|
|
131
131
|
vars_dict = generate_fields(variables, scrollable_frame)
|
132
132
|
|
133
133
|
# Button section
|
134
|
-
import_btn = CustomButton(scrollable_frame.scrollable_frame, text="Import
|
134
|
+
import_btn = CustomButton(scrollable_frame.scrollable_frame, text="Import", command=lambda: import_settings(scrollable_frame), font=('Helvetica', 10))
|
135
135
|
import_btn.grid(row=47, column=0, pady=20, padx=20)
|
136
|
-
run_button = CustomButton(scrollable_frame.scrollable_frame, text="Run", command=lambda: start_process(q, fig_queue))
|
136
|
+
run_button = CustomButton(scrollable_frame.scrollable_frame, text="Run", command=lambda: start_process(q, fig_queue), font=('Helvetica', 10))
|
137
137
|
run_button.grid(row=45, column=0, pady=20, padx=20)
|
138
|
-
abort_button = CustomButton(scrollable_frame.scrollable_frame, text="Abort", command=initiate_abort)
|
138
|
+
abort_button = CustomButton(scrollable_frame.scrollable_frame, text="Abort", command=initiate_abort, font=('Helvetica', 10))
|
139
139
|
abort_button.grid(row=45, column=1, pady=20, padx=20)
|
140
140
|
progress_label = ttk.Label(scrollable_frame.scrollable_frame, text="Processing: 0%", background="black", foreground="white") # Create progress field
|
141
141
|
progress_label.grid(row=50, column=0, columnspan=2, sticky="ew", pady=(5, 0), padx=10)
|
@@ -177,9 +177,23 @@ def initiate_classify_root(parent_frame):#, width, height):
|
|
177
177
|
|
178
178
|
def gui_classify():
|
179
179
|
root = tk.Tk()
|
180
|
-
root.
|
181
|
-
root.
|
182
|
-
|
180
|
+
width = root.winfo_screenwidth()
|
181
|
+
height = root.winfo_screenheight()
|
182
|
+
root.geometry(f"{width}x{height}")
|
183
|
+
root.title("SpaCr: classify objects")
|
184
|
+
|
185
|
+
# Clear previous content if any
|
186
|
+
if hasattr(root, 'content_frame'):
|
187
|
+
for widget in root.content_frame.winfo_children():
|
188
|
+
widget.destroy()
|
189
|
+
root.content_frame.grid_forget()
|
190
|
+
else:
|
191
|
+
root.content_frame = tk.Frame(root)
|
192
|
+
root.content_frame.grid(row=1, column=0, sticky="nsew")
|
193
|
+
root.grid_rowconfigure(1, weight=1)
|
194
|
+
root.grid_columnconfigure(0, weight=1)
|
195
|
+
|
196
|
+
initiate_classify_root(root.content_frame)
|
183
197
|
create_menu_bar(root)
|
184
198
|
root.mainloop()
|
185
199
|
|