spacr 0.2.1__py3-none-any.whl → 0.2.21__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.py +2 -1
- spacr/gui_elements.py +2 -7
- spacr/resources/icons/abort.png +0 -0
- spacr/resources/icons/classify.png +0 -0
- spacr/resources/icons/make_masks.png +0 -0
- spacr/resources/icons/mask.png +0 -0
- spacr/resources/icons/measure.png +0 -0
- spacr/resources/icons/recruitment.png +0 -0
- spacr/resources/icons/regression.png +0 -0
- spacr/resources/icons/run.png +0 -0
- spacr/resources/icons/umap.png +0 -0
- {spacr-0.2.1.dist-info → spacr-0.2.21.dist-info}/METADATA +1 -1
- spacr-0.2.21.dist-info/RECORD +56 -0
- spacr/alpha.py +0 -807
- spacr/annotate_app.py +0 -670
- spacr/annotate_app_v2.py +0 -670
- spacr/app_make_masks_v2.py +0 -686
- spacr/classify_app.py +0 -201
- spacr/cli.py +0 -41
- spacr/foldseek.py +0 -779
- spacr/get_alfafold_structures.py +0 -72
- spacr/gui_2.py +0 -157
- spacr/gui_annotate.py +0 -145
- spacr/gui_classify_app.py +0 -201
- spacr/gui_make_masks_app.py +0 -927
- spacr/gui_make_masks_app_v2.py +0 -688
- spacr/gui_mask_app.py +0 -249
- spacr/gui_measure_app.py +0 -246
- spacr/gui_run.py +0 -58
- spacr/gui_sim_app.py +0 -0
- spacr/gui_wrappers.py +0 -149
- spacr/icons/abort.png +0 -0
- spacr/icons/abort.svg +0 -1
- spacr/icons/download.png +0 -0
- spacr/icons/download.svg +0 -1
- spacr/icons/download_for_offline_100dp_E8EAED_FILL0_wght100_GRAD-25_opsz48.png +0 -0
- spacr/icons/download_for_offline_100dp_E8EAED_FILL0_wght100_GRAD-25_opsz48.svg +0 -1
- spacr/icons/logo_spacr.png +0 -0
- spacr/icons/make_masks.png +0 -0
- spacr/icons/make_masks.svg +0 -1
- spacr/icons/map_barcodes.png +0 -0
- spacr/icons/map_barcodes.svg +0 -1
- spacr/icons/mask.png +0 -0
- spacr/icons/mask.svg +0 -1
- spacr/icons/measure.png +0 -0
- spacr/icons/measure.svg +0 -1
- spacr/icons/play_circle_100dp_E8EAED_FILL0_wght100_GRAD-25_opsz48.png +0 -0
- spacr/icons/play_circle_100dp_E8EAED_FILL0_wght100_GRAD-25_opsz48.svg +0 -1
- spacr/icons/run.png +0 -0
- spacr/icons/run.svg +0 -1
- spacr/icons/sequencing.png +0 -0
- spacr/icons/sequencing.svg +0 -1
- spacr/icons/settings.png +0 -0
- spacr/icons/settings.svg +0 -1
- spacr/icons/settings_100dp_E8EAED_FILL0_wght100_GRAD-25_opsz48.png +0 -0
- spacr/icons/settings_100dp_E8EAED_FILL0_wght100_GRAD-25_opsz48.svg +0 -1
- spacr/icons/stop_circle_100dp_E8EAED_FILL0_wght100_GRAD-25_opsz48.png +0 -0
- spacr/icons/stop_circle_100dp_E8EAED_FILL0_wght100_GRAD-25_opsz48.svg +0 -1
- spacr/icons/theater_comedy_100dp_E8EAED_FILL0_wght100_GRAD200_opsz48.png +0 -0
- spacr/icons/theater_comedy_100dp_E8EAED_FILL0_wght100_GRAD200_opsz48.svg +0 -1
- spacr/make_masks_app.py +0 -929
- spacr/make_masks_app_v2.py +0 -688
- spacr/mask_app.py +0 -249
- spacr/measure_app.py +0 -246
- spacr/models/cp/toxo_plaque_cyto_e25000_X1120_Y1120.CP_model +0 -0
- spacr/models/cp/toxo_plaque_cyto_e25000_X1120_Y1120.CP_model_settings.csv +0 -23
- spacr/models/cp/toxo_pv_lumen.CP_model +0 -0
- spacr/old_code.py +0 -358
- spacr/resources/icons/abort.svg +0 -1
- spacr/resources/icons/annotate.svg +0 -1
- spacr/resources/icons/classify.svg +0 -1
- spacr/resources/icons/download.svg +0 -1
- spacr/resources/icons/icon.psd +0 -0
- spacr/resources/icons/make_masks.svg +0 -1
- spacr/resources/icons/map_barcodes.svg +0 -1
- spacr/resources/icons/mask.svg +0 -1
- spacr/resources/icons/measure.svg +0 -1
- spacr/resources/icons/run.svg +0 -1
- spacr/resources/icons/run_2.png +0 -0
- spacr/resources/icons/run_2.svg +0 -1
- spacr/resources/icons/sequencing.svg +0 -1
- spacr/resources/icons/settings.svg +0 -1
- spacr/resources/icons/train_cellpose.svg +0 -1
- spacr/test_gui.py +0 -0
- spacr-0.2.1.dist-info/RECORD +0 -126
- /spacr/resources/icons/{cellpose.png → cellpose_all.png} +0 -0
- {spacr-0.2.1.dist-info → spacr-0.2.21.dist-info}/LICENSE +0 -0
- {spacr-0.2.1.dist-info → spacr-0.2.21.dist-info}/WHEEL +0 -0
- {spacr-0.2.1.dist-info → spacr-0.2.21.dist-info}/entry_points.txt +0 -0
- {spacr-0.2.1.dist-info → spacr-0.2.21.dist-info}/top_level.txt +0 -0
spacr/get_alfafold_structures.py
DELETED
@@ -1,72 +0,0 @@
|
|
1
|
-
import csv
|
2
|
-
import os
|
3
|
-
import requests
|
4
|
-
|
5
|
-
def download_alphafold_structures(tsv_location, dst, version="4"):
|
6
|
-
# Create the destination directory if it does not exist
|
7
|
-
dst_pdb = os.path.join(dst,'pdb')
|
8
|
-
dst_cif = os.path.join(dst,'cif')
|
9
|
-
dst_pae = os.path.join(dst,'pae')
|
10
|
-
|
11
|
-
if not os.path.exists(dst):
|
12
|
-
os.makedirs(dst)
|
13
|
-
if not os.path.exists(dst_pdb):
|
14
|
-
os.makedirs(dst_pdb)
|
15
|
-
if not os.path.exists(dst_cif):
|
16
|
-
os.makedirs(dst_cif)
|
17
|
-
if not os.path.exists(dst_pae):
|
18
|
-
os.makedirs(dst_pae)
|
19
|
-
|
20
|
-
failed_downloads = [] # List to keep track of failed downloads
|
21
|
-
|
22
|
-
# Open the TSV file and read entries
|
23
|
-
with open(tsv_location, 'r') as tsv_file:
|
24
|
-
reader = csv.DictReader(tsv_file, delimiter='\t')
|
25
|
-
for row in reader:
|
26
|
-
entry = row['Entry']
|
27
|
-
af_link = f"https://alphafold.ebi.ac.uk/files/AF-{entry}-F1-model_v{version}.pdb"
|
28
|
-
cif_link = f"https://alphafold.ebi.ac.uk/files/AF-{entry}-F1-model_v{version}.cif"
|
29
|
-
pae_link = f"https://alphafold.ebi.ac.uk/files/AF-{entry}-F1-predicted_aligned_error_v{version}.json"
|
30
|
-
|
31
|
-
try:
|
32
|
-
response_pdb = requests.get(af_link, stream=True)
|
33
|
-
response_cif = requests.get(cif_link, stream=True)
|
34
|
-
response_pae = requests.get(pae_link, stream=True)
|
35
|
-
if response_pdb.status_code == 200:
|
36
|
-
|
37
|
-
# Save the PDB file
|
38
|
-
with open(os.path.join(dst_pdb, f"AF-{entry}-F1-model_v{version}.pdb"), 'wb') as pdb_file:
|
39
|
-
pdb_file.write(response_pdb.content)
|
40
|
-
print(f"Downloaded: AF-{entry}-F1-model_v{version}.pdb")
|
41
|
-
|
42
|
-
# Save the CIF file
|
43
|
-
with open(os.path.join(dst_cif, f"AF-{entry}-F1-model_v{version}.cif"), 'wb') as cif_file:
|
44
|
-
cif_file.write(response_cif.content)
|
45
|
-
print(f"Downloaded: AF-{entry}-F1-model_v{version}.cif")
|
46
|
-
|
47
|
-
# Save the PAE file
|
48
|
-
with open(os.path.join(dst_pae, f"AF-{entry}-F1-predicted_aligned_error_v{version}.json"), 'wb') as pdb_file:
|
49
|
-
pdb_file.write(response_pae.content)
|
50
|
-
print(f"Downloaded: AF-{entry}-F1-predicted_aligned_error_v{version}.json")
|
51
|
-
|
52
|
-
else:
|
53
|
-
# If the file could not be downloaded, record the entry
|
54
|
-
failed_downloads.append(entry)
|
55
|
-
print(f"Failed to download structure for: {entry}")
|
56
|
-
except Exception as e:
|
57
|
-
print(f"Error downloading structure for {entry}: {e}")
|
58
|
-
failed_downloads.append(entry)
|
59
|
-
|
60
|
-
# Save the list of failed downloads to a CSV file in the destination folder
|
61
|
-
if failed_downloads:
|
62
|
-
with open(os.path.join(dst, 'failed_downloads.csv'), 'w', newline='') as failed_file:
|
63
|
-
writer = csv.writer(failed_file)
|
64
|
-
writer.writerow(['Entry'])
|
65
|
-
for entry in failed_downloads:
|
66
|
-
writer.writerow([entry])
|
67
|
-
print(f"Failed download entries saved to: {os.path.join(dst, 'failed_downloads.csv')}")
|
68
|
-
|
69
|
-
# Example usage:
|
70
|
-
#tsv_location = '/home/carruthers/Downloads/GT1_proteome/GT1_proteins_uniprot.tsv' # Replace with the path to your TSV file containing a list of UniProt entries
|
71
|
-
#dst_folder = '/home/carruthers/Downloads/GT1_proteome' # Replace with your destination folder
|
72
|
-
#download_alphafold_structures(tsv_location, dst_folder)
|
spacr/gui_2.py
DELETED
@@ -1,157 +0,0 @@
|
|
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=50)
|
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)
|
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()
|
spacr/gui_annotate.py
DELETED
@@ -1,145 +0,0 @@
|
|
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
DELETED
@@ -1,201 +0,0 @@
|
|
1
|
-
import sys, ctypes, matplotlib
|
2
|
-
import tkinter as tk
|
3
|
-
from tkinter import ttk, scrolledtext
|
4
|
-
from matplotlib.figure import Figure
|
5
|
-
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
|
6
|
-
from matplotlib.figure import Figure
|
7
|
-
matplotlib.use('Agg')
|
8
|
-
from tkinter import filedialog
|
9
|
-
from multiprocessing import Process, Queue, Value
|
10
|
-
import traceback
|
11
|
-
|
12
|
-
try:
|
13
|
-
ctypes.windll.shcore.SetProcessDpiAwareness(True)
|
14
|
-
except AttributeError:
|
15
|
-
pass
|
16
|
-
|
17
|
-
from .logger import log_function_call
|
18
|
-
from .gui_utils import ScrollableFrame, StdoutRedirector, CustomButton, set_dark_style, set_default_font, generate_fields, process_stdout_stderr, clear_canvas, main_thread_update_function
|
19
|
-
from .gui_utils import classify_variables, check_classify_gui_settings, train_test_model_wrapper, read_settings_from_csv, update_settings_from_csv, style_text_boxes, create_menu_bar
|
20
|
-
|
21
|
-
thread_control = {"run_thread": None, "stop_requested": False}
|
22
|
-
|
23
|
-
#@log_function_call
|
24
|
-
def initiate_abort():
|
25
|
-
global thread_control
|
26
|
-
if thread_control.get("stop_requested") is not None:
|
27
|
-
thread_control["stop_requested"].value = 1
|
28
|
-
|
29
|
-
if thread_control.get("run_thread") is not None:
|
30
|
-
thread_control["run_thread"].join(timeout=5)
|
31
|
-
if thread_control["run_thread"].is_alive():
|
32
|
-
thread_control["run_thread"].terminate()
|
33
|
-
thread_control["run_thread"] = None
|
34
|
-
|
35
|
-
#@log_function_call
|
36
|
-
def run_classify_gui(q, fig_queue, stop_requested):
|
37
|
-
global vars_dict
|
38
|
-
process_stdout_stderr(q)
|
39
|
-
try:
|
40
|
-
settings = check_classify_gui_settings(vars_dict)
|
41
|
-
for key in settings:
|
42
|
-
value = settings[key]
|
43
|
-
print(key, value, type(value))
|
44
|
-
train_test_model_wrapper(settings['src'], settings)
|
45
|
-
except Exception as e:
|
46
|
-
q.put(f"Error during processing: {e}")
|
47
|
-
traceback.print_exc()
|
48
|
-
finally:
|
49
|
-
stop_requested.value = 1
|
50
|
-
|
51
|
-
#@log_function_call
|
52
|
-
def start_process(q, fig_queue):
|
53
|
-
global thread_control
|
54
|
-
if thread_control.get("run_thread") is not None:
|
55
|
-
initiate_abort()
|
56
|
-
|
57
|
-
stop_requested = Value('i', 0) # multiprocessing shared value for inter-process communication
|
58
|
-
thread_control["stop_requested"] = stop_requested
|
59
|
-
thread_control["run_thread"] = Process(target=run_classify_gui, args=(q, fig_queue, stop_requested))
|
60
|
-
thread_control["run_thread"].start()
|
61
|
-
|
62
|
-
def import_settings(scrollable_frame):
|
63
|
-
global vars_dict
|
64
|
-
|
65
|
-
csv_file_path = filedialog.askopenfilename(filetypes=[("CSV files", "*.csv")])
|
66
|
-
csv_settings = read_settings_from_csv(csv_file_path)
|
67
|
-
variables = classify_variables()
|
68
|
-
new_settings = update_settings_from_csv(variables, csv_settings)
|
69
|
-
vars_dict = generate_fields(new_settings, scrollable_frame)
|
70
|
-
|
71
|
-
#@log_function_call
|
72
|
-
def initiate_classify_root(parent_frame):
|
73
|
-
global vars_dict, q, canvas, fig_queue, canvas_widget, thread_control
|
74
|
-
|
75
|
-
style = ttk.Style(parent_frame)
|
76
|
-
set_dark_style(style)
|
77
|
-
style_text_boxes(style)
|
78
|
-
set_default_font(parent_frame, font_name="Helvetica", size=8)
|
79
|
-
|
80
|
-
parent_frame.configure(bg='#333333')
|
81
|
-
parent_frame.grid_rowconfigure(0, weight=1)
|
82
|
-
parent_frame.grid_columnconfigure(0, weight=1)
|
83
|
-
fig_queue = Queue()
|
84
|
-
|
85
|
-
def _process_fig_queue():
|
86
|
-
global canvas
|
87
|
-
try:
|
88
|
-
while not fig_queue.empty():
|
89
|
-
clear_canvas(canvas)
|
90
|
-
fig = fig_queue.get_nowait()
|
91
|
-
for ax in fig.get_axes():
|
92
|
-
ax.set_xticks([]) # Remove x-axis ticks
|
93
|
-
ax.set_yticks([]) # Remove y-axis ticks
|
94
|
-
ax.xaxis.set_visible(False) # Hide the x-axis
|
95
|
-
ax.yaxis.set_visible(False) # Hide the y-axis
|
96
|
-
fig.tight_layout()
|
97
|
-
fig.set_facecolor('#333333')
|
98
|
-
canvas.figure = fig
|
99
|
-
fig_width, fig_height = canvas_widget.winfo_width(), canvas_widget.winfo_height()
|
100
|
-
fig.set_size_inches(fig_width / fig.dpi, fig_height / fig.dpi, forward=True)
|
101
|
-
canvas.draw_idle()
|
102
|
-
except Exception as e:
|
103
|
-
traceback.print_exc()
|
104
|
-
finally:
|
105
|
-
canvas_widget.after(100, _process_fig_queue)
|
106
|
-
|
107
|
-
def _process_console_queue():
|
108
|
-
while not q.empty():
|
109
|
-
message = q.get_nowait()
|
110
|
-
console_output.insert(tk.END, message)
|
111
|
-
console_output.see(tk.END)
|
112
|
-
console_output.after(100, _process_console_queue)
|
113
|
-
|
114
|
-
vertical_container = tk.PanedWindow(parent_frame, orient=tk.HORIZONTAL)
|
115
|
-
vertical_container.grid(row=0, column=0, sticky=tk.NSEW)
|
116
|
-
parent_frame.grid_rowconfigure(0, weight=1)
|
117
|
-
parent_frame.grid_columnconfigure(0, weight=1)
|
118
|
-
|
119
|
-
# Settings Section
|
120
|
-
settings_frame = tk.Frame(vertical_container, bg='#333333')
|
121
|
-
vertical_container.add(settings_frame, stretch="always")
|
122
|
-
settings_label = ttk.Label(settings_frame, text="Settings", background="#333333", foreground="white")
|
123
|
-
settings_label.grid(row=0, column=0, pady=10, padx=10)
|
124
|
-
scrollable_frame = ScrollableFrame(settings_frame, width=500)
|
125
|
-
scrollable_frame.grid(row=1, column=0, sticky="nsew")
|
126
|
-
settings_frame.grid_rowconfigure(1, weight=1)
|
127
|
-
settings_frame.grid_columnconfigure(0, weight=1)
|
128
|
-
|
129
|
-
# Setup for user input fields (variables)
|
130
|
-
variables = classify_variables()
|
131
|
-
vars_dict = generate_fields(variables, scrollable_frame)
|
132
|
-
|
133
|
-
# Button section
|
134
|
-
import_btn = CustomButton(scrollable_frame.scrollable_frame, text="Import", command=lambda: import_settings(scrollable_frame), font=('Helvetica', 10))
|
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), font=('Helvetica', 10))
|
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, font=('Helvetica', 10))
|
139
|
-
abort_button.grid(row=45, column=1, pady=20, padx=20)
|
140
|
-
progress_label = ttk.Label(scrollable_frame.scrollable_frame, text="Processing: 0%", background="black", foreground="white") # Create progress field
|
141
|
-
progress_label.grid(row=50, column=0, columnspan=2, sticky="ew", pady=(5, 0), padx=10)
|
142
|
-
|
143
|
-
# Plot Canvas Section
|
144
|
-
plot_frame = tk.PanedWindow(vertical_container, orient=tk.VERTICAL)
|
145
|
-
vertical_container.add(plot_frame, stretch="always")
|
146
|
-
figure = Figure(figsize=(30, 4), dpi=100, facecolor='#333333')
|
147
|
-
plot = figure.add_subplot(111)
|
148
|
-
plot.plot([], [])
|
149
|
-
plot.axis('off')
|
150
|
-
canvas = FigureCanvasTkAgg(figure, master=plot_frame)
|
151
|
-
canvas.get_tk_widget().configure(cursor='arrow', background='#333333', highlightthickness=0)
|
152
|
-
canvas_widget = canvas.get_tk_widget()
|
153
|
-
plot_frame.add(canvas_widget, stretch="always")
|
154
|
-
canvas.draw()
|
155
|
-
canvas.figure = figure
|
156
|
-
|
157
|
-
# Console Section
|
158
|
-
console_frame = tk.Frame(vertical_container, bg='#333333')
|
159
|
-
vertical_container.add(console_frame, stretch="always")
|
160
|
-
console_label = ttk.Label(console_frame, text="Console", background="#333333", foreground="white")
|
161
|
-
console_label.grid(row=0, column=0, pady=10, padx=10)
|
162
|
-
console_output = scrolledtext.ScrolledText(console_frame, height=10, bg='#333333', fg='white', insertbackground='white')
|
163
|
-
console_output.grid(row=1, column=0, sticky="nsew")
|
164
|
-
console_frame.grid_rowconfigure(1, weight=1)
|
165
|
-
console_frame.grid_columnconfigure(0, weight=1)
|
166
|
-
|
167
|
-
q = Queue()
|
168
|
-
sys.stdout = StdoutRedirector(console_output)
|
169
|
-
sys.stderr = StdoutRedirector(console_output)
|
170
|
-
|
171
|
-
_process_console_queue()
|
172
|
-
_process_fig_queue()
|
173
|
-
|
174
|
-
parent_frame.after(100, lambda: main_thread_update_function(parent_frame, q, fig_queue, canvas_widget, progress_label))
|
175
|
-
|
176
|
-
return parent_frame, vars_dict
|
177
|
-
|
178
|
-
def gui_classify():
|
179
|
-
root = tk.Tk()
|
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)
|
197
|
-
create_menu_bar(root)
|
198
|
-
root.mainloop()
|
199
|
-
|
200
|
-
if __name__ == "__main__":
|
201
|
-
gui_classify()
|