spacr 0.2.46__py3-none-any.whl → 0.2.56__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.
Files changed (59) hide show
  1. spacr/core.py +306 -21
  2. spacr/deep_spacr.py +101 -41
  3. spacr/gui.py +1 -3
  4. spacr/gui_core.py +78 -65
  5. spacr/gui_elements.py +437 -152
  6. spacr/gui_utils.py +84 -73
  7. spacr/io.py +14 -7
  8. spacr/measure.py +196 -145
  9. spacr/plot.py +2 -42
  10. spacr/resources/font/open_sans/OFL.txt +93 -0
  11. spacr/resources/font/open_sans/OpenSans-Italic-VariableFont_wdth,wght.ttf +0 -0
  12. spacr/resources/font/open_sans/OpenSans-VariableFont_wdth,wght.ttf +0 -0
  13. spacr/resources/font/open_sans/README.txt +100 -0
  14. spacr/resources/font/open_sans/static/OpenSans-Bold.ttf +0 -0
  15. spacr/resources/font/open_sans/static/OpenSans-BoldItalic.ttf +0 -0
  16. spacr/resources/font/open_sans/static/OpenSans-ExtraBold.ttf +0 -0
  17. spacr/resources/font/open_sans/static/OpenSans-ExtraBoldItalic.ttf +0 -0
  18. spacr/resources/font/open_sans/static/OpenSans-Italic.ttf +0 -0
  19. spacr/resources/font/open_sans/static/OpenSans-Light.ttf +0 -0
  20. spacr/resources/font/open_sans/static/OpenSans-LightItalic.ttf +0 -0
  21. spacr/resources/font/open_sans/static/OpenSans-Medium.ttf +0 -0
  22. spacr/resources/font/open_sans/static/OpenSans-MediumItalic.ttf +0 -0
  23. spacr/resources/font/open_sans/static/OpenSans-Regular.ttf +0 -0
  24. spacr/resources/font/open_sans/static/OpenSans-SemiBold.ttf +0 -0
  25. spacr/resources/font/open_sans/static/OpenSans-SemiBoldItalic.ttf +0 -0
  26. spacr/resources/font/open_sans/static/OpenSans_Condensed-Bold.ttf +0 -0
  27. spacr/resources/font/open_sans/static/OpenSans_Condensed-BoldItalic.ttf +0 -0
  28. spacr/resources/font/open_sans/static/OpenSans_Condensed-ExtraBold.ttf +0 -0
  29. spacr/resources/font/open_sans/static/OpenSans_Condensed-ExtraBoldItalic.ttf +0 -0
  30. spacr/resources/font/open_sans/static/OpenSans_Condensed-Italic.ttf +0 -0
  31. spacr/resources/font/open_sans/static/OpenSans_Condensed-Light.ttf +0 -0
  32. spacr/resources/font/open_sans/static/OpenSans_Condensed-LightItalic.ttf +0 -0
  33. spacr/resources/font/open_sans/static/OpenSans_Condensed-Medium.ttf +0 -0
  34. spacr/resources/font/open_sans/static/OpenSans_Condensed-MediumItalic.ttf +0 -0
  35. spacr/resources/font/open_sans/static/OpenSans_Condensed-Regular.ttf +0 -0
  36. spacr/resources/font/open_sans/static/OpenSans_Condensed-SemiBold.ttf +0 -0
  37. spacr/resources/font/open_sans/static/OpenSans_Condensed-SemiBoldItalic.ttf +0 -0
  38. spacr/resources/font/open_sans/static/OpenSans_SemiCondensed-Bold.ttf +0 -0
  39. spacr/resources/font/open_sans/static/OpenSans_SemiCondensed-BoldItalic.ttf +0 -0
  40. spacr/resources/font/open_sans/static/OpenSans_SemiCondensed-ExtraBold.ttf +0 -0
  41. spacr/resources/font/open_sans/static/OpenSans_SemiCondensed-ExtraBoldItalic.ttf +0 -0
  42. spacr/resources/font/open_sans/static/OpenSans_SemiCondensed-Italic.ttf +0 -0
  43. spacr/resources/font/open_sans/static/OpenSans_SemiCondensed-Light.ttf +0 -0
  44. spacr/resources/font/open_sans/static/OpenSans_SemiCondensed-LightItalic.ttf +0 -0
  45. spacr/resources/font/open_sans/static/OpenSans_SemiCondensed-Medium.ttf +0 -0
  46. spacr/resources/font/open_sans/static/OpenSans_SemiCondensed-MediumItalic.ttf +0 -0
  47. spacr/resources/font/open_sans/static/OpenSans_SemiCondensed-Regular.ttf +0 -0
  48. spacr/resources/font/open_sans/static/OpenSans_SemiCondensed-SemiBold.ttf +0 -0
  49. spacr/resources/font/open_sans/static/OpenSans_SemiCondensed-SemiBoldItalic.ttf +0 -0
  50. spacr/sequencing.py +481 -587
  51. spacr/settings.py +197 -122
  52. spacr/utils.py +21 -13
  53. {spacr-0.2.46.dist-info → spacr-0.2.56.dist-info}/METADATA +7 -4
  54. spacr-0.2.56.dist-info/RECORD +100 -0
  55. spacr-0.2.46.dist-info/RECORD +0 -60
  56. {spacr-0.2.46.dist-info → spacr-0.2.56.dist-info}/LICENSE +0 -0
  57. {spacr-0.2.46.dist-info → spacr-0.2.56.dist-info}/WHEEL +0 -0
  58. {spacr-0.2.46.dist-info → spacr-0.2.56.dist-info}/entry_points.txt +0 -0
  59. {spacr-0.2.46.dist-info → spacr-0.2.56.dist-info}/top_level.txt +0 -0
