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 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(0, weight=1) # Add this line to make the row expandable
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
- description_label.config(text=description_text)
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 - 40 # Adjust as needed
541
- description_label.config(wraplength=new_width)
564
+ new_width = event.width - 20 # Adjust as needed
565
+ description_text_widget.config(width=new_width)
542
566
 
543
- description_label.bind('<Configure>', update_wraplength)
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=containers, widgets=widgets)
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, window_dimensions=dims)
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
- # Create the progress label
393
- self.progress_label = tk.Label(parent, text="Processing: 0/0", anchor='w', justify='left', bg=self.inactive_color, fg=self.fg_color)
394
- self.progress_label.grid(row=1, column=0, columnspan=2, pady=5, padx=5, sticky='ew')
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
- # Initialize attributes for time and operation
397
- self.operation_type = None
398
- self.time_image = None
399
- self.time_batch = None
400
- self.time_left = None
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
- # Update the progress label with current progress and additional info
404
- label_text = f"Processing: {self['value']}/{self['maximum']}"
405
- if self.operation_type:
406
- label_text += f", {self.operation_type}"
407
- if self.time_image:
408
- label_text += f", Time/image: {self.time_image:.3f} sec"
409
- if self.time_batch:
410
- label_text += f", Time/batch: {self.time_batch:.3f} sec"
411
- if self.time_left:
412
- label_text += f", Time_left: {self.time_left:.3f} min"
413
- self.progress_label.config(text=label_text)
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.grid_frame.grid_rowconfigure(0, weight=1)
1666
- self.grid_frame.grid_columnconfigure(0, weight=1)
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.clear()
1949
- self.db_update_thread.join()
1950
- self.root.quit()
1951
- self.root.destroy()
1952
- print(f'Quit application')
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
- #src_fldr = settings['src']
945
- #if not os.path.basename(src_fldr).endswith('merged'):
946
- # settings['src'] = os.path.join(src_fldr, 'merged')
947
- # print(f"changed src to {src_fldr}")
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=None)
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 Cellpose 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.",
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.31
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=4II8TscaDHDvRXc4D-azQyAeVGNkqyN6_HaNhkjij4s,35546
16
- spacr/gui_elements.py,sha256=XGM88u7acPO6ulRE4QJwD72-POcN-pKJhseRkJLELzo,96179
17
- spacr/gui_utils.py,sha256=ySSDDYmY80h_Wk2Nb1oxbugRU2TWt6N7BwusUl_-wRo,14970
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=W5_yuLnsFSafuZNcKzVsCTJSTfpbNgrGTuxG1OVb0iU,55283
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=deX0pNwTqyHojpCTiF060RSK5oPeSEcS_s6UlVc0x3Q,65442
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.31.dist-info/LICENSE,sha256=SR-2MeGc6SCM1UORJYyarSWY_A-JaOMFDj7ReSs9tRM,1083
54
- spacr-0.2.31.dist-info/METADATA,sha256=avO1ZcgZs-TVLFdCBmxznpwuIH0Cehk29AuUOmFeVKM,5050
55
- spacr-0.2.31.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
56
- spacr-0.2.31.dist-info/entry_points.txt,sha256=BMC0ql9aNNpv8lUZ8sgDLQMsqaVnX5L535gEhKUP5ho,296
57
- spacr-0.2.31.dist-info/top_level.txt,sha256=GJPU8FgwRXGzKeut6JopsSRY2R8T3i9lDgya42tLInY,6
58
- spacr-0.2.31.dist-info/RECORD,,
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