spacr 0.2.31__py3-none-any.whl → 0.2.41__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_core.py +210 -26
- spacr/gui_elements.py +42 -51
- spacr/gui_utils.py +10 -0
- spacr/measure.py +6 -9
- spacr/settings.py +3 -1
- {spacr-0.2.31.dist-info → spacr-0.2.41.dist-info}/METADATA +4 -1
- {spacr-0.2.31.dist-info → spacr-0.2.41.dist-info}/RECORD +11 -11
- {spacr-0.2.31.dist-info → spacr-0.2.41.dist-info}/LICENSE +0 -0
- {spacr-0.2.31.dist-info → spacr-0.2.41.dist-info}/WHEEL +0 -0
- {spacr-0.2.31.dist-info → spacr-0.2.41.dist-info}/entry_points.txt +0 -0
- {spacr-0.2.31.dist-info → spacr-0.2.41.dist-info}/top_level.txt +0 -0
spacr/gui_core.py
CHANGED
@@ -11,6 +11,13 @@ from matplotlib.figure import Figure
|
|
11
11
|
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
|
12
12
|
from huggingface_hub import list_repo_files
|
13
13
|
import numpy as np
|
14
|
+
|
15
|
+
import psutil, gpustat
|
16
|
+
import GPUtil
|
17
|
+
from threading import Thread
|
18
|
+
from time import sleep
|
19
|
+
|
20
|
+
|
14
21
|
try:
|
15
22
|
ctypes.windll.shcore.SetProcessDpiAwareness(True)
|
16
23
|
except AttributeError:
|
@@ -470,13 +477,12 @@ def download_dataset(repo_id, subfolder, local_dir=None, retries=5, delay=5):
|
|
470
477
|
|
471
478
|
raise Exception("Failed to download files after multiple attempts.")
|
472
479
|
|
473
|
-
def setup_button_section(horizontal_container, settings_type='mask', window_dimensions=[500, 1000], run=True, abort=True, download=True, import_btn=True):
|
474
|
-
global button_frame, button_scrollable_frame, run_button, abort_button, download_dataset_button, import_button, q, fig_queue, vars_dict, progress_bar
|
475
|
-
from .settings import descriptions
|
476
480
|
|
477
|
-
width = (window_dimensions[0]) // 8
|
478
|
-
height = window_dimensions[1]
|
479
481
|
|
482
|
+
def setup_button_section(horizontal_container, settings_type='mask', run=True, abort=True, download=True, import_btn=True):
|
483
|
+
global button_frame, button_scrollable_frame, run_button, abort_button, download_dataset_button, import_button, q, fig_queue, vars_dict, progress_bar
|
484
|
+
from .gui_utils import set_element_size
|
485
|
+
size_dict = set_element_size(horizontal_container)
|
480
486
|
button_frame = tk.Frame(horizontal_container)
|
481
487
|
horizontal_container.add(button_frame, stretch="always", sticky="nsew")
|
482
488
|
button_frame.grid_rowconfigure(0, weight=0)
|
@@ -495,25 +501,25 @@ def setup_button_section(horizontal_container, settings_type='mask', window_dime
|
|
495
501
|
|
496
502
|
if run:
|
497
503
|
print(f'settings_type: {settings_type}')
|
498
|
-
run_button = spacrButton(button_scrollable_frame.scrollable_frame, text="run", command=lambda: start_process(q, fig_queue, settings_type))
|
504
|
+
run_button = spacrButton(button_scrollable_frame.scrollable_frame, text="run", command=lambda: start_process(q, fig_queue, settings_type), show_text=False, size=size_dict['btn_size'])
|
499
505
|
run_button.grid(row=btn_row, column=btn_col, pady=5, padx=5, sticky='ew')
|
500
506
|
widgets.append(run_button)
|
501
507
|
btn_row += 1
|
502
508
|
|
503
509
|
if abort and settings_type in ['mask', 'measure', 'classify', 'sequencing', 'umap']:
|
504
|
-
abort_button = spacrButton(button_scrollable_frame.scrollable_frame, text="abort", command=initiate_abort)
|
510
|
+
abort_button = spacrButton(button_scrollable_frame.scrollable_frame, text="abort", command=initiate_abort, show_text=False, size=size_dict['btn_size'])
|
505
511
|
abort_button.grid(row=btn_row, column=btn_col, pady=5, padx=5, sticky='ew')
|
506
512
|
widgets.append(abort_button)
|
507
513
|
btn_row += 1
|
508
514
|
|
509
515
|
if download and settings_type in ['mask']:
|
510
|
-
download_dataset_button = spacrButton(button_scrollable_frame.scrollable_frame, text="download", command=download_hug_dataset)
|
516
|
+
download_dataset_button = spacrButton(button_scrollable_frame.scrollable_frame, text="download", command=download_hug_dataset, show_text=False, size=size_dict['btn_size'])
|
511
517
|
download_dataset_button.grid(row=btn_row, column=btn_col, pady=5, padx=5, sticky='ew')
|
512
518
|
widgets.append(download_dataset_button)
|
513
519
|
btn_row += 1
|
514
520
|
|
515
521
|
if import_btn:
|
516
|
-
import_button = spacrButton(button_scrollable_frame.scrollable_frame, text="settings", command=lambda: import_settings(settings_type))
|
522
|
+
import_button = spacrButton(button_scrollable_frame.scrollable_frame, text="settings", command=lambda: import_settings(settings_type),show_text=False, size=size_dict['btn_size'])
|
517
523
|
import_button.grid(row=btn_row, column=btn_col, pady=5, padx=5, sticky='ew')
|
518
524
|
widgets.append(import_button)
|
519
525
|
btn_row += 1
|
@@ -526,30 +532,44 @@ def setup_button_section(horizontal_container, settings_type='mask', window_dime
|
|
526
532
|
if vars_dict is not None:
|
527
533
|
toggle_settings(button_scrollable_frame)
|
528
534
|
|
535
|
+
style = ttk.Style(horizontal_container)
|
536
|
+
_ = set_dark_style(style, containers=[button_frame], widgets=widgets)
|
537
|
+
|
538
|
+
return button_scrollable_frame
|
539
|
+
|
540
|
+
def setup_help_section(horizontal_container, settings_type='mask'):
|
541
|
+
from .settings import descriptions
|
542
|
+
|
529
543
|
description_frame = tk.Frame(horizontal_container)
|
530
544
|
horizontal_container.add(description_frame, stretch="always", sticky="nsew")
|
531
545
|
description_frame.grid_columnconfigure(0, weight=1)
|
532
|
-
description_frame.grid_rowconfigure(
|
546
|
+
description_frame.grid_rowconfigure(1, weight=1) # Ensure the text widget row is expandable
|
547
|
+
|
548
|
+
description_label = spacrLabel(description_frame, text=f"{settings_type} Module", anchor='center', justify='center', align="center")
|
549
|
+
description_label.grid(row=0, column=0, pady=10, padx=10, sticky='ew')
|
550
|
+
|
551
|
+
# Set background color directly
|
552
|
+
style_out = set_dark_style(ttk.Style())
|
553
|
+
bg_color = style_out['bg_color']
|
554
|
+
fg_color = style_out['fg_color']
|
555
|
+
|
556
|
+
description_text_widget = tk.Text(description_frame, wrap="word", bg=bg_color, fg=fg_color)
|
557
|
+
description_text_widget.grid(row=1, column=0, sticky="nsew")
|
533
558
|
|
534
|
-
description_label = tk.Label(description_frame, text="Module Description", anchor='nw', justify='left', wraplength=width - 50)
|
535
|
-
description_label.grid(row=0, column=0, pady=50, padx=20, sticky='nsew')
|
536
559
|
description_text = descriptions.get(settings_type, "No description available for this module.")
|
537
|
-
|
560
|
+
description_text_widget.insert("1.0", description_text)
|
561
|
+
description_text_widget.config(state="disabled") # Make the text widget read-only
|
538
562
|
|
539
563
|
def update_wraplength(event):
|
540
|
-
new_width = event.width -
|
541
|
-
|
564
|
+
new_width = event.width - 20 # Adjust as needed
|
565
|
+
description_text_widget.config(width=new_width)
|
542
566
|
|
543
|
-
|
544
|
-
|
545
|
-
containers = [button_frame, description_frame]
|
546
|
-
widgets.extend([description_label])
|
567
|
+
description_text_widget.bind('<Configure>', update_wraplength)
|
547
568
|
|
548
569
|
style = ttk.Style(horizontal_container)
|
549
|
-
_ = set_dark_style(style, containers=
|
550
|
-
|
551
|
-
return button_scrollable_frame
|
570
|
+
_ = set_dark_style(style, containers=[description_frame], widgets=[description_label, description_text_widget])
|
552
571
|
|
572
|
+
return description_frame
|
553
573
|
|
554
574
|
def hide_all_settings(vars_dict, categories):
|
555
575
|
"""
|
@@ -707,8 +727,8 @@ def process_console_queue():
|
|
707
727
|
after_id = console_output.after(100, process_console_queue)
|
708
728
|
parent_frame.after_tasks.append(after_id)
|
709
729
|
|
710
|
-
def set_globals(q_var, console_output_var, parent_frame_var, vars_dict_var, canvas_var, canvas_widget_var, scrollable_frame_var, fig_queue_var, progress_bar_var):
|
711
|
-
global q, console_output, parent_frame, vars_dict, canvas, canvas_widget, scrollable_frame, fig_queue, progress_bar
|
730
|
+
def set_globals(q_var, console_output_var, parent_frame_var, vars_dict_var, canvas_var, canvas_widget_var, scrollable_frame_var, fig_queue_var, progress_bar_var, usage_bars_var):
|
731
|
+
global q, console_output, parent_frame, vars_dict, canvas, canvas_widget, scrollable_frame, fig_queue, progress_bar, usage_bars
|
712
732
|
q = q_var
|
713
733
|
console_output = console_output_var
|
714
734
|
parent_frame = parent_frame_var
|
@@ -718,6 +738,7 @@ def set_globals(q_var, console_output_var, parent_frame_var, vars_dict_var, canv
|
|
718
738
|
scrollable_frame = scrollable_frame_var
|
719
739
|
fig_queue = fig_queue_var
|
720
740
|
progress_bar = progress_bar_var
|
741
|
+
usage_bars = usage_bars_var
|
721
742
|
|
722
743
|
def create_containers(parent_frame):
|
723
744
|
vertical_container = tk.PanedWindow(parent_frame, orient=tk.VERTICAL)
|
@@ -744,6 +765,165 @@ def setup_frame(parent_frame):
|
|
744
765
|
|
745
766
|
return parent_frame, vertical_container, horizontal_container
|
746
767
|
|
768
|
+
def setup_usage_panel(horizontal_container):
|
769
|
+
global usage_bars
|
770
|
+
from .gui_utils import set_element_size
|
771
|
+
|
772
|
+
def update_usage(ram_bar, vram_bar, gpu_bar, usage_bars, parent_frame):
|
773
|
+
# Update RAM usage
|
774
|
+
ram_usage = psutil.virtual_memory().percent
|
775
|
+
ram_bar['value'] = ram_usage
|
776
|
+
|
777
|
+
# Update GPU and VRAM usage
|
778
|
+
gpus = GPUtil.getGPUs()
|
779
|
+
if gpus:
|
780
|
+
gpu = gpus[0]
|
781
|
+
vram_usage = gpu.memoryUtil * 100
|
782
|
+
gpu_usage = gpu.load * 100
|
783
|
+
vram_bar['value'] = vram_usage
|
784
|
+
gpu_bar['value'] = gpu_usage
|
785
|
+
|
786
|
+
# Update CPU usage for each core
|
787
|
+
cpu_percentages = psutil.cpu_percent(percpu=True)
|
788
|
+
for bar, usage in zip(usage_bars[3:], cpu_percentages):
|
789
|
+
bar['value'] = usage
|
790
|
+
|
791
|
+
# Schedule the function to run again after 1000 ms (1 second)
|
792
|
+
parent_frame.after(1000, update_usage, ram_bar, vram_bar, gpu_bar, usage_bars, parent_frame)
|
793
|
+
|
794
|
+
size_dict = set_element_size(horizontal_container)
|
795
|
+
print(size_dict)
|
796
|
+
|
797
|
+
usage_frame = tk.Frame(horizontal_container)
|
798
|
+
horizontal_container.add(usage_frame, stretch="always", sticky="nsew")
|
799
|
+
usage_frame.grid_rowconfigure(0, weight=0)
|
800
|
+
usage_frame.grid_rowconfigure(1, weight=1)
|
801
|
+
usage_frame.grid_columnconfigure(0, weight=1)
|
802
|
+
usage_frame.grid_columnconfigure(1, weight=1)
|
803
|
+
|
804
|
+
usage_label = spacrLabel(usage_frame, text="Hardware Stats", anchor='center', justify='center', align="center")
|
805
|
+
usage_label.grid(row=0, column=0, pady=10, padx=10, columnspan=2)
|
806
|
+
|
807
|
+
usage_scrollable_frame = spacrFrame(usage_frame)
|
808
|
+
usage_scrollable_frame.grid(row=1, column=0, sticky="nsew", columnspan=2)
|
809
|
+
widgets = [usage_label, usage_scrollable_frame.scrollable_frame]
|
810
|
+
usage_bars = []
|
811
|
+
max_elements_per_column = 12
|
812
|
+
row = 0
|
813
|
+
col = 0
|
814
|
+
|
815
|
+
# Initialize RAM, VRAM, and GPU bars as None
|
816
|
+
ram_bar, vram_bar, gpu_bar = None, None, None
|
817
|
+
|
818
|
+
# Try adding RAM bar
|
819
|
+
try:
|
820
|
+
ram_info = psutil.virtual_memory()
|
821
|
+
ram_label_text = f"RAM"
|
822
|
+
label = ttk.Label(usage_scrollable_frame.scrollable_frame, text=ram_label_text, anchor='w')
|
823
|
+
label.grid(row=row, column=2 * col, pady=5, padx=5, sticky='w')
|
824
|
+
ram_bar = spacrProgressBar(usage_scrollable_frame.scrollable_frame, orient='horizontal', mode='determinate', length=size_dict['bar_size'], label=False)
|
825
|
+
ram_bar.grid(row=row, column=2 * col + 1, pady=5, padx=5, sticky='ew')
|
826
|
+
widgets.append(label)
|
827
|
+
widgets.append(ram_bar)
|
828
|
+
usage_bars.append(ram_bar)
|
829
|
+
row += 1
|
830
|
+
except Exception as e:
|
831
|
+
print(f"Could not add RAM usage bar: {e}")
|
832
|
+
|
833
|
+
# Try adding VRAM and GPU usage bars
|
834
|
+
try:
|
835
|
+
gpus = GPUtil.getGPUs()
|
836
|
+
if gpus:
|
837
|
+
gpu = gpus[0]
|
838
|
+
vram_label_text = f"VRAM"
|
839
|
+
label = ttk.Label(usage_scrollable_frame.scrollable_frame, text=vram_label_text, anchor='w')
|
840
|
+
label.grid(row=row, column=2 * col, pady=5, padx=5, sticky='w')
|
841
|
+
vram_bar = spacrProgressBar(usage_scrollable_frame.scrollable_frame, orient='horizontal', mode='determinate', length=size_dict['bar_size'], label=False)
|
842
|
+
vram_bar.grid(row=row, column=2 * col + 1, pady=5, padx=5, sticky='ew')
|
843
|
+
widgets.append(label)
|
844
|
+
widgets.append(vram_bar)
|
845
|
+
usage_bars.append(vram_bar)
|
846
|
+
row += 1
|
847
|
+
|
848
|
+
gpu_label_text = f"GPU"
|
849
|
+
label = ttk.Label(usage_scrollable_frame.scrollable_frame, text=gpu_label_text, anchor='w')
|
850
|
+
label.grid(row=row, column=2 * col, pady=5, padx=5, sticky='w')
|
851
|
+
gpu_bar = spacrProgressBar(usage_scrollable_frame.scrollable_frame, orient='horizontal', mode='determinate', length=size_dict['bar_size'], label=False)
|
852
|
+
gpu_bar.grid(row=row, column=2 * col + 1, pady=5, padx=5, sticky='ew')
|
853
|
+
widgets.append(label)
|
854
|
+
widgets.append(gpu_bar)
|
855
|
+
usage_bars.append(gpu_bar)
|
856
|
+
row += 1
|
857
|
+
except Exception as e:
|
858
|
+
print(f"Could not add VRAM or GPU usage bars: {e}")
|
859
|
+
|
860
|
+
# Add CPU core usage bars
|
861
|
+
try:
|
862
|
+
cpu_cores = psutil.cpu_count(logical=True)
|
863
|
+
cpu_freq = psutil.cpu_freq()
|
864
|
+
|
865
|
+
for core in range(cpu_cores):
|
866
|
+
if row > 0 and row % max_elements_per_column == 0:
|
867
|
+
col += 1
|
868
|
+
row = 0
|
869
|
+
label = ttk.Label(usage_scrollable_frame.scrollable_frame, text=f"Core {core+1}", anchor='w')
|
870
|
+
label.grid(row=row, column=2 * col, pady=2, padx=5, sticky='w')
|
871
|
+
bar = spacrProgressBar(usage_scrollable_frame.scrollable_frame, orient='horizontal', mode='determinate', length=size_dict['bar_size'], label=False)
|
872
|
+
bar.grid(row=row, column=2 * col + 1, pady=2, padx=5, sticky='ew')
|
873
|
+
widgets.append(label)
|
874
|
+
widgets.append(bar)
|
875
|
+
usage_bars.append(bar)
|
876
|
+
row += 1
|
877
|
+
except Exception as e:
|
878
|
+
print(f"Could not add CPU core usage bars: {e}")
|
879
|
+
|
880
|
+
# Adding the text box for hardware information
|
881
|
+
#hardware_frame = tk.Frame(horizontal_container)
|
882
|
+
#horizontal_container.add(hardware_frame, stretch="always", sticky="nsew")
|
883
|
+
#hardware_frame.grid_columnconfigure(0, weight=1)
|
884
|
+
|
885
|
+
#hardware_info = tk.Text(hardware_frame, height=1, wrap='none', bg='black', fg='white', bd=0)
|
886
|
+
#hardware_info.grid(row=0, column=0, pady=10, padx=5, sticky='ew')
|
887
|
+
|
888
|
+
#hardware_text = ""
|
889
|
+
#try:
|
890
|
+
# ram_info = psutil.virtual_memory()
|
891
|
+
# hardware_text += f"RAM: {ram_info.total / (1024 ** 3):.1f} GB "
|
892
|
+
#except Exception as e:
|
893
|
+
# hardware_text += f"RAM: Could not retrieve ({e}) "
|
894
|
+
|
895
|
+
#try:
|
896
|
+
# gpus = GPUtil.getGPUs()
|
897
|
+
# if gpus:
|
898
|
+
# gpu = gpus[0]
|
899
|
+
# hardware_text += f"VRAM: {gpu.memoryTotal / 1024:.1f} GB "
|
900
|
+
# hardware_text += f"GPU: {gpu.name} "
|
901
|
+
#except Exception as e:
|
902
|
+
# hardware_text += f"VRAM and GPU: Could not retrieve ({e}) "
|
903
|
+
|
904
|
+
#try:
|
905
|
+
# if cpu_freq:
|
906
|
+
# hardware_text += f"CPU Max Clock Speed: {cpu_freq.max / 1000:.0f} GHz"
|
907
|
+
#except Exception as e:
|
908
|
+
# hardware_text += f"CPU Max Clock Speed: Could not retrieve ({e})"
|
909
|
+
|
910
|
+
#hardware_info.insert(tk.END, hardware_text)
|
911
|
+
#hardware_info.configure(state='disabled')
|
912
|
+
#widgets.append(hardware_info)
|
913
|
+
|
914
|
+
style = ttk.Style(horizontal_container)
|
915
|
+
_ = set_dark_style(style, containers=[usage_frame], widgets=widgets) # hardware_frame
|
916
|
+
|
917
|
+
if ram_bar is None:
|
918
|
+
ram_bar = spacrProgressBar(usage_scrollable_frame.scrollable_frame, orient='horizontal', mode='determinate', length=size_dict['bar_size'], label=False)
|
919
|
+
if vram_bar is None:
|
920
|
+
vram_bar = spacrProgressBar(usage_scrollable_frame.scrollable_frame, orient='horizontal', mode='determinate', length=size_dict['bar_size'], label=False)
|
921
|
+
if gpu_bar is None:
|
922
|
+
gpu_bar = spacrProgressBar(usage_scrollable_frame.scrollable_frame, orient='horizontal', mode='determinate', length=size_dict['bar_size'], label=False)
|
923
|
+
|
924
|
+
update_usage(ram_bar, vram_bar, gpu_bar, usage_bars, usage_frame)
|
925
|
+
return usage_scrollable_frame, usage_bars
|
926
|
+
|
747
927
|
def initiate_root(parent, settings_type='mask'):
|
748
928
|
global q, fig_queue, parent_frame, scrollable_frame, button_frame, vars_dict, canvas, canvas_widget, button_scrollable_frame, progress_bar
|
749
929
|
from .gui_utils import main_thread_update_function
|
@@ -780,11 +960,15 @@ def initiate_root(parent, settings_type='mask'):
|
|
780
960
|
initiate_make_mask_app(horizontal_container)
|
781
961
|
else:
|
782
962
|
scrollable_frame, vars_dict = setup_settings_panel(horizontal_container, settings_type, window_dimensions=dims)
|
783
|
-
button_scrollable_frame = setup_button_section(horizontal_container, settings_type
|
963
|
+
button_scrollable_frame = setup_button_section(horizontal_container, settings_type)
|
964
|
+
|
965
|
+
_, usage_bars = setup_usage_panel(horizontal_container)
|
966
|
+
_ = setup_help_section(horizontal_container, settings_type)
|
967
|
+
|
784
968
|
canvas, canvas_widget = setup_plot_section(vertical_container)
|
785
969
|
console_output = setup_console(vertical_container)
|
786
970
|
|
787
|
-
set_globals(q, console_output, parent_frame, vars_dict, canvas, canvas_widget, scrollable_frame, fig_queue, progress_bar)
|
971
|
+
set_globals(q, console_output, parent_frame, vars_dict, canvas, canvas_widget, scrollable_frame, fig_queue, progress_bar, usage_bars)
|
788
972
|
process_console_queue()
|
789
973
|
process_fig_queue()
|
790
974
|
after_id = parent_frame.after(100, lambda: main_thread_update_function(parent_frame, q, fig_queue, canvas_widget))
|
spacr/gui_elements.py
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
import os, threading, time, sqlite3
|
1
|
+
import os, threading, time, sqlite3, webbrowser
|
2
2
|
import tkinter as tk
|
3
3
|
from tkinter import ttk
|
4
4
|
import tkinter.font as tkFont
|
@@ -47,29 +47,11 @@ def set_dark_style(style, parent_frame=None, containers=None, widgets=None, font
|
|
47
47
|
style.configure('TEntry', padding=padding)
|
48
48
|
style.configure('Spacr.TEntry', padding=padding)
|
49
49
|
style.configure('Custom.TLabel', padding=padding)
|
50
|
-
#style.configure('Spacr.TCheckbutton', padding=padding)
|
51
50
|
style.configure('TButton', padding=padding)
|
52
|
-
|
53
51
|
style.configure('TFrame', background=bg_color)
|
54
52
|
style.configure('TPanedwindow', background=bg_color)
|
55
53
|
style.configure('TLabel', background=bg_color, foreground=fg_color, font=font_style)
|
56
54
|
|
57
|
-
|
58
|
-
#style.configure('Custom.TLabel', padding='5 5 5 5', borderwidth=1, relief='flat', background=bg_color, foreground=fg_color, font=font_style)
|
59
|
-
#style.configure('Spacr.TCheckbutton', background=bg_color, foreground=fg_color, indicatoron=False, relief='flat', font="15")
|
60
|
-
#style.map('Spacr.TCheckbutton', background=[('selected', bg_color), ('active', bg_color)], foreground=[('selected', fg_color), ('active', fg_color)])
|
61
|
-
|
62
|
-
|
63
|
-
#style.configure('TNotebook', background=bg_color, tabmargins=[2, 5, 2, 0])
|
64
|
-
#style.configure('TNotebook.Tab', background=bg_color, foreground=fg_color, padding=[5, 5], font=font_style)
|
65
|
-
#style.map('TNotebook.Tab', background=[('selected', active_color), ('active', active_color)], foreground=[('selected', fg_color), ('active', fg_color)])
|
66
|
-
#style.configure('TButton', background=bg_color, foreground=fg_color, padding='5 5 5 5', font=font_style)
|
67
|
-
#style.map('TButton', background=[('active', active_color), ('disabled', inactive_color)])
|
68
|
-
#style.configure('Vertical.TScrollbar', background=bg_color, troughcolor=bg_color, bordercolor=bg_color)
|
69
|
-
#style.configure('Horizontal.TScrollbar', background=bg_color, troughcolor=bg_color, bordercolor=bg_color)
|
70
|
-
#style.configure('Custom.TLabelFrame', font=(font_family, font_size, 'bold'), background=bg_color, foreground='white', relief='solid', borderwidth=1)
|
71
|
-
#style.configure('Custom.TLabelFrame.Label', background=bg_color, foreground='white', font=(font_family, font_size, 'bold'))
|
72
|
-
|
73
55
|
if parent_frame:
|
74
56
|
parent_frame.configure(bg=bg_color)
|
75
57
|
parent_frame.grid_rowconfigure(0, weight=1)
|
@@ -363,12 +345,12 @@ class spacrCheckbutton(ttk.Checkbutton):
|
|
363
345
|
_ = set_dark_style(style, widgets=[self])
|
364
346
|
|
365
347
|
class spacrProgressBar(ttk.Progressbar):
|
366
|
-
def __init__(self, parent, *args, **kwargs):
|
348
|
+
def __init__(self, parent, label=True, *args, **kwargs):
|
367
349
|
super().__init__(parent, *args, **kwargs)
|
368
350
|
|
369
351
|
# Get the style colors
|
370
352
|
style_out = set_dark_style(ttk.Style())
|
371
|
-
|
353
|
+
|
372
354
|
self.fg_color = style_out['fg_color']
|
373
355
|
self.bg_color = style_out['bg_color']
|
374
356
|
self.active_color = style_out['active_color']
|
@@ -389,28 +371,33 @@ class spacrProgressBar(ttk.Progressbar):
|
|
389
371
|
# Set initial value to 0
|
390
372
|
self['value'] = 0
|
391
373
|
|
392
|
-
#
|
393
|
-
self.
|
394
|
-
|
374
|
+
# Track whether to show the progress label
|
375
|
+
self.label = label
|
376
|
+
|
377
|
+
if self.label:
|
378
|
+
# Create the progress label
|
379
|
+
self.progress_label = tk.Label(parent, text="Processing: 0/0", anchor='w', justify='left', bg=self.inactive_color, fg=self.fg_color)
|
380
|
+
self.progress_label.grid(row=1, column=0, columnspan=2, pady=5, padx=5, sticky='ew')
|
395
381
|
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
382
|
+
# Initialize attributes for time and operation
|
383
|
+
self.operation_type = None
|
384
|
+
self.time_image = None
|
385
|
+
self.time_batch = None
|
386
|
+
self.time_left = None
|
401
387
|
|
402
388
|
def update_label(self):
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
389
|
+
if self.label:
|
390
|
+
# Update the progress label with current progress and additional info
|
391
|
+
label_text = f"Processing: {self['value']}/{self['maximum']}"
|
392
|
+
if self.operation_type:
|
393
|
+
label_text += f", {self.operation_type}"
|
394
|
+
if self.time_image:
|
395
|
+
label_text += f", Time/image: {self.time_image:.3f} sec"
|
396
|
+
if self.time_batch:
|
397
|
+
label_text += f", Time/batch: {self.time_batch:.3f} sec"
|
398
|
+
if self.time_left:
|
399
|
+
label_text += f", Time_left: {self.time_left:.3f} min"
|
400
|
+
self.progress_label.config(text=label_text)
|
414
401
|
|
415
402
|
class spacrFrame(ttk.Frame):
|
416
403
|
def __init__(self, container, width=None, *args, bg='black', **kwargs):
|
@@ -1591,14 +1578,14 @@ class AnnotateApp:
|
|
1591
1578
|
self.db_path = db_path
|
1592
1579
|
self.src = src
|
1593
1580
|
self.index = 0
|
1594
|
-
|
1581
|
+
|
1595
1582
|
if isinstance(image_size, list):
|
1596
1583
|
self.image_size = (int(image_size[0]), int(image_size[0]))
|
1597
1584
|
elif isinstance(image_size, int):
|
1598
1585
|
self.image_size = (image_size, image_size)
|
1599
1586
|
else:
|
1600
1587
|
raise ValueError("Invalid image size")
|
1601
|
-
|
1588
|
+
|
1602
1589
|
self.annotation_column = annotation_column
|
1603
1590
|
self.image_type = image_type
|
1604
1591
|
self.channels = channels
|
@@ -1613,8 +1600,6 @@ class AnnotateApp:
|
|
1613
1600
|
self.measurement = measurement
|
1614
1601
|
self.threshold = threshold
|
1615
1602
|
|
1616
|
-
print('self.image_size', self.image_size)
|
1617
|
-
|
1618
1603
|
style_out = set_dark_style(ttk.Style())
|
1619
1604
|
self.root.configure(bg=style_out['inactive_color'])
|
1620
1605
|
|
@@ -1662,8 +1647,10 @@ class AnnotateApp:
|
|
1662
1647
|
self.root.grid_columnconfigure(0, weight=1)
|
1663
1648
|
self.root.grid_columnconfigure(1, weight=1)
|
1664
1649
|
|
1665
|
-
self.
|
1666
|
-
|
1650
|
+
for row in range(self.grid_rows):
|
1651
|
+
self.grid_frame.grid_rowconfigure(row, weight=1)
|
1652
|
+
for col in range(self.grid_cols):
|
1653
|
+
self.grid_frame.grid_columnconfigure(col, weight=1)
|
1667
1654
|
|
1668
1655
|
def calculate_grid_dimensions(self):
|
1669
1656
|
window_width = self.root.winfo_width()
|
@@ -1945,11 +1932,14 @@ class AnnotateApp:
|
|
1945
1932
|
def shutdown(self):
|
1946
1933
|
self.terminate = True
|
1947
1934
|
self.update_queue.put(self.pending_updates.copy())
|
1948
|
-
self.pending_updates
|
1949
|
-
|
1950
|
-
|
1951
|
-
|
1952
|
-
|
1935
|
+
if not self.pending_updates:
|
1936
|
+
self.pending_updates.clear()
|
1937
|
+
self.db_update_thread.join()
|
1938
|
+
self.root.quit()
|
1939
|
+
self.root.destroy()
|
1940
|
+
print(f'Quit application')
|
1941
|
+
else:
|
1942
|
+
print('Waiting for pending updates to finish before quitting')
|
1953
1943
|
|
1954
1944
|
def create_menu_bar(root):
|
1955
1945
|
from .gui import initiate_root
|
@@ -1987,6 +1977,7 @@ def create_menu_bar(root):
|
|
1987
1977
|
|
1988
1978
|
# Add a separator and an exit option
|
1989
1979
|
app_menu.add_separator()
|
1980
|
+
app_menu.add_command(label="Help", command=lambda: webbrowser.open("https://readthedocs.org/projects/spacr/badge/?version=latest"))
|
1990
1981
|
app_menu.add_command(label="Exit", command=root.quit)
|
1991
1982
|
|
1992
1983
|
# Configure the menu for the root window
|
spacr/gui_utils.py
CHANGED
@@ -349,4 +349,14 @@ def annotate_with_image_refs(settings, root, shutdown_callback):
|
|
349
349
|
# Call load_images after setting up the root window
|
350
350
|
app.load_images()
|
351
351
|
|
352
|
+
def set_element_size(widget):
|
353
|
+
screen_width = widget.winfo_screenwidth()
|
354
|
+
screen_height = widget.winfo_screenheight()
|
355
|
+
btn_size = screen_width/50
|
356
|
+
bar_size = screen_width/75
|
357
|
+
|
358
|
+
size_dict = {'btn_size':btn_size,
|
359
|
+
'bar_size':bar_size}
|
360
|
+
return size_dict
|
361
|
+
|
352
362
|
|
spacr/measure.py
CHANGED
@@ -941,14 +941,11 @@ def measure_crop(settings):
|
|
941
941
|
settings = get_measure_crop_settings(settings)
|
942
942
|
settings = measure_test_mode(settings)
|
943
943
|
|
944
|
-
|
945
|
-
|
946
|
-
|
947
|
-
|
948
|
-
|
949
|
-
#if not os.path.exists(settings['src']):
|
950
|
-
# print(f'src: {settings["src"]} does not exist')
|
951
|
-
# return
|
944
|
+
src_fldr = settings['src']
|
945
|
+
if not os.path.basename(src_fldr).endswith('merged'):
|
946
|
+
print(f"WARNING: Source folder, settings: src: {src_fldr} should end with 'merged'")
|
947
|
+
src_fldr = os.path.join(src_fldr, 'merged')
|
948
|
+
print(f"Changed source folder to: {src_fldr}")
|
952
949
|
|
953
950
|
if settings['cell_mask_dim'] is None:
|
954
951
|
settings['include_uninfected'] = True
|
@@ -1009,7 +1006,7 @@ def measure_crop(settings):
|
|
1009
1006
|
time.sleep(1)
|
1010
1007
|
files_processed = len(time_ls)
|
1011
1008
|
files_to_process = len(files)
|
1012
|
-
print_progress(files_processed, files_to_process, n_jobs, time_ls=
|
1009
|
+
print_progress(files_processed, files_to_process, n_jobs, time_ls=time_ls, operation_type='Measure and Crop')
|
1013
1010
|
result.get()
|
1014
1011
|
|
1015
1012
|
if settings['representative_images']:
|
spacr/settings.py
CHANGED
@@ -1114,7 +1114,9 @@ categories = {
|
|
1114
1114
|
}
|
1115
1115
|
|
1116
1116
|
descriptions = {
|
1117
|
-
'mask': "Generate
|
1117
|
+
'mask': "\n\nHelp:\n- Generate Cells, Nuclei, Pathogens, and Cytoplasm masks from intensity images in src.\n- To ensure that spacr is installed correctly:\n- 1. Downloade the training set (click Download).\n- 2. Import settings (click settings navigate to downloaded dataset settings folder and import preprocess_generate_masks_settings.csv).\n- 3. Run the module.\n- 4. Proceed to the Measure module (click Measure in the menue bar).\n- For further help, click the Help button in the menue bar.",
|
1118
|
+
|
1119
|
+
#'mask': "Help. Generate masks for Cells, Nuclei, and Pathogens . Function: preprocess_generate_masks from spacr.core.\n\nKey Features:\n- Automated Mask Generation: Automatically generate accurate masks for various cellular components using Cellpose, a robust deep learning model for cell segmentation.\n- Versatility: Capable of handling different types of biological samples, including cells, nuclei, and pathogens.\n- Integration: Directly integrates with other modules, providing the foundational masks required for subsequent analysis.",
|
1118
1120
|
|
1119
1121
|
'measure': "Capture Measurements from Cells, Nuclei, Pathogens, and Cytoplasm objects. Generate single object PNG images for one or several objects. (Requires masks from the Mask module). Function: measure_crop from spacr.measure.\n\nKey Features:\n- Comprehensive Measurement Capture: Obtain detailed measurements for various cellular components, including area, perimeter, intensity, and more.\n- Image Generation: Create high-resolution PNG images of individual objects, facilitating further analysis and visualization.\n- Mask Dependency: Requires accurate masks generated by the Mask module to ensure precise measurements.",
|
1120
1122
|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: spacr
|
3
|
-
Version: 0.2.
|
3
|
+
Version: 0.2.41
|
4
4
|
Summary: Spatial phenotype analysis of crisp screens (SpaCr)
|
5
5
|
Home-page: https://github.com/EinarOlafsson/spacr
|
6
6
|
Author: Einar Birnir Olafsson
|
@@ -39,6 +39,9 @@ Requires-Dist: ttf-opensans >=2020.10.30
|
|
39
39
|
Requires-Dist: customtkinter <6.0,>=5.2.2
|
40
40
|
Requires-Dist: biopython <2.0,>=1.80
|
41
41
|
Requires-Dist: lxml <6.0,>=5.1.0
|
42
|
+
Requires-Dist: psutil <6.0,>=5.9.8
|
43
|
+
Requires-Dist: gputil <2.0,>=1.4.0
|
44
|
+
Requires-Dist: gpustat <2.0,>=1.1.1
|
42
45
|
Requires-Dist: huggingface-hub <0.25,>=0.24.0
|
43
46
|
Provides-Extra: dev
|
44
47
|
Requires-Dist: pytest <3.11,>=3.9 ; extra == 'dev'
|
@@ -12,15 +12,15 @@ spacr/core.py,sha256=iAH6de2dW0nKVtVeBjdWOhSW_KoHlVDVOoOsHb6vGC0,148884
|
|
12
12
|
spacr/deep_spacr.py,sha256=ASBsN4JpHp_3S-91JUsB34IWTjTGPYI7jKV2qZnUR5M,37005
|
13
13
|
spacr/graph_learning.py,sha256=1tR-ZxvXE3dBz1Saw7BeVFcrsUFu9OlUZeZVifih9eo,13070
|
14
14
|
spacr/gui.py,sha256=bA1Qy6D9aeL_Qe0Xeql8bRkbbFajAMGTZZR3uBzIW1Q,8495
|
15
|
-
spacr/gui_core.py,sha256=
|
16
|
-
spacr/gui_elements.py,sha256=
|
17
|
-
spacr/gui_utils.py,sha256=
|
15
|
+
spacr/gui_core.py,sha256=X75_P1pUNiA2B2WAzG20xBqpBygxJ4UU8nPkyBwqBOo,43662
|
16
|
+
spacr/gui_elements.py,sha256=XbawiE7JJkY4qRtBLENWQGtbKl7LWTzS7GlQASiXbLw,95149
|
17
|
+
spacr/gui_utils.py,sha256=7kD1EB9hqpjoVszJuCcEu_2oSSX6UsTMGrKBT7LhK9A,15255
|
18
18
|
spacr/io.py,sha256=Dehuqn_oGo0gcyezQIw9rUUvO7oOHDWuMkPDSCgyrp8,115521
|
19
19
|
spacr/logger.py,sha256=7Zqr3TuuOQLWT32gYr2q1qvv7x0a2JhLANmZcnBXAW8,670
|
20
|
-
spacr/measure.py,sha256=
|
20
|
+
spacr/measure.py,sha256=u7j3z8wJyDQt24vh0nUmrI7uS1hei_9p_zlmAwoT4zI,55295
|
21
21
|
spacr/plot.py,sha256=DYJEoK1kz2ih6ZGvKiA3xTqeIeKQNhuQKwgrscopFxA,69101
|
22
22
|
spacr/sequencing.py,sha256=fHZRnoMSxmhMdadkei3lUeBdckqFyptWdQyWsDW3aaU,83304
|
23
|
-
spacr/settings.py,sha256=
|
23
|
+
spacr/settings.py,sha256=uUiWyeoXEFiybs4JgD0m8THdIQAVxyAA4wSqmpnuRCg,65945
|
24
24
|
spacr/sim.py,sha256=FveaVgBi3eypO2oVB5Dx-v0CC1Ny7UPfXkJiiRRodAk,71212
|
25
25
|
spacr/sim_app.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
26
26
|
spacr/timelapse.py,sha256=KMYCgHzf9LTZe-lWl5mvH2EjbKRE6OhpwdY13wEumGc,39504
|
@@ -50,9 +50,9 @@ spacr/resources/icons/umap.png,sha256=dOLF3DeLYy9k0nkUybiZMe1wzHQwLJFRmgccppw-8b
|
|
50
50
|
spacr/resources/models/cp/toxo_plaque_cyto_e25000_X1120_Y1120.CP_model,sha256=z8BbHWZPRnE9D_BHO0fBREE85c1vkltDs-incs2ytXQ,26566572
|
51
51
|
spacr/resources/models/cp/toxo_plaque_cyto_e25000_X1120_Y1120.CP_model_settings.csv,sha256=fBAGuL_B8ERVdVizO3BHozTDSbZUh1yFzsYK3wkQN68,420
|
52
52
|
spacr/resources/models/cp/toxo_pv_lumen.CP_model,sha256=2y_CindYhmTvVwBH39SNILF3rI3x9SsRn6qrMxHy3l0,26562451
|
53
|
-
spacr-0.2.
|
54
|
-
spacr-0.2.
|
55
|
-
spacr-0.2.
|
56
|
-
spacr-0.2.
|
57
|
-
spacr-0.2.
|
58
|
-
spacr-0.2.
|
53
|
+
spacr-0.2.41.dist-info/LICENSE,sha256=SR-2MeGc6SCM1UORJYyarSWY_A-JaOMFDj7ReSs9tRM,1083
|
54
|
+
spacr-0.2.41.dist-info/METADATA,sha256=YxsBdTgoarr-fq8Dc7fH0KmZiHYT0e0c-slo7Gjclf0,5156
|
55
|
+
spacr-0.2.41.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
|
56
|
+
spacr-0.2.41.dist-info/entry_points.txt,sha256=BMC0ql9aNNpv8lUZ8sgDLQMsqaVnX5L535gEhKUP5ho,296
|
57
|
+
spacr-0.2.41.dist-info/top_level.txt,sha256=GJPU8FgwRXGzKeut6JopsSRY2R8T3i9lDgya42tLInY,6
|
58
|
+
spacr-0.2.41.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|