spacr/deep_spacr.py CHANGED
@@ -196,7 +196,7 @@ def test_model_performance(loaders, model, loader_name_list, epoch, train_mode,
196
196
  test_time = end_time - start_time
197
197
  return result, results_df
198
198
 
199
- def train_test_model(src, settings, custom_model=False, custom_model_path=None):
199
+ def train_test_model(settings):
200
200
 
201
201
  from .io import _save_settings, _copy_missclassified
202
202
  from .utils import pick_best_model
@@ -208,7 +208,10 @@ def train_test_model(src, settings, custom_model=False, custom_model_path=None):
208
208
  gc.collect()
209
209
 
210
210
  settings = set_default_train_test_model(settings)
211
- channels_str = ''.join(settings['channels'])
211
+
212
+ src = settings['src']
213
+
214
+ channels_str = ''.join(settings['train_channels'])
212
215
  dst = os.path.join(src,'model', settings['model_type'], channels_str, str(f"epochs_{settings['epochs']}"))
213
216
  os.makedirs(dst, exist_ok=True)
214
217
  settings['src'] = src
@@ -217,8 +220,8 @@ def train_test_model(src, settings, custom_model=False, custom_model_path=None):
217
220
  settings_csv = os.path.join(dst,'train_test_model_settings.csv')
218
221
  settings_df.to_csv(settings_csv, index=False)
219
222
 
220
- if custom_model:
221
- model = torch.load(custom_model_path)
223
+ if settings['custom_model']:
224
+ model = torch.load(settings['custom_model_path'])
222
225
 
223
226
  if settings['train']:
224
227
  _save_settings(settings, src)
@@ -234,7 +237,7 @@ def train_test_model(src, settings, custom_model=False, custom_model_path=None):
234
237
  validation_split=settings['val_split'],
235
238
  pin_memory=settings['pin_memory'],
236
239
  normalize=settings['normalize'],
237
- channels=settings['channels'],
240
+ channels=settings['train_channels'],
238
241
  augment=settings['augment'],
239
242
  verbose=settings['verbose'])
240
243
 
@@ -242,28 +245,28 @@ def train_test_model(src, settings, custom_model=False, custom_model_path=None):
242
245
  train_fig.savefig(train_batch_1_figure, format='pdf', dpi=600)
243
246
 
244
247
  if settings['train']:
245
- model = train_model(dst = settings['dst'],
246
- model_type=settings['model_type'],
247
- train_loaders = train,
248
- train_loader_names = plate_names,
249
- train_mode = settings['train_mode'],
250
- epochs = settings['epochs'],
251
- learning_rate = settings['learning_rate'],
252
- init_weights = settings['init_weights'],
253
- weight_decay = settings['weight_decay'],
254
- amsgrad = settings['amsgrad'],
255
- optimizer_type = settings['optimizer_type'],
256
- use_checkpoint = settings['use_checkpoint'],
257
- dropout_rate = settings['dropout_rate'],
258
- n_jobs = settings['n_jobs'],
259
- val_loaders = val,
260
- test_loaders = None,
261
- intermedeate_save = settings['intermedeate_save'],
262
- schedule = settings['schedule'],
263
- loss_type=settings['loss_type'],
264
- gradient_accumulation=settings['gradient_accumulation'],
265
- gradient_accumulation_steps=settings['gradient_accumulation_steps'],
266
- channels=settings['channels'])
248
+ model, model_path = train_model(dst = settings['dst'],
249
+ model_type=settings['model_type'],
250
+ train_loaders = train,
251
+ train_loader_names = plate_names,
252
+ train_mode = settings['train_mode'],
253
+ epochs = settings['epochs'],
254
+ learning_rate = settings['learning_rate'],
255
+ init_weights = settings['init_weights'],
256
+ weight_decay = settings['weight_decay'],
257
+ amsgrad = settings['amsgrad'],
258
+ optimizer_type = settings['optimizer_type'],
259
+ use_checkpoint = settings['use_checkpoint'],
260
+ dropout_rate = settings['dropout_rate'],
261
+ n_jobs = settings['n_jobs'],
262
+ val_loaders = val,
263
+ test_loaders = None,
264
+ intermedeate_save = settings['intermedeate_save'],
265
+ schedule = settings['schedule'],
266
+ loss_type=settings['loss_type'],
267
+ gradient_accumulation=settings['gradient_accumulation'],
268
+ gradient_accumulation_steps=settings['gradient_accumulation_steps'],
269
+ channels=settings['train_channels'])
267
270
 
268
271
  torch.cuda.empty_cache()
269
272
  torch.cuda.memory.empty_cache()
@@ -280,7 +283,7 @@ def train_test_model(src, settings, custom_model=False, custom_model_path=None):
280
283
  validation_split=0.0,
281
284
  pin_memory=settings['pin_memory'],
282
285
  normalize=settings['normalize'],
283
- channels=settings['channels'],
286
+ channels=settings['train_channels'],
284
287
  augment=False,
285
288
  verbose=settings['verbose'])
286
289
  if model == None:
