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/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):#, width, height):
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="Arial", size=8)
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 Settings", command=lambda: import_settings(scrollable_frame))
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.geometry("1000x800")
181
- root.title("SpaCer: generate masks")
182
- initiate_classify_root(root, 1000, 800)
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