@@ -314,6 +317,8 @@ def train_test_model(src, settings, custom_model=False, custom_model_path=None):
314
317
  torch.cuda.empty_cache()
315
318
  torch.cuda.memory.empty_cache()
316
319
  gc.collect()
320
+
321
+ return model_path
317
322
 
318
323
  def train_model(dst, model_type, train_loaders, train_loader_names, train_mode='erm', epochs=100, learning_rate=0.0001, weight_decay=0.05, amsgrad=False, optimizer_type='adamw', use_checkpoint=False, dropout_rate=0, n_jobs=20, val_loaders=None, test_loaders=None, init_weights='imagenet', intermedeate_save=None, chan_dict=None, schedule = None, loss_type='binary_cross_entropy_with_logits', gradient_accumulation=False, gradient_accumulation_steps=4, channels=['r','g','b']):
319
324
  """
@@ -348,7 +353,7 @@ def train_model(dst, model_type, train_loaders, train_loader_names, train_mode='
348
353
  """
349
354
 
350
355
  from .io import _save_model, _save_progress
351
- from .utils import compute_irm_penalty, calculate_loss, choose_model
356
+ from .utils import compute_irm_penalty, calculate_loss, choose_model, print_progress
352
357
 
353
358
  print(f'Train batches:{len(train_loaders)}, Validation batches:{len(val_loaders)}')
354
359
 
@@ -386,6 +391,7 @@ def train_model(dst, model_type, train_loaders, train_loader_names, train_mode='
386
391
  else:
387
392
  scheduler = None
388
393
 
394
+ time_ls = []
389
395
  if train_mode == 'erm':
390
396
  for epoch in range(1, epochs+1):
391
397
  model.train()
@@ -412,7 +418,13 @@ def train_model(dst, model_type, train_loaders, train_loader_names, train_mode='
412
418
  optimizer.zero_grad()
413
419
 
414
420
  avg_loss = running_loss / batch_idx
415
- print(f'\rTrain: epoch: {epoch} batch: {batch_idx}/{len(train_loaders)} avg_loss: {avg_loss:.5f} time: {(time.time()-start_time):.5f}', end='\r', flush=True)
421
+ #print(f'\rTrain: epoch: {epoch} batch: {batch_idx}/{len(train_loaders)} avg_loss: {avg_loss:.5f} time: {(time.time()-start_time):.5f}', end='\r', flush=True)
422
+
423
+ batch_size = len(train_loaders)
424
+ duration = time.time() - start_time
425
+ time_ls.append(duration)
426
+ metricks = f"Loss: {avg_loss:.5f}"
427
+ print_progress(files_processed=epoch, files_to_process=epochs, n_jobs=1, time_ls=time_ls, batch_size=batch_size, operation_type=f"Training {model_type} model", metricks=metricks)
416
428
 
417
429
  end_time = time.time()
418
430
  train_time = end_time - start_time
@@ -421,6 +433,7 @@ def train_model(dst, model_type, train_loaders, train_loader_names, train_mode='
421
433
  train_names = 'train'
422
434
  results_df, train_test_time = evaluate_model_performance(train_loaders, model, train_names, epoch, train_mode='erm', loss_type=loss_type)
423
435
  train_metrics_df['train_test_time'] = train_test_time
436
+
424
437
  if val_loaders != None:
425
438
  val_names = 'val'
426
439
  result, val_time = evaluate_model_performance(val_loaders, model, val_names, epoch, train_mode='erm', loss_type=loss_type)
@@ -430,6 +443,7 @@ def train_model(dst, model_type, train_loaders, train_loader_names, train_mode='
430
443
 
431
444
  results_df = pd.concat([results_df, result])
432
445
  train_metrics_df['val_time'] = val_time
446
+
433
447
  if test_loaders != None:
434
448
  test_names = 'test'
435
449
  result, test_test_time = evaluate_model_performance(test_loaders, model, test_names, epoch, train_mode='erm', loss_type=loss_type)
@@ -444,9 +458,30 @@ def train_model(dst, model_type, train_loaders, train_loader_names, train_mode='
444
458
  scheduler.step()
445
459
 
446
460
  _save_progress(dst, results_df, train_metrics_df, epoch, epochs)
447
- clear_output(wait=True)
448
- display(results_df)
449
- _save_model(model, model_type, results_df, dst, epoch, epochs, intermedeate_save=[0.99,0.98,0.95,0.94], channels=channels)
461
+ #clear_output(wait=True)
462
+ #display(results_df)
463
+
464
+ train_idx = f"{epoch}_train"
465
+ val_idx = f"{epoch}_val"
466
+ train_acc = results_df.loc[train_idx, 'accuracy']
467
+ neg_train_acc = results_df.loc[train_idx, 'neg_accuracy']
468
+ pos_train_acc = results_df.loc[train_idx, 'pos_accuracy']
469
+ val_acc = results_df.loc[val_idx, 'accuracy']
470
+ neg_val_acc = results_df.loc[val_idx, 'neg_accuracy']
471
+ pos_val_acc = results_df.loc[val_idx, 'pos_accuracy']
472
+ train_loss = results_df.loc[train_idx, 'loss']
473
+ train_prauc = results_df.loc[train_idx, 'prauc']
474
+ val_loss = results_df.loc[val_idx, 'loss']
475
+ val_prauc = results_df.loc[val_idx, 'prauc']
476
+
477
+ metricks = f"Train Acc: {train_acc:.5f} Val Acc: {val_acc:.5f} Train Loss: {train_loss:.5f} Val Loss: {val_loss:.5f} Train PRAUC: {train_prauc:.5f} Val PRAUC: {val_prauc:.5f}, Nc Train Acc: {neg_train_acc:.5f} Nc Val Acc: {neg_val_acc:.5f} Pc Train Acc: {pos_train_acc:.5f} Pc Val Acc: {pos_val_acc:.5f}"
478
+
479
+ batch_size = len(train_loaders)
480
+ duration = time.time() - start_time
481
+ time_ls.append(duration)
482
+ print_progress(files_processed=epoch, files_to_process=epochs, n_jobs=1, time_ls=time_ls, batch_size=batch_size, operation_type=f"Training {model_type} model", metricks=metricks)
483
+
484
+ model_path = _save_model(model, model_type, results_df, dst, epoch, epochs, intermedeate_save=[0.99,0.98,0.95,0.94], channels=channels)
450
485
 
451
486
  if train_mode == 'irm':
452
487
  dummy_w = torch.nn.Parameter(torch.Tensor([1.0])).to(device)
@@ -517,9 +552,10 @@ def train_model(dst, model_type, train_loaders, train_loader_names, train_mode='
517
552
  clear_output(wait=True)
518
553
  display(results_df)
519
554
  _save_progress(dst, results_df, train_metrics_df, epoch, epochs)
520
- _save_model(model, model_type, results_df, dst, epoch, epochs, intermedeate_save=[0.99,0.98,0.95,0.94])
521
- print(f'Saved model: {dst}')
522
- return model
555
+ model_path = _save_model(model, model_type, results_df, dst, epoch, epochs, intermedeate_save=[0.99,0.98,0.95,0.94])
556
+ print(f'Saved model: {model_path}')
557
+
558
+ return model, model_path
523
559
 
524
560
  def visualize_saliency_map(src, model_type='maxvit', model_path='', image_size=224, channels=[1,2,3], normalize=True, class_names=None, save_saliency=False, save_dir='saliency_maps'):
525
561
 
@@ -778,8 +814,32 @@ def visualize_smooth_grad(src, model_path, target_label_idx, image_size=224, cha
778
814
  smooth_grad_image = Image.fromarray((smooth_grad_map * 255).astype(np.uint8))
779
815
  smooth_grad_image.save(os.path.join(save_dir, f'smooth_grad_{file}'))
780
816
 
781
- # Usage
782
- #src = '/path/to/images'
783
- #model_path = '/path/to/model.pth'
784
- #target_label_idx = 0 # Change this to the target class index
785
- #visualize_smooth_grad(src, model_path, target_label_idx)
817
+ def deep_spacr(settings={}):
818
+ from .settings import deep_spacr_defaults
819
+ from .core import generate_training_dataset, generate_dataset, apply_model_to_tar
820
+
821
+ settings = deep_spacr_defaults(settings)
822
+ src = settings['src']
823
+
824
+ if settings['train'] or settings['test']:
825
+ if settings['generate_training_dataset']:
826
+ print(f"Generating train and test datasets ...")
827
+ train_path, test_path = generate_training_dataset(settings)
828
+ print(f'Generated Train set: {train_path}')
829
+ print(f'Generated Train set: {test_path}')
830
+ settings['src'] = os.path.dirname(train_path)
831
+
832
+ if settings['train_DL_model']:
833
+ print(f"Training model ...")
834
+ model_path = train_test_model(settings)
835
+ settings['model_path'] = model_path
836
+ settings['src'] = src
837
+
838
+ if settings['apply_model_to_dataset']:
839
+ if not os.path.exists(settings['tar_path']):
840
+ print(f"Generating dataset ...")
841
+ tar_path = generate_dataset(settings)
842
+ settings['tar_path'] = tar_path
843
+
844
+ if os.path.exists(settings['model_path']):
845
+ apply_model_to_tar(settings)
spacr/gui.py CHANGED
@@ -1,7 +1,5 @@
1
1
  import tkinter as tk
2
2
  from tkinter import ttk
3
- from PIL import Image, ImageTk, ImageDraw
4
- import os
5
3
  from multiprocessing import set_start_method
6
4
  from .gui_elements import spacrButton, create_menu_bar, set_dark_style
7
5
  from .gui_core import initiate_root
@@ -29,7 +27,7 @@ class MainApp(tk.Tk):
29
27
  }
30
28
 
31
29
  self.additional_gui_apps = {
32
- "Sequencing": (lambda frame: initiate_root(self, 'sequencing'), "Analyze sequencing data."),
30
+ #"Sequencing": (lambda frame: initiate_root(self, 'sequencing'), "Analyze sequencing data."),
33
31
  "Umap": (lambda frame: initiate_root(self, 'umap'), "Generate UMAP embeddings with datapoints represented as images."),
34
32
  "Train Cellpose": (lambda frame: initiate_root(self, 'train_cellpose'), "Train custom Cellpose models."),
35
33
  "ML Analyze": (lambda frame: initiate_root(self, 'ml_analyze'), "Machine learning analysis of data."),
spacr/gui_core.py CHANGED
@@ -1,23 +1,21 @@
1
- import os, traceback, ctypes, requests, csv, time, requests, re
1
+ import traceback, ctypes, csv, re, time
2
2
  import tkinter as tk
3
3
  from tkinter import ttk
4
4
  from tkinter import filedialog
5
5
  from multiprocessing import Process, Value, Queue, set_start_method
6
- from multiprocessing.sharedctypes import Synchronized
7
6
  from tkinter import ttk, scrolledtext
8
7
  from matplotlib.figure import Figure
9
8
  from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
10
9
  import numpy as np
11
10
  import psutil
12
11
  import GPUtil
13
- import tkinter.font as tkFont
14
12
 
15
13
  try:
16
14
  ctypes.windll.shcore.SetProcessDpiAwareness(True)
17
15
  except AttributeError:
18
16
  pass
19
17
 
20
- from .settings import set_default_train_test_model, get_measure_crop_settings, set_default_settings_preprocess_generate_masks, get_analyze_reads_default_settings, set_default_umap_image_settings
18
+ from .settings import set_default_train_test_model, get_measure_crop_settings, set_default_settings_preprocess_generate_masks, set_default_generate_barecode_mapping, set_default_umap_image_settings
21
19
  from .gui_elements import spacrProgressBar, spacrButton, spacrLabel, spacrFrame, spacrDropdownMenu ,set_dark_style
22
20
 
23
21
  # Define global variables
@@ -45,13 +43,15 @@ def toggle_settings(button_scrollable_frame):
45
43
  def toggle_category(settings):
46
44
  for setting in settings:
47
45
  if setting in vars_dict:
48
- label, widget, _ = vars_dict[setting]
46
+ label, widget, _, frame = vars_dict[setting]
49
47
  if widget.grid_info():
50
48
  label.grid_remove()
51
49
  widget.grid_remove()
50
+ frame.grid_remove()
52
51
  else:
53
52
  label.grid()
54
53
  widget.grid()
54
+ frame.grid()
55
55
 
56
56
  def on_category_select(selected_category):
57
57
  if selected_category == "Select Category":
@@ -81,15 +81,20 @@ def process_fig_queue():
81
81
 
82
82
  try:
83
83
  while not fig_queue.empty():
84
+ time.sleep(1)
84
85
  clear_canvas(canvas)
85
86
  fig = fig_queue.get_nowait()
87
+
86
88
  for ax in fig.get_axes():
87
89
  ax.set_xticks([]) # Remove x-axis ticks
88
90
  ax.set_yticks([]) # Remove y-axis ticks
89
91
  ax.xaxis.set_visible(False) # Hide the x-axis
90
92
  ax.yaxis.set_visible(False) # Hide the y-axis
91
- fig.tight_layout()
93
+
94
+ # Adjust layout to minimize spacing between axes
95
+ fig.subplots_adjust(left=0, right=1, top=1, bottom=0, wspace=0.01, hspace=0.01)
92
96
  fig.set_facecolor('black')
97
+
93
98
  canvas.figure = fig
94
99
  fig_width, fig_height = canvas_widget.winfo_width(), canvas_widget.winfo_height()
95
100
  fig.set_size_inches(fig_width / fig.dpi, fig_height / fig.dpi, forward=True)
@@ -97,12 +102,9 @@ def process_fig_queue():
97
102
  except Exception as e:
98
103
  traceback.print_exc()
99
104
  finally:
100
- after_id = canvas_widget.after(100, process_fig_queue)
105
+ after_id = canvas_widget.after(1, process_fig_queue)
101
106
  parent_frame.after_tasks.append(after_id)
102
107
 
103
-
104
-
105
-
106
108
  def set_globals(thread_control_var, 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):
107
109
  global thread_control, q, console_output, parent_frame, vars_dict, canvas, canvas_widget, scrollable_frame, fig_queue, progress_bar, usage_bars
108
110
  thread_control = thread_control_var
@@ -120,7 +122,7 @@ def set_globals(thread_control_var, q_var, console_output_var, parent_frame_var,
120
122
  def import_settings(settings_type='mask'):
121
123
  from .gui_utils import convert_settings_dict_for_gui, hide_all_settings
122
124
  global vars_dict, scrollable_frame, button_scrollable_frame
123
- from .settings import generate_fields
125
+ from .settings import generate_fields, set_default_settings_preprocess_generate_masks, get_measure_crop_settings, set_default_train_test_model, set_default_generate_barecode_mapping, set_default_umap_image_settings
124
126
 
125
127
  def read_settings_from_csv(csv_file_path):
126
128
  settings = {}
@@ -156,7 +158,7 @@ def import_settings(settings_type='mask'):
156
158
  elif settings_type == 'classify':
157
159
  settings = set_default_train_test_model(settings={})
158
160
  elif settings_type == 'sequencing':
159
- settings = get_analyze_reads_default_settings(settings={})
161
+ settings = set_default_generate_barecode_mapping(settings={})
160
162
  elif settings_type == 'umap':
161
163
  settings = set_default_umap_image_settings(settings={})
162
164
  else:
@@ -169,14 +171,15 @@ def import_settings(settings_type='mask'):
169
171
 
170
172
  def setup_settings_panel(vertical_container, settings_type='mask'):
171
173
  global vars_dict, scrollable_frame
172
- from .settings import get_identify_masks_finetune_default_settings, set_default_analyze_screen, set_default_settings_preprocess_generate_masks, get_measure_crop_settings, set_default_train_test_model, get_analyze_reads_default_settings, set_default_umap_image_settings, generate_fields, get_perform_regression_default_settings, get_train_cellpose_default_settings, get_map_barcodes_default_settings, get_analyze_recruitment_default_settings, get_check_cellpose_models_default_settings
173
- from .gui_utils import convert_settings_dict_for_gui, set_element_size
174
+ from .settings import get_identify_masks_finetune_default_settings, set_default_analyze_screen, set_default_settings_preprocess_generate_masks, get_measure_crop_settings, deep_spacr_defaults, set_default_generate_barecode_mapping, set_default_umap_image_settings, generate_fields, get_perform_regression_default_settings, get_train_cellpose_default_settings, get_map_barcodes_default_settings, get_analyze_recruitment_default_settings, get_check_cellpose_models_default_settings
175
+ from .gui_utils import convert_settings_dict_for_gui
176
+ from .gui_elements import set_element_size
174
177
 
175
- size_dict = set_element_size(vertical_container)
178
+ size_dict = set_element_size()
176
179
  settings_width = size_dict['settings_width']
177
180
 
178
181
  # Create a PanedWindow for the settings panel
179
- settings_paned_window = tk.PanedWindow(vertical_container, orient=tk.HORIZONTAL)
182
+ settings_paned_window = tk.PanedWindow(vertical_container, orient=tk.HORIZONTAL, width=size_dict['settings_width'])
180
183
  vertical_container.add(settings_paned_window, stretch="always")
181
184
 
182
185
  settings_frame = tk.Frame(settings_paned_window, width=settings_width)
@@ -194,9 +197,7 @@ def setup_settings_panel(vertical_container, settings_type='mask'):
194
197
  elif settings_type == 'measure':
195
198
  settings = get_measure_crop_settings(settings={})
196
199
  elif settings_type == 'classify':
197
- settings = set_default_train_test_model(settings={})
198
- elif settings_type == 'sequencing':
199
- settings = get_analyze_reads_default_settings(settings={})
200
+ settings = deep_spacr_defaults(settings={})
200
201
  elif settings_type == 'umap':
201
202
  settings = set_default_umap_image_settings(settings={})
202
203
  elif settings_type == 'train_cellpose':
@@ -208,7 +209,7 @@ def setup_settings_panel(vertical_container, settings_type='mask'):
208
209
  elif settings_type == 'cellpose_all':
209
210
  settings = get_check_cellpose_models_default_settings(settings={})
210
211
  elif settings_type == 'map_barcodes':
211
- settings = get_map_barcodes_default_settings(settings={})
212
+ settings = set_default_generate_barecode_mapping(settings={})
212
213
  elif settings_type == 'regression':
213
214
  settings = get_perform_regression_default_settings(settings={})
214
215
  elif settings_type == 'recruitment':
@@ -230,8 +231,12 @@ def setup_settings_panel(vertical_container, settings_type='mask'):
230
231
 
231
232
  def setup_plot_section(vertical_container):
232
233
  global canvas, canvas_widget
233
- plot_frame = tk.PanedWindow(vertical_container, orient=tk.VERTICAL)
234
+
235
+ # Create a frame for the plot section
236
+ plot_frame = tk.Frame(vertical_container, bg='lightgrey')
234
237
  vertical_container.add(plot_frame, stretch="always")
238
+
239
+ # Set up the plot
235
240
  figure = Figure(figsize=(30, 4), dpi=100)
236
241
  plot = figure.add_subplot(111)
237
242
  plot.plot([], []) # This creates an empty plot.
@@ -239,7 +244,11 @@ def setup_plot_section(vertical_container):
239
244
  canvas = FigureCanvasTkAgg(figure, master=plot_frame)
240
245
  canvas.get_tk_widget().configure(cursor='arrow', highlightthickness=0)
241
246
  canvas_widget = canvas.get_tk_widget()
242
- plot_frame.add(canvas_widget, stretch="always")
247
+ canvas_widget.grid(row=0, column=0, sticky="nsew") # Use grid for the canvas widget
248
+
249
+ plot_frame.grid_rowconfigure(0, weight=1)
250
+ plot_frame.grid_columnconfigure(0, weight=1)
251
+
243
252
  canvas.draw()
244
253
  canvas.figure = figure
245
254
  style_out = set_dark_style(ttk.Style())
@@ -250,6 +259,7 @@ def setup_plot_section(vertical_container):
250
259
  widgets = [canvas_widget]
251
260
  style = ttk.Style(vertical_container)
252
261
  _ = set_dark_style(style, containers=containers, widgets=widgets)
262
+
253
263
  return canvas, canvas_widget
254
264
 
255
265
  def setup_console(vertical_container):
@@ -260,46 +270,47 @@ def setup_console(vertical_container):
260
270
  style = ttk.Style()
261
271
  style_out = set_dark_style(style)
262
272
 
263
- # Create a PanedWindow to hold the main content and console sections
264
- main_paned_window = tk.PanedWindow(vertical_container, orient=tk.VERTICAL, bg=style_out['bg_color'])
265
- vertical_container.add(main_paned_window, stretch="always")
273
+ # Create a frame for the console section
274
+ console_frame = tk.Frame(vertical_container, bg=style_out['bg_color'])
275
+ vertical_container.add(console_frame, stretch="always")
266
276
 
267
- # Create the main content frame
268
- main_content_frame = tk.Frame(main_paned_window, bg=style_out['bg_color'])
269
- main_paned_window.add(main_content_frame, stretch="always")
270
-
271
- # Create a frame to hold the console and button sections
272
- console_button_frame = tk.Frame(main_paned_window, bg=style_out['bg_color'])
273
- main_paned_window.add(console_button_frame, stretch="always")
274
-
275
- # Create the main console frame
276
- console_frame = tk.Frame(console_button_frame, bg=style_out['bg_color'])
277
- console_frame.pack(fill=tk.BOTH, expand=True)
277
+ # Create a thicker frame at the top for the hover effect
278
+ top_border = tk.Frame(console_frame, height=5, bg=style_out['bg_color'])
279
+ top_border.grid(row=0, column=0, sticky="ew", pady=(0, 2))
278
280
 
279
281
  # Create the scrollable frame (which is a Text widget) with white text
280
282
  family = style_out['font_family']
281
- size = style_out['font_size'] -2
282
- font = tkFont.Font(family=family, size=size)
283
- console_output = tk.Text(console_frame, bg=style_out['bg_color'], fg=style_out['fg_color'], font=font)
284
- console_output.pack(fill=tk.BOTH, expand=True)
283
+ font_size = style_out['font_size'] - 2
284
+ font_loader = style_out['font_loader']
285
+ console_output = tk.Text(console_frame, bg=style_out['bg_color'], fg=style_out['fg_color'], font=font_loader.get_font(size=font_size), bd=0, highlightthickness=0)
286
+
287
+ console_output.grid(row=1, column=0, sticky="nsew") # Use grid for console_output
285
288
 
286
289
  # Configure the grid to allow expansion
287
- console_frame.grid_rowconfigure(0, weight=1)
290
+ console_frame.grid_rowconfigure(1, weight=1)
288
291
  console_frame.grid_columnconfigure(0, weight=1)
289
292
 
290
- # Create a lower frame to act as the anchor point
291
- lower_frame = tk.Frame(console_button_frame, bg=style_out['bg_color'])
292
- lower_frame.pack(fill=tk.X, expand=False)
293
+ def on_enter(event):
294
+ top_border.config(bg=style_out['active_color'])
295
+
296
+ def on_leave(event):
297
+ top_border.config(bg=style_out['bg_color'])
298
+
299
+ console_output.bind("<Enter>", on_enter)
300
+ console_output.bind("<Leave>", on_leave)
293
301
 
294
302
  return console_output, console_frame
295
303
 
296
304
  def setup_progress_frame(vertical_container):
297
305
  global progress_output
306
+ style_out = set_dark_style(ttk.Style())
307
+ font_loader = style_out['font_loader']
308
+ font_size = style_out['font_size']
298
309
  progress_frame = tk.Frame(vertical_container)
299
310
  vertical_container.add(progress_frame, stretch="always")
300
311
  label_frame = tk.Frame(progress_frame)
301
312
  label_frame.grid(row=0, column=0, sticky="ew", pady=(5, 0), padx=10)
302
- progress_label = spacrLabel(label_frame, text="Processing: 0%", font=('Helvetica', 12), anchor='w', justify='left', align="left")
313
+ progress_label = spacrLabel(label_frame, text="Processing: 0%", font=font_loader.get_font(size=font_size), anchor='w', justify='left', align="left")
303
314
  progress_label.grid(row=0, column=0, sticky="w")
304
315
  progress_output = scrolledtext.ScrolledText(progress_frame, height=10)
305
316
  progress_output.grid(row=1, column=0, sticky="nsew")
@@ -313,10 +324,10 @@ def setup_progress_frame(vertical_container):
313
324
 
314
325
  def setup_button_section(horizontal_container, settings_type='mask', run=True, abort=True, download=True, import_btn=True):
315
326
  global thread_control, parent_frame, button_frame, button_scrollable_frame, run_button, abort_button, download_dataset_button, import_button, q, fig_queue, vars_dict, progress_bar
316
- from .gui_utils import set_element_size, download_hug_dataset
317
- from .settings import categories
327
+ from .gui_utils import download_hug_dataset
328
+ from .gui_elements import set_element_size
318
329
 
319
- size_dict = set_element_size(horizontal_container)
330
+ size_dict = set_element_size()
320
331
  button_section_height = size_dict['panel_height']
321
332
  button_frame = tk.Frame(horizontal_container, height=button_section_height)
322
333
 
@@ -337,7 +348,7 @@ def setup_button_section(horizontal_container, settings_type='mask', run=True, a
337
348
  widgets.append(run_button)
338
349
  btn_col += 1
339
350
 
340
- if abort and settings_type in ['mask', 'measure', 'classify', 'sequencing', 'umap']:
351
+ if abort and settings_type in ['mask', 'measure', 'classify', 'sequencing', 'umap', 'map_barcodes']:
341
352
  abort_button = spacrButton(button_scrollable_frame.scrollable_frame, text="abort", command=lambda: initiate_abort(), show_text=False, size=size_dict['btn_size'], animation=False)
342
353
  abort_button.grid(row=btn_row, column=btn_col, pady=5, padx=5, sticky='ew')
343
354
  widgets.append(abort_button)
@@ -357,7 +368,7 @@ def setup_button_section(horizontal_container, settings_type='mask', run=True, a
357
368
 
358
369
  # Add the progress bar under the settings category menu
359
370
  progress_bar = spacrProgressBar(button_scrollable_frame.scrollable_frame, orient='horizontal', mode='determinate')
360
- progress_bar.grid(row=btn_row, column=0, columnspan=6, pady=5, padx=5, sticky='ew')
371
+ progress_bar.grid(row=btn_row, column=0, columnspan=7, pady=5, padx=5, sticky='ew')
361
372
  progress_bar.set_label_position() # Set the label position after grid placement
362
373
  widgets.append(progress_bar)
363
374
 
@@ -371,8 +382,7 @@ def setup_button_section(horizontal_container, settings_type='mask', run=True, a
371
382
 
372
383
  def setup_usage_panel(horizontal_container, btn_col):
373
384
  global usage_bars
374
- from .gui_utils import set_element_size
375
- from .gui_elements import set_dark_style
385
+ from .gui_elements import set_dark_style, set_element_size
376
386
 
377
387
  usg_col = 1
378
388
 
@@ -398,7 +408,7 @@ def setup_usage_panel(horizontal_container, btn_col):
398
408
  # Schedule the function to run again after 1000 ms (1 second)
399
409
  parent_frame.after(1000, update_usage, ram_bar, vram_bar, gpu_bar, usage_bars, parent_frame)
400
410
 
401
- size_dict = set_element_size(horizontal_container)
411
+ size_dict = set_element_size()
402
412
  usage_panel_height = size_dict['panel_height']
403
413
  usage_frame = tk.Frame(horizontal_container, height=usage_panel_height)
404
414
  horizontal_container.add(usage_frame)
@@ -413,7 +423,7 @@ def setup_usage_panel(horizontal_container, btn_col):
413
423
  widgets = [usage_scrollable_frame.scrollable_frame]
414
424
 
415
425
  usage_bars = []
416
- max_elements_per_column = 6
426
+ max_elements_per_column = 4
417
427
  row = 0
418
428
  col = 0
419
429
 
@@ -423,9 +433,9 @@ def setup_usage_panel(horizontal_container, btn_col):
423
433
  # Configure the style for the label
424
434
  style = ttk.Style()
425
435
  style_out = set_dark_style(style)
426
- size = style_out['font_size'] - 2
427
- usage_font = tkFont.Font(family=style_out['font_family'], size=size)
428
- style.configure("usage.TLabel", font=usage_font, foreground=style_out['fg_color'])
436
+ font_loader = style_out['font_loader']
437
+ font_size = style_out['font_size'] - 2
438
+ style.configure("usage.TLabel", font=font_loader.get_font(size=font_size), foreground=style_out['fg_color'])
429
439
 
430
440
  # Try adding RAM bar
431
441
  try:
@@ -525,7 +535,6 @@ def start_process(q=None, fig_queue=None, settings_type='mask'):
525
535
  q = Queue()
526
536
  if fig_queue is None:
527
537
  fig_queue = Queue()
528
-
529
538
  try:
530
539
  settings = check_settings(vars_dict, expected_types, q)
531
540
  except ValueError as e:
@@ -540,7 +549,7 @@ def start_process(q=None, fig_queue=None, settings_type='mask'):
540
549
 
541
550
  process_args = (settings_type, settings, q, fig_queue, stop_requested)
542
551
  if settings_type in [
543
- 'mask', 'measure', 'simulation', 'sequencing', 'classify', 'cellpose_dataset',
552
+ 'mask', 'umap', 'measure', 'simulation', 'sequencing', 'classify', 'cellpose_dataset',
544
553
  'train_cellpose', 'ml_analyze', 'cellpose_masks', 'cellpose_all', 'map_barcodes',
545
554
  'regression', 'recruitment', 'plaques', 'cellpose_compare', 'vision_scores',
546
555
  'vision_dataset'
@@ -573,7 +582,7 @@ def process_console_queue():
573
582
  try:
574
583
  # Extract the progress information
575
584
  match = re.search(r'Progress: (\d+)/(\d+), operation_type: ([\w\s]*)(.*)', clean_message)
576
- print('match', match)
585
+
577
586
  if match:
578
587
  current_progress = int(match.group(1))
579
588
  total_progress = int(match.group(2))
@@ -622,14 +631,18 @@ def process_console_queue():
622
631
 
623
632
  except Exception as e:
624
633
  print(f"Error parsing progress message: {e}")
625
-
626
- after_id = console_output.after(10, process_console_queue)
634
+ #else:
635
+ # # Only insert messages that do not start with "Progress:"
636
+ # console_output.insert(tk.END, clean_message + "\n")
637
+ # console_output.see(tk.END)
638
+
639
+ after_id = console_output.after(1, process_console_queue)
627
640
  parent_frame.after_tasks.append(after_id)
628
641
 
642
+
629
643
  def initiate_root(parent, settings_type='mask'):
630
644
  global q, fig_queue, thread_control, parent_frame, scrollable_frame, button_frame, vars_dict, canvas, canvas_widget, button_scrollable_frame, progress_bar
631
- from .gui_utils import main_thread_update_function, setup_frame, set_element_size
632
- from .gui import gui_app
645
+ from .gui_utils import main_thread_update_function, setup_frame
633
646
  from .settings import descriptions
634
647
 
635
648
  set_start_method('spawn', force=True)
@@ -678,4 +691,4 @@ def initiate_root(parent, settings_type='mask'):
678
691
  parent_window.after_tasks.append(after_id)
679
692
 
680
693
  print("Root initialization complete")
681
- return parent_frame, vars_dict
694
+ return parent_frame, vars_dict