celldetective 1.1.1.post3__py3-none-any.whl → 1.2.0__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 (42) hide show
  1. celldetective/__init__.py +2 -1
  2. celldetective/__main__.py +17 -0
  3. celldetective/extra_properties.py +62 -34
  4. celldetective/gui/__init__.py +1 -0
  5. celldetective/gui/analyze_block.py +2 -1
  6. celldetective/gui/classifier_widget.py +18 -10
  7. celldetective/gui/control_panel.py +57 -6
  8. celldetective/gui/layouts.py +14 -11
  9. celldetective/gui/neighborhood_options.py +21 -13
  10. celldetective/gui/plot_signals_ui.py +39 -11
  11. celldetective/gui/process_block.py +413 -95
  12. celldetective/gui/retrain_segmentation_model_options.py +17 -4
  13. celldetective/gui/retrain_signal_model_options.py +106 -6
  14. celldetective/gui/signal_annotator.py +110 -30
  15. celldetective/gui/signal_annotator2.py +2708 -0
  16. celldetective/gui/signal_annotator_options.py +3 -1
  17. celldetective/gui/survival_ui.py +15 -6
  18. celldetective/gui/tableUI.py +248 -43
  19. celldetective/io.py +598 -416
  20. celldetective/measure.py +919 -969
  21. celldetective/models/pair_signal_detection/blank +0 -0
  22. celldetective/neighborhood.py +482 -340
  23. celldetective/preprocessing.py +81 -61
  24. celldetective/relative_measurements.py +648 -0
  25. celldetective/scripts/analyze_signals.py +1 -1
  26. celldetective/scripts/measure_cells.py +28 -8
  27. celldetective/scripts/measure_relative.py +103 -0
  28. celldetective/scripts/segment_cells.py +5 -5
  29. celldetective/scripts/track_cells.py +4 -1
  30. celldetective/scripts/train_segmentation_model.py +23 -18
  31. celldetective/scripts/train_signal_model.py +33 -0
  32. celldetective/segmentation.py +67 -29
  33. celldetective/signals.py +402 -8
  34. celldetective/tracking.py +8 -2
  35. celldetective/utils.py +144 -12
  36. {celldetective-1.1.1.post3.dist-info → celldetective-1.2.0.dist-info}/METADATA +8 -8
  37. {celldetective-1.1.1.post3.dist-info → celldetective-1.2.0.dist-info}/RECORD +42 -38
  38. {celldetective-1.1.1.post3.dist-info → celldetective-1.2.0.dist-info}/WHEEL +1 -1
  39. tests/test_segmentation.py +1 -1
  40. {celldetective-1.1.1.post3.dist-info → celldetective-1.2.0.dist-info}/LICENSE +0 -0
  41. {celldetective-1.1.1.post3.dist-info → celldetective-1.2.0.dist-info}/entry_points.txt +0 -0
  42. {celldetective-1.1.1.post3.dist-info → celldetective-1.2.0.dist-info}/top_level.txt +0 -0
@@ -7,14 +7,17 @@ import gc
7
7
  from PyQt5.QtGui import QIcon, QDoubleValidator, QIntValidator
8
8
 
9
9
  from celldetective.gui.signal_annotator import MeasureAnnotator
10
- from celldetective.io import get_segmentation_models_list, control_segmentation_napari, get_signal_models_list, control_tracking_btrack, load_experiment_tables
11
- from celldetective.io import locate_segmentation_model, auto_load_number_of_frames, load_frames
10
+ from celldetective.gui.signal_annotator2 import SignalAnnotator2
11
+ from celldetective.io import get_segmentation_models_list, control_segmentation_napari, get_signal_models_list, \
12
+ control_tracking_btrack, load_experiment_tables, get_pair_signal_models_list, get_position_pickle, get_position_table
13
+ from celldetective.io import locate_segmentation_model, auto_load_number_of_frames, load_frames, locate_signal_model
12
14
  from celldetective.gui import SegmentationModelLoader, ClassifierWidget, ConfigNeighborhoods, ConfigSegmentationModelTraining, ConfigTracking, SignalAnnotator, ConfigSignalModelTraining, ConfigMeasurements, ConfigSignalAnnotator, TableUI
13
15
  from celldetective.gui.gui_utils import QHSeperationLine
16
+ from celldetective.relative_measurements import rel_measure_at_position
14
17
  from celldetective.segmentation import segment_at_position, segment_from_threshold_at_position
15
18
  from celldetective.tracking import track_at_position
16
19
  from celldetective.measure import measure_at_position
17
- from celldetective.signals import analyze_signals_at_position
20
+ from celldetective.signals import analyze_signals_at_position, analyze_pair_signals, analyze_pair_signals_at_position
18
21
  from celldetective.utils import extract_experiment_channels
19
22
  import numpy as np
20
23
  from glob import glob
@@ -42,7 +45,7 @@ from celldetective.gui import Styles
42
45
  class ProcessPanel(QFrame, Styles):
43
46
  def __init__(self, parent_window, mode):
44
47
 
45
- super().__init__()
48
+ super().__init__()
46
49
  self.parent_window = parent_window
47
50
  self.mode = mode
48
51
  self.exp_channels = self.parent_window.exp_channels
@@ -59,7 +62,7 @@ class ProcessPanel(QFrame, Styles):
59
62
  self.grid = QGridLayout(self)
60
63
  self.grid.setContentsMargins(5,5,5,5)
61
64
  self.generate_header()
62
-
65
+
63
66
  def generate_header(self):
64
67
 
65
68
  """
@@ -83,7 +86,7 @@ class ProcessPanel(QFrame, Styles):
83
86
  self.select_all_btn.setStyleSheet(self.button_select_all)
84
87
  self.grid.addWidget(self.select_all_btn, 0, 0, 1, 4, alignment=Qt.AlignLeft)
85
88
  #self.to_disable.append(self.all_tc_actions)
86
-
89
+
87
90
  self.collapse_btn = QPushButton()
88
91
  self.collapse_btn.setIcon(icon(MDI6.chevron_down,color="black"))
89
92
  self.collapse_btn.setIconSize(QSize(25, 25))
@@ -110,7 +113,7 @@ class ProcessPanel(QFrame, Styles):
110
113
  self.collapse_btn.setIconSize(QSize(20, 20))
111
114
  #self.parent.w.adjustSize()
112
115
  #self.parent.adjustSize()
113
- self.parent_window.scroll.setMinimumHeight(min(int(880), int(0.8*self.parent_window.screen_height)))
116
+ self.parent_window.scroll.setMinimumHeight(min(int(930), int(0.9*self.parent_window.screen_height)))
114
117
  self.parent_window.scroll.setMinimumWidth(425)
115
118
 
116
119
  #self.parent.scroll.adjustSize()
@@ -142,7 +145,7 @@ class ProcessPanel(QFrame, Styles):
142
145
  self.grid_contents.addWidget(self.submit_btn, 11, 0, 1, 4)
143
146
 
144
147
  def generate_measure_options(self):
145
-
148
+
146
149
  measure_layout = QHBoxLayout()
147
150
 
148
151
  self.measure_action = QCheckBox("MEASURE")
@@ -221,7 +224,7 @@ class ProcessPanel(QFrame, Styles):
221
224
 
222
225
  signal_model_vbox = QVBoxLayout()
223
226
  signal_model_vbox.setContentsMargins(25,0,25,0)
224
-
227
+
225
228
  model_zoo_layout = QHBoxLayout()
226
229
  model_zoo_layout.addWidget(QLabel("Model zoo:"),90)
227
230
 
@@ -233,11 +236,11 @@ class ProcessPanel(QFrame, Styles):
233
236
  self.train_signal_model_btn = QPushButton("TRAIN")
234
237
  self.train_signal_model_btn.setToolTip("Open a dialog box to create a new target segmentation model.")
235
238
  self.train_signal_model_btn.setIcon(icon(MDI6.redo_variant,color='black'))
236
- self.train_signal_model_btn.setIconSize(QSize(20, 20))
239
+ self.train_signal_model_btn.setIconSize(QSize(20, 20))
237
240
  self.train_signal_model_btn.setStyleSheet(self.button_style_sheet_3)
238
241
  model_zoo_layout.addWidget(self.train_signal_model_btn, 5)
239
242
  self.train_signal_model_btn.clicked.connect(self.open_signal_model_config_ui)
240
-
243
+
241
244
  signal_model_vbox.addLayout(model_zoo_layout)
242
245
  signal_model_vbox.addWidget(self.signal_models_list)
243
246
 
@@ -274,6 +277,16 @@ class ProcessPanel(QFrame, Styles):
274
277
  # self.show_track_table_btn.setEnabled(False)
275
278
  # grid_track.addWidget(self.show_track_table_btn, 6) #4,3,1,1, alignment=Qt.AlignLeft
276
279
 
280
+ self.delete_tracks_btn = QPushButton()
281
+ self.delete_tracks_btn.setIcon(icon(MDI6.trash_can,color="black"))
282
+ self.delete_tracks_btn.setIconSize(QSize(20, 20))
283
+ self.delete_tracks_btn.setToolTip("Delete existing tracks.")
284
+ self.delete_tracks_btn.setStyleSheet(self.button_select_all)
285
+ self.delete_tracks_btn.clicked.connect(self.delete_tracks)
286
+ self.delete_tracks_btn.setEnabled(True)
287
+ self.delete_tracks_btn.hide()
288
+ grid_track.addWidget(self.delete_tracks_btn, 6) #4,3,1,1, alignment=Qt.AlignLeft
289
+
277
290
  self.check_tracking_result_btn = QPushButton()
278
291
  self.check_tracking_result_btn.setIcon(icon(MDI6.eye_check_outline,color="black"))
279
292
  self.check_tracking_result_btn.setIconSize(QSize(20, 20))
@@ -293,6 +306,28 @@ class ProcessPanel(QFrame, Styles):
293
306
 
294
307
  self.grid_contents.addLayout(grid_track, 4, 0, 1,4)
295
308
 
309
+ def delete_tracks(self):
310
+
311
+ msgBox = QMessageBox()
312
+ msgBox.setIcon(QMessageBox.Question)
313
+ msgBox.setText("Do you want to erase the tracks? All subsequent annotations will be erased...")
314
+ msgBox.setWindowTitle("Info")
315
+ msgBox.setStandardButtons(QMessageBox.Yes | QMessageBox.No)
316
+ returnValue = msgBox.exec()
317
+ if returnValue == QMessageBox.No:
318
+ return None
319
+ elif returnValue == QMessageBox.Yes:
320
+ if os.path.exists(os.sep.join([self.parent_window.pos,'output','tables',f'trajectories_{self.mode}.csv'])):
321
+ os.remove(os.sep.join([self.parent_window.pos,'output','tables',f'trajectories_{self.mode}.csv']))
322
+ if os.path.exists(os.sep.join([self.parent_window.pos,'output','tables',f'trajectories_{self.mode}.pkl'])):
323
+ os.remove(os.sep.join([self.parent_window.pos,'output','tables',f'trajectories_{self.mode}.pkl']))
324
+ if os.path.exists(os.sep.join([self.parent_window.pos,'output','tables',f'napari_{self.mode[:-1]}_trajectories.npy'])):
325
+ os.remove(os.sep.join([self.parent_window.pos,'output','tables',f'napari_{self.mode[:-1]}_trajectories.npy']))
326
+ if os.path.exists(os.sep.join([self.parent_window.pos,'output','tables',f'trajectories_pairs.csv'])):
327
+ os.remove(os.sep.join([self.parent_window.pos,'output','tables',f'trajectories_pairs.csv']))
328
+ self.parent_window.update_position_options()
329
+ else:
330
+ return None
296
331
 
297
332
  def generate_segmentation_options(self):
298
333
 
@@ -310,7 +345,7 @@ class ProcessPanel(QFrame, Styles):
310
345
  self.segment_action.toggled.connect(self.enable_segmentation_model_list)
311
346
  #self.to_disable.append(self.segment_action)
312
347
  grid_segment.addWidget(self.segment_action, 90)
313
-
348
+
314
349
  self.check_seg_btn = QPushButton()
315
350
  self.check_seg_btn.setIcon(icon(MDI6.eye_check_outline,color="black"))
316
351
  self.check_seg_btn.setIconSize(QSize(20, 20))
@@ -321,7 +356,7 @@ class ProcessPanel(QFrame, Styles):
321
356
  #self.to_disable.append(self.control_target_seg)
322
357
  grid_segment.addWidget(self.check_seg_btn, 10)
323
358
  self.grid_contents.addLayout(grid_segment, 0,0,1,4)
324
-
359
+
325
360
  seg_option_vbox = QVBoxLayout()
326
361
  seg_option_vbox.setContentsMargins(25,0,25,0)
327
362
  model_zoo_layout = QHBoxLayout()
@@ -394,7 +429,7 @@ class ProcessPanel(QFrame, Styles):
394
429
  test = self.parent_window.locate_selected_position()
395
430
  if test:
396
431
  self.SignalAnnotator = SignalAnnotator(self)
397
- self.SignalAnnotator.show()
432
+ self.SignalAnnotator.show()
398
433
 
399
434
  def check_measurements(self):
400
435
 
@@ -413,8 +448,8 @@ class ProcessPanel(QFrame, Styles):
413
448
  if self.signal_analysis_action.isChecked():
414
449
  self.signal_models_list.setEnabled(True)
415
450
  else:
416
- self.signal_models_list.setEnabled(False)
417
-
451
+ self.signal_models_list.setEnabled(False)
452
+
418
453
  def init_seg_model_list(self):
419
454
 
420
455
  self.seg_model_list.clear()
@@ -428,14 +463,14 @@ class ProcessPanel(QFrame, Styles):
428
463
  self.seg_models.extend(self.seg_models_generic)
429
464
 
430
465
  #self.seg_models_generic.insert(0,'Threshold')
431
- self.seg_model_list.addItems(self.seg_models)
466
+ self.seg_model_list.addItems(self.seg_models)
432
467
 
433
468
  for i in range(len(self.seg_models)):
434
469
  self.seg_model_list.setItemData(i, self.seg_models[i], Qt.ToolTipRole)
435
470
 
436
471
  self.seg_model_list.insertSeparator(len(self.models_truncated))
437
472
 
438
-
473
+
439
474
  #if ("live_nuclei_channel" in self.exp_channels)*("dead_nuclei_channel" in self.exp_channels):
440
475
  # print("both channels found")
441
476
  # index = self.tc_seg_model_list.findText("MCF7_Hoescht_PI_w_primary_NK", Qt.MatchFixedString)
@@ -508,10 +543,10 @@ class ProcessPanel(QFrame, Styles):
508
543
  msgBox.setStandardButtons(QMessageBox.Ok)
509
544
  returnValue = msgBox.exec()
510
545
  if returnValue == QMessageBox.Ok:
511
- return None
546
+ return None
512
547
  else:
513
548
  return None
514
- else:
549
+ else:
515
550
  self.ClassifierWidget = ClassifierWidget(self)
516
551
  self.ClassifierWidget.show()
517
552
 
@@ -520,7 +555,7 @@ class ProcessPanel(QFrame, Styles):
520
555
  self.ConfigSignalAnnotator.show()
521
556
 
522
557
  def process_population(self):
523
-
558
+
524
559
  if self.parent_window.well_list.currentText()=="*":
525
560
  self.well_index = np.linspace(0,len(self.wells)-1,len(self.wells),dtype=int)
526
561
  else:
@@ -534,7 +569,28 @@ class ProcessPanel(QFrame, Styles):
534
569
  self.threshold_config = self.threshold_config_targets
535
570
  elif self.mode=="effectors":
536
571
  self.threshold_config = self.threshold_config_effectors
537
-
572
+
573
+ self.load_available_tables()
574
+
575
+ if self.df is not None and self.segment_action.isChecked():
576
+ msgBox = QMessageBox()
577
+ msgBox.setIcon(QMessageBox.Question)
578
+ msgBox.setText("Measurement tables have been found... Re-segmenting may create mismatches between the cell labels and the associated measurements. Do you want to erase the tables post-segmentation?")
579
+ msgBox.setWindowTitle("Info")
580
+ msgBox.setStandardButtons(QMessageBox.Yes | QMessageBox.No | QMessageBox.Cancel)
581
+ returnValue = msgBox.exec()
582
+ if returnValue == QMessageBox.No:
583
+ pass
584
+ elif returnValue == QMessageBox.Cancel:
585
+ return None
586
+ else:
587
+ print('erase tabs!')
588
+ tabs = [pos+os.sep.join(['output', 'tables', f'trajectories_{self.mode}.csv']) for pos in self.df_pos_info['pos_path'].unique()]
589
+ for t in tabs:
590
+ if os.path.exists(t.replace('.csv','.pkl')):
591
+ os.remove(t.replace('.csv','.pkl'))
592
+ os.remove(t)
593
+
538
594
  loop_iter=0
539
595
 
540
596
  if self.parent_window.position_list.currentText()=="*":
@@ -546,7 +602,7 @@ class ProcessPanel(QFrame, Styles):
546
602
  returnValue = msgBox.exec()
547
603
  if returnValue == QMessageBox.No:
548
604
  return None
549
-
605
+
550
606
  if self.seg_model_list.currentIndex() > len(self.models_truncated):
551
607
  self.model_name = self.seg_models[self.seg_model_list.currentIndex()-1]
552
608
  else:
@@ -557,7 +613,7 @@ class ProcessPanel(QFrame, Styles):
557
613
 
558
614
  self.diamWidget = QWidget()
559
615
  self.diamWidget.setWindowTitle('Estimate diameter')
560
-
616
+
561
617
  layout = QVBoxLayout()
562
618
  self.diamWidget.setLayout(layout)
563
619
 
@@ -583,12 +639,12 @@ class ProcessPanel(QFrame, Styles):
583
639
  if k==1:
584
640
  self.cellpose_channel_cb[k].addItems(list(self.exp_channels)+['None'])
585
641
  else:
586
- self.cellpose_channel_cb[k].addItems(list(self.exp_channels))
642
+ self.cellpose_channel_cb[k].addItems(list(self.exp_channels))
587
643
  idx = self.cellpose_channel_cb[k].findText(self.cellpose_channel_template[k])
588
644
  if idx>0:
589
645
  self.cellpose_channel_cb[k].setCurrentIndex(idx)
590
646
  else:
591
- self.cellpose_channel_cb[k].setCurrentIndex(0)
647
+ self.cellpose_channel_cb[k].setCurrentIndex(0)
592
648
 
593
649
  if k==1:
594
650
  idx = self.cellpose_channel_cb[k].findText('None')
@@ -610,7 +666,7 @@ class ProcessPanel(QFrame, Styles):
610
666
  hbox = QHBoxLayout()
611
667
  hbox.addWidget(QLabel('flow threshold: '), 33)
612
668
  hbox.addWidget(self.flow_slider, 66)
613
- layout.addLayout(hbox)
669
+ layout.addLayout(hbox)
614
670
 
615
671
  self.cellprob_slider = QLabeledDoubleSlider()
616
672
  self.cellprob_slider.setOrientation(1)
@@ -620,7 +676,7 @@ class ProcessPanel(QFrame, Styles):
620
676
  hbox = QHBoxLayout()
621
677
  hbox.addWidget(QLabel('cellprob threshold: '), 33)
622
678
  hbox.addWidget(self.cellprob_slider, 66)
623
- layout.addLayout(hbox)
679
+ layout.addLayout(hbox)
624
680
 
625
681
  self.set_cellpose_scale_btn = QPushButton('set')
626
682
  self.set_cellpose_scale_btn.clicked.connect(self.set_cellpose_scale)
@@ -635,7 +691,7 @@ class ProcessPanel(QFrame, Styles):
635
691
 
636
692
  self.diamWidget = QWidget()
637
693
  self.diamWidget.setWindowTitle('Channels')
638
-
694
+
639
695
  layout = QVBoxLayout()
640
696
  self.diamWidget.setLayout(layout)
641
697
 
@@ -654,7 +710,7 @@ class ProcessPanel(QFrame, Styles):
654
710
  if k==1:
655
711
  self.stardist_channel_cb[k].addItems(list(self.exp_channels)+['None'])
656
712
  else:
657
- self.stardist_channel_cb[k].addItems(list(self.exp_channels))
713
+ self.stardist_channel_cb[k].addItems(list(self.exp_channels))
658
714
  idx = self.stardist_channel_cb[k].findText(self.stardist_channel_template[k])
659
715
  if idx>0:
660
716
  self.stardist_channel_cb[k].setCurrentIndex(idx)
@@ -685,7 +741,7 @@ class ProcessPanel(QFrame, Styles):
685
741
  well = self.parent_window.wells[w_idx]
686
742
 
687
743
  for pos_idx in pos_indices:
688
-
744
+
689
745
  self.pos = natsorted(glob(well+f"{os.path.split(well)[-1].replace('W','').replace(os.sep,'')}*/"))[pos_idx]
690
746
  print(f"Position {self.pos}...\nLoading stack movie...")
691
747
 
@@ -695,7 +751,7 @@ class ProcessPanel(QFrame, Styles):
695
751
  os.mkdir(self.pos + 'output/tables/')
696
752
 
697
753
  if self.segment_action.isChecked():
698
-
754
+
699
755
  if len(glob(os.sep.join([self.pos, f'labels_{self.mode}','*.tif'])))>0 and self.parent_window.position_list.currentText()!="*":
700
756
  msgBox = QMessageBox()
701
757
  msgBox.setIcon(QMessageBox.Question)
@@ -715,7 +771,7 @@ class ProcessPanel(QFrame, Styles):
715
771
  msgBox.setStandardButtons(QMessageBox.Ok)
716
772
  returnValue = msgBox.exec()
717
773
  if returnValue == QMessageBox.Ok:
718
- return None
774
+ return None
719
775
  else:
720
776
  print(f"Segmentation from threshold config: {self.threshold_config}")
721
777
  segment_from_threshold_at_position(self.pos, self.mode, self.threshold_config, threads=self.parent_window.parent_window.n_threads)
@@ -768,12 +824,12 @@ class ProcessPanel(QFrame, Styles):
768
824
  # self.unfreeze()
769
825
 
770
826
  def view_current_stack_with_scale_bar(self):
771
-
827
+
772
828
  self.parent_window.locate_image()
773
829
  if self.parent_window.current_stack is not None:
774
830
  self.viewer = CellSizeViewer(
775
- initial_diameter = float(self.diameter_le.text().replace(',','.')),
776
- parent_le = self.diameter_le,
831
+ initial_diameter = float(self.diameter_le.text().replace(',', '.')),
832
+ parent_le = self.diameter_le,
777
833
  stack_path=self.parent_window.current_stack,
778
834
  window_title=f'Position {self.parent_window.position_list.currentText()}',
779
835
  frame_slider = True,
@@ -791,7 +847,7 @@ class ProcessPanel(QFrame, Styles):
791
847
  control_tracking_btrack(self.parent_window.pos, prefix=self.parent_window.movie_prefix, population=self.mode, threads=self.parent_window.parent_window.n_threads)
792
848
 
793
849
  def view_table_ui(self):
794
-
850
+
795
851
  print('Load table...')
796
852
  self.load_available_tables()
797
853
 
@@ -813,13 +869,13 @@ class ProcessPanel(QFrame, Styles):
813
869
  return None
814
870
 
815
871
  # def interpret_pos_location(self):
816
-
872
+
817
873
  # """
818
874
  # Read the well/position selection from the control panel to decide which data to load
819
875
  # Set position_indices to None if all positions must be taken
820
876
 
821
877
  # """
822
-
878
+
823
879
  # if self.well_option==len(self.wells):
824
880
  # self.well_indices = np.arange(len(self.wells))
825
881
  # else:
@@ -865,7 +921,7 @@ class ProcessPanel(QFrame, Styles):
865
921
  print(new_channels)
866
922
  with open(input_config_path) as config_file:
867
923
  input_config = json.load(config_file)
868
-
924
+
869
925
  input_config['spatial_calibration'] = scale
870
926
  input_config['channels'] = new_channels
871
927
  input_config['flow_threshold'] = flow_thresh
@@ -890,7 +946,7 @@ class ProcessPanel(QFrame, Styles):
890
946
  new_channels = [self.stardist_channel_cb[i].currentText() for i in range(len(self.stardist_channel_cb))]
891
947
  with open(input_config_path) as config_file:
892
948
  input_config = json.load(config_file)
893
-
949
+
894
950
  # input_config['spatial_calibration'] = scale
895
951
  input_config['channels'] = new_channels
896
952
  # input_config['flow_threshold'] = flow_thresh
@@ -906,17 +962,18 @@ class ProcessPanel(QFrame, Styles):
906
962
  class NeighPanel(QFrame, Styles):
907
963
  def __init__(self, parent_window):
908
964
 
909
- super().__init__()
965
+ super().__init__()
910
966
  self.parent_window = parent_window
911
967
  self.exp_channels = self.parent_window.exp_channels
912
968
  self.exp_dir = self.parent_window.exp_dir
913
969
  self.wells = np.array(self.parent_window.wells,dtype=str)
914
970
  self.protocols = []
971
+ self.mode='neighborhood'
915
972
 
916
973
  self.setFrameStyle(QFrame.StyledPanel | QFrame.Raised)
917
974
  self.grid = QGridLayout(self)
918
975
  self.generate_header()
919
-
976
+
920
977
  def generate_header(self):
921
978
 
922
979
  """
@@ -924,7 +981,7 @@ class NeighPanel(QFrame, Styles):
924
981
 
925
982
  """
926
983
 
927
- panel_title = QLabel(f"NEIGHBORHOOD")
984
+ panel_title = QLabel(f"INTERACTIONS")
928
985
  panel_title.setStyleSheet(self.block_title)
929
986
 
930
987
  self.grid.addWidget(panel_title, 0, 0, 1, 4, alignment=Qt.AlignCenter)
@@ -935,7 +992,7 @@ class NeighPanel(QFrame, Styles):
935
992
  # self.all_ticked = False
936
993
  # self.select_all_btn.setStyleSheet(self.button_select_all)
937
994
  # self.grid.addWidget(self.select_all_btn, 0, 0, 1, 4, alignment=Qt.AlignLeft)
938
-
995
+
939
996
  self.collapse_btn = QPushButton()
940
997
  self.collapse_btn.setIcon(icon(MDI6.chevron_down,color="black"))
941
998
  self.collapse_btn.setIconSize(QSize(25, 25))
@@ -943,7 +1000,7 @@ class NeighPanel(QFrame, Styles):
943
1000
  self.grid.addWidget(self.collapse_btn, 0, 0, 1, 4, alignment=Qt.AlignRight)
944
1001
 
945
1002
  self.populate_contents()
946
-
1003
+
947
1004
  self.grid.addWidget(self.ContentsFrame, 1, 0, 1, 4, alignment=Qt.AlignTop)
948
1005
  self.collapse_btn.clicked.connect(lambda: self.ContentsFrame.setHidden(not self.ContentsFrame.isHidden()))
949
1006
  self.collapse_btn.clicked.connect(self.collapse_advanced)
@@ -962,7 +1019,7 @@ class NeighPanel(QFrame, Styles):
962
1019
  self.collapse_btn.setIconSize(QSize(20, 20))
963
1020
  #self.parent.w.adjustSize()
964
1021
  #self.parent.adjustSize()
965
- self.parent_window.scroll.setMinimumHeight(min(int(750), int(0.8*self.parent_window.screen_height)))
1022
+ self.parent_window.scroll.setMinimumHeight(min(int(1000), int(0.9*self.parent_window.screen_height)))
966
1023
  self.parent_window.scroll.setMinimumWidth(425)
967
1024
 
968
1025
 
@@ -971,8 +1028,26 @@ class NeighPanel(QFrame, Styles):
971
1028
  self.ContentsFrame = QFrame()
972
1029
  self.grid_contents = QGridLayout(self.ContentsFrame)
973
1030
  self.grid_contents.setContentsMargins(0,0,0,0)
974
- self.grid_contents.setSpacing(0)
975
-
1031
+ self.grid_contents.setSpacing(3)
1032
+
1033
+ # Button to compute the neighborhoods
1034
+ neigh_option_hbox = QHBoxLayout()
1035
+ self.neigh_action = QCheckBox('NEIGHBORHOODS')
1036
+ self.neigh_action.setStyleSheet("""
1037
+ font-size: 10px;
1038
+ padding-left: 10px;
1039
+ padding-top: 5px;
1040
+ """)
1041
+ #self.neigh_action.setIcon(icon(MDI6.eyedropper, color="black"))
1042
+ #self.neigh_action.setIconSize(QSize(20, 20))
1043
+ self.neigh_action.setToolTip(
1044
+ "Compute neighborhoods in list below.")
1045
+ neigh_option_hbox.addWidget(self.neigh_action,90)
1046
+ self.grid_contents.addLayout(neigh_option_hbox, 1,0,1,4)
1047
+
1048
+ neigh_options_layout = QVBoxLayout()
1049
+
1050
+ neigh_options_vbox = QVBoxLayout()
976
1051
 
977
1052
  # DISTANCE NEIGHBORHOOD
978
1053
  dist_neigh_hbox = QHBoxLayout()
@@ -982,10 +1057,11 @@ class NeighPanel(QFrame, Styles):
982
1057
  self.dist_neigh_action = QLabel("ISOTROPIC DISTANCE THRESHOLD")
983
1058
  self.dist_neigh_action.setStyleSheet(self.action_lbl_style_sheet)
984
1059
  #self.dist_neigh_action.setIcon(icon(MDI6.circle_expand, color='black'))
1060
+ self.dist_neigh_action.setToolTip("")
985
1061
  self.dist_neigh_action.setToolTip("Define an isotropic neighborhood between the center of mass\nof the cells, within a threshold distance.")
986
1062
  #self.segment_action.toggled.connect(self.enable_segmentation_model_list)
987
1063
  #self.to_disable.append(self.segment_action)
988
-
1064
+
989
1065
  self.config_distance_neigh_btn = QPushButton()
990
1066
  self.config_distance_neigh_btn.setIcon(icon(MDI6.plus,color="black"))
991
1067
  self.config_distance_neigh_btn.setIconSize(QSize(20, 20))
@@ -994,10 +1070,9 @@ class NeighPanel(QFrame, Styles):
994
1070
  self.config_distance_neigh_btn.clicked.connect(self.open_config_distance_threshold_neighborhood)
995
1071
  dist_neigh_hbox.addWidget(self.config_distance_neigh_btn,5)
996
1072
  dist_neigh_hbox.addWidget(self.dist_neigh_action, 95)
1073
+ neigh_options_vbox.addLayout(dist_neigh_hbox)
997
1074
 
998
- self.grid_contents.addLayout(dist_neigh_hbox, 0,0,1,4)
999
-
1000
- # DISTANCE NEIGHBORHOOD
1075
+ # CONTACT NEIGHBORHOOD
1001
1076
  contact_neighborhood_layout = QHBoxLayout()
1002
1077
  contact_neighborhood_layout.setContentsMargins(0,0,0,0)
1003
1078
  contact_neighborhood_layout.setSpacing(0)
@@ -1006,7 +1081,8 @@ class NeighPanel(QFrame, Styles):
1006
1081
  self.contact_neigh_action.setToolTip("Identify touching cell masks, within a threshold edge distance.")
1007
1082
  self.contact_neigh_action.setStyleSheet(self.action_lbl_style_sheet)
1008
1083
  #self.contact_neigh_action.setIcon(icon(MDI6.transition_masked, color='black'))
1009
-
1084
+ self.contact_neigh_action.setToolTip("")
1085
+
1010
1086
  self.config_contact_neigh_btn = QPushButton()
1011
1087
  self.config_contact_neigh_btn.setIcon(icon(MDI6.plus,color="black"))
1012
1088
  self.config_contact_neigh_btn.setIconSize(QSize(20, 20))
@@ -1015,10 +1091,10 @@ class NeighPanel(QFrame, Styles):
1015
1091
  self.config_contact_neigh_btn.clicked.connect(self.open_config_contact_neighborhood)
1016
1092
  contact_neighborhood_layout.addWidget(self.config_contact_neigh_btn,5)
1017
1093
  contact_neighborhood_layout.addWidget(self.contact_neigh_action, 95)
1094
+ neigh_options_vbox.addLayout(contact_neighborhood_layout)
1095
+ #self.grid_contents.addLayout(neigh_options_vbox, 2,0,1,4)
1018
1096
 
1019
- self.grid_contents.addLayout(contact_neighborhood_layout, 1,0,1,4)
1020
-
1021
- self.grid_contents.addWidget(QHSeperationLine(), 2, 0, 1, 4)
1097
+ #self.grid_contents.addWidget(QHSeperationLine(), 3, 0, 1, 4)
1022
1098
 
1023
1099
  self.delete_protocol_btn = QPushButton('')
1024
1100
  self.delete_protocol_btn.setStyleSheet(self.button_select_all)
@@ -1034,15 +1110,205 @@ class NeighPanel(QFrame, Styles):
1034
1110
  list_header_layout = QHBoxLayout()
1035
1111
  list_header_layout.addWidget(self.protocol_list_lbl)
1036
1112
  list_header_layout.addWidget(self.delete_protocol_btn, alignment=Qt.AlignRight)
1037
- self.grid_contents.addLayout(list_header_layout, 3, 0, 1, 4)
1038
- self.grid_contents.addWidget(self.protocol_list, 4, 0, 1, 4)
1113
+ #self.grid_contents.addLayout(list_header_layout, 4, 0, 1, 4)
1114
+ #self.grid_contents.addWidget(self.protocol_list, 5, 0, 1, 4)
1115
+
1116
+ neigh_options_layout.addLayout(neigh_options_vbox)
1117
+ neigh_options_layout.addWidget(QHSeperationLine())
1118
+ neigh_options_layout.addLayout(list_header_layout)
1119
+ neigh_options_layout.addWidget(self.protocol_list)
1120
+
1121
+ neigh_options_layout.setContentsMargins(30,5,30,5)
1122
+ neigh_options_layout.setSpacing(1)
1123
+ self.grid_contents.addLayout(neigh_options_layout, 5, 0, 1, 4)
1124
+
1125
+
1126
+ rel_layout = QHBoxLayout()
1127
+ self.measure_pairs_action = QCheckBox("MEASURE PAIRS")
1128
+ self.measure_pairs_action.setStyleSheet("""
1129
+ font-size: 10px;
1130
+ padding-left: 10px;
1131
+ padding-top: 5px;
1132
+ """)
1133
+ self.measure_pairs_action.setIcon(icon(MDI6.eyedropper, color="black"))
1134
+ self.measure_pairs_action.setIconSize(QSize(20, 20))
1135
+ self.measure_pairs_action.setToolTip("Measure the relative quantities defined for the cell pairs, for all neighborhoods.")
1136
+ rel_layout.addWidget(self.measure_pairs_action, 90)
1137
+
1138
+ # self.visu_btn = QPushButton()
1139
+ # self.visu_btn.setIcon(icon(MDI6.eye_check_outline,color="black"))
1140
+ # self.visu_btn.setIconSize(QSize(20, 20))
1141
+ # self.visu_btn.clicked.connect(self.check_measurements2)
1142
+ # self.visu_btn.setToolTip("Open measurement annotator for two populations.")
1143
+ # self.visu_btn.setStyleSheet(self.button_select_all)
1144
+ # self.grid_contents.addWidget(self.visu_btn, 1,1,1,1,alignment=Qt.AlignRight)
1145
+ # rel_layout.addWidget(self.visu_btn, 6)
1146
+
1147
+ # self.config_rel_annotator_btn = QPushButton()
1148
+ # self.config_rel_annotator_btn.setIcon(icon(MDI6.cog_outline, color="black"))
1149
+ # self.config_rel_annotator_btn.setIconSize(QSize(20, 20))
1150
+ # self.config_rel_annotator_btn.setToolTip("Configure the animation of the annotation tool.")
1151
+ # self.config_rel_annotator_btn.setStyleSheet(self.button_select_all)
1152
+ # self.config_rel_annotator_btn.clicked.connect(self.open_signal_annotator_configuration_ui)
1153
+ # # self.grid_contents.addWidget(self.config_rel_annotator_btn, 1,2,1,1, alignment=Qt.AlignRight)
1154
+ # rel_layout.addWidget(self.config_rel_annotator_btn, 6)
1155
+ self.grid_contents.addLayout(rel_layout, 6, 0, 1, 4)
1156
+
1157
+ signal_layout = QVBoxLayout()
1158
+ signal_hlayout = QHBoxLayout()
1159
+ self.signal_analysis_action = QCheckBox("PAIR SIGNAL ANALYSIS")
1160
+ self.signal_analysis_action.setStyleSheet("""
1161
+ font-size: 10px;
1162
+ padding-left: 10px;
1163
+ padding-top: 5px;""")
1164
+
1165
+ self.signal_analysis_action.setIcon(icon(MDI6.chart_bell_curve_cumulative, color="black"))
1166
+ self.signal_analysis_action.setIconSize(QSize(20, 20))
1167
+ self.signal_analysis_action.setToolTip("Detect cell pair events using a DL model.")
1168
+ self.signal_analysis_action.toggled.connect(self.enable_signal_model_list)
1169
+ signal_hlayout.addWidget(self.signal_analysis_action, 90)
1170
+
1171
+ self.check_signals_btn = QPushButton()
1172
+ self.check_signals_btn.setIcon(icon(MDI6.eye_check_outline, color="black"))
1173
+ self.check_signals_btn.setIconSize(QSize(20, 20))
1174
+ self.check_signals_btn.clicked.connect(self.check_signals2)
1175
+ self.check_signals_btn.setToolTip("Annotate dynamic cell pairs.")
1176
+ self.check_signals_btn.setStyleSheet(self.button_select_all)
1177
+ signal_hlayout.addWidget(self.check_signals_btn, 6)
1178
+
1179
+ self.config_signal_annotator_btn = QPushButton()
1180
+ self.config_signal_annotator_btn.setIcon(icon(MDI6.cog_outline, color="black"))
1181
+ self.config_signal_annotator_btn.setIconSize(QSize(20, 20))
1182
+ self.config_signal_annotator_btn.setToolTip("Configure the animation of the annotation tool.")
1183
+ self.config_signal_annotator_btn.setStyleSheet(self.button_select_all)
1184
+ self.config_signal_annotator_btn.clicked.connect(self.open_signal_annotator_configuration_ui)
1185
+ signal_hlayout.addWidget(self.config_signal_annotator_btn, 6)
1186
+ signal_layout.addLayout(signal_hlayout)
1187
+ # self.to_disable.append(self.measure_action_tc)
1188
+ pair_signal_model_vbox = QVBoxLayout()
1189
+ pair_signal_model_vbox.setContentsMargins(25, 0, 25, 0)
1190
+
1191
+ pair_model_zoo_layout = QHBoxLayout()
1192
+ pair_model_zoo_layout.addWidget(QLabel("Model zoo:"), 90)
1193
+
1194
+ self.pair_signal_models_list = QComboBox()
1195
+ self.pair_signal_models_list.setEnabled(False)
1196
+ self.refresh_signal_models()
1197
+ # self.to_disable.append(self.cell_models_list)
1198
+
1199
+ self.pair_train_signal_model_btn = QPushButton("TRAIN")
1200
+ self.pair_train_signal_model_btn.setToolTip("Train a cell pair event detection model.")
1201
+ self.pair_train_signal_model_btn.setIcon(icon(MDI6.redo_variant, color='black'))
1202
+ self.pair_train_signal_model_btn.setIconSize(QSize(20, 20))
1203
+ self.pair_train_signal_model_btn.setStyleSheet(self.button_style_sheet_3)
1204
+ pair_model_zoo_layout.addWidget(self.pair_train_signal_model_btn, 5)
1205
+ self.pair_train_signal_model_btn.clicked.connect(self.open_signal_model_config_ui)
1206
+
1207
+ pair_signal_model_vbox.addLayout(pair_model_zoo_layout)
1208
+ pair_signal_model_vbox.addWidget(self.pair_signal_models_list)
1209
+
1210
+ signal_layout.addLayout(pair_signal_model_vbox)
1211
+ self.grid_contents.addLayout(signal_layout, 7, 0, 1, 4)
1212
+ self.grid_contents.addWidget(QHSeperationLine(), 11, 0, 1, 4)
1213
+
1214
+ self.view_tab_btn = QPushButton("View table")
1215
+ self.view_tab_btn.setStyleSheet(self.button_style_sheet_2)
1216
+ self.view_tab_btn.clicked.connect(self.view_table_ui)
1217
+ self.view_tab_btn.setToolTip('View table')
1218
+ self.view_tab_btn.setIcon(icon(MDI6.table,color="#1565c0"))
1219
+ self.view_tab_btn.setIconSize(QSize(20, 20))
1220
+ #self.view_tab_btn.setEnabled(False)
1221
+ self.grid_contents.addWidget(self.view_tab_btn, 12, 0, 1, 4)
1222
+
1223
+ #self.grid_contents.addWidget(QLabel(''), 12, 0, 1, 4)
1039
1224
 
1040
1225
  self.submit_btn = QPushButton("Submit")
1041
1226
  self.submit_btn.setStyleSheet(self.button_style_sheet_2)
1042
1227
  self.submit_btn.setToolTip("Compute the neighborhoods of the selected positions.")
1043
1228
  self.submit_btn.clicked.connect(self.process_neighborhood)
1044
- self.grid_contents.addWidget(self.submit_btn, 5, 0, 1, 4)
1229
+ self.grid_contents.addWidget(self.submit_btn, 14, 0, 1, 4)
1230
+
1231
+ self.neigh_action.toggled.connect(self.activate_neigh_options)
1232
+ self.neigh_action.setChecked(True)
1233
+ self.neigh_action.setChecked(False)
1234
+
1235
+
1236
+ def load_available_tables(self):
1237
+
1238
+ """
1239
+ Load the tables of the selected wells/positions from the control Panel for the population of interest
1240
+
1241
+ """
1242
+
1243
+ self.well_option = self.parent_window.well_list.currentIndex()
1244
+ if self.well_option==len(self.wells):
1245
+ wo = '*'
1246
+ else:
1247
+ wo = self.well_option
1248
+ self.position_option = self.parent_window.position_list.currentIndex()
1249
+ if self.position_option==0:
1250
+ po = '*'
1251
+ else:
1252
+ po = self.position_option - 1
1253
+
1254
+ self.df, self.df_pos_info = load_experiment_tables(self.exp_dir, well_option=wo, position_option=po, population="pairs", return_pos_info=True)
1255
+ if self.df is None:
1256
+ print('No table could be found...')
1257
+
1258
+
1259
+ def view_table_ui(self):
1260
+
1261
+ print('Load table...')
1262
+ self.load_available_tables()
1263
+
1264
+ if self.df is not None:
1265
+ plot_mode = 'static'
1266
+ self.tab_ui = TableUI(self.df, f"Well {self.parent_window.well_list.currentText()}; Position {self.parent_window.position_list.currentText()}", population='pairs', plot_mode=plot_mode)
1267
+ self.tab_ui.show()
1268
+ else:
1269
+ print('Table could not be loaded...')
1270
+ msgBox = QMessageBox()
1271
+ msgBox.setIcon(QMessageBox.Warning)
1272
+ msgBox.setText("No table could be loaded...")
1273
+ msgBox.setWindowTitle("Info")
1274
+ msgBox.setStandardButtons(QMessageBox.Ok)
1275
+ returnValue = msgBox.exec()
1276
+ if returnValue == QMessageBox.Ok:
1277
+ return None
1278
+
1279
+
1280
+ def activate_neigh_options(self):
1281
+
1282
+ if self.neigh_action.isChecked():
1283
+ self.dist_neigh_action.setEnabled(True)
1284
+ self.contact_neigh_action.setEnabled(True)
1285
+ self.config_distance_neigh_btn.setEnabled(True)
1286
+ self.config_contact_neigh_btn.setEnabled(True)
1287
+ self.protocol_list_lbl.setEnabled(True)
1288
+ self.protocol_list.setEnabled(True)
1289
+ self.delete_protocol_btn.setEnabled(True)
1290
+ else:
1291
+ self.dist_neigh_action.setEnabled(False)
1292
+ self.contact_neigh_action.setEnabled(False)
1293
+ self.config_distance_neigh_btn.setEnabled(False)
1294
+ self.config_contact_neigh_btn.setEnabled(False)
1295
+ self.protocol_list_lbl.setEnabled(False)
1296
+ self.protocol_list.setEnabled(False)
1297
+ self.delete_protocol_btn.setEnabled(False)
1298
+
1299
+ def refresh_signal_models(self):
1300
+ signal_models = get_pair_signal_models_list()
1301
+ self.pair_signal_models_list.clear()
1302
+ self.pair_signal_models_list.addItems(signal_models)
1303
+
1304
+ def open_signal_annotator_configuration_ui(self):
1305
+ self.ConfigSignalAnnotator = ConfigSignalAnnotator(self)
1306
+ self.ConfigSignalAnnotator.show()
1045
1307
 
1308
+ def open_signal_model_config_ui(self):
1309
+ self.ConfigSignalTrain = ConfigSignalModelTraining(self, signal_mode='pairs')
1310
+ self.ConfigSignalTrain.show()
1311
+
1046
1312
  def remove_protocol_from_list(self):
1047
1313
 
1048
1314
  current_item = self.protocol_list.currentRow()
@@ -1066,9 +1332,14 @@ class NeighPanel(QFrame, Styles):
1066
1332
  )
1067
1333
  self.ConfigNeigh.show()
1068
1334
 
1335
+ def enable_signal_model_list(self):
1336
+ if self.signal_analysis_action.isChecked():
1337
+ self.pair_signal_models_list.setEnabled(True)
1338
+ else:
1339
+ self.pair_signal_models_list.setEnabled(False)
1069
1340
 
1070
1341
  def process_neighborhood(self):
1071
-
1342
+
1072
1343
  if self.parent_window.well_list.currentText()=="*":
1073
1344
  self.well_index = np.linspace(0,len(self.wells)-1,len(self.wells),dtype=int)
1074
1345
  else:
@@ -1089,7 +1360,7 @@ class NeighPanel(QFrame, Styles):
1089
1360
  returnValue = msgBox.exec()
1090
1361
  if returnValue == QMessageBox.No:
1091
1362
  return None
1092
-
1363
+
1093
1364
  for w_idx in self.well_index:
1094
1365
 
1095
1366
  pos = self.parent_window.positions[w_idx]
@@ -1103,7 +1374,7 @@ class NeighPanel(QFrame, Styles):
1103
1374
  well = self.parent_window.wells[w_idx]
1104
1375
 
1105
1376
  for pos_idx in pos_indices:
1106
-
1377
+
1107
1378
  self.pos = natsorted(glob(well+f"{os.path.split(well)[-1].replace('W','').replace(os.sep,'')}*{os.sep}"))[pos_idx]
1108
1379
  print(f"Position {self.pos}...\nLoading stack movie...")
1109
1380
 
@@ -1112,41 +1383,88 @@ class NeighPanel(QFrame, Styles):
1112
1383
  if not os.path.exists(self.pos + os.sep.join(['output','tables'])+os.sep):
1113
1384
  os.mkdir(self.pos + os.sep.join(['output','tables'])+os.sep)
1114
1385
 
1115
- for protocol in self.protocols:
1116
-
1117
- if protocol['neighborhood_type']=='distance_threshold':
1118
-
1119
- compute_neighborhood_at_position(self.pos,
1120
- protocol['distance'],
1121
- population=protocol['population'],
1122
- theta_dist=None,
1123
- img_shape=(self.parent_window.shape_x,self.parent_window.shape_y),
1386
+ if self.neigh_action.isChecked():
1387
+ for protocol in self.protocols:
1388
+
1389
+ if protocol['neighborhood_type']=='distance_threshold':
1390
+
1391
+ compute_neighborhood_at_position(self.pos,
1392
+ protocol['distance'],
1393
+ population=protocol['population'],
1394
+ theta_dist=None,
1395
+ img_shape=(self.parent_window.shape_x,self.parent_window.shape_y),
1396
+ return_tables=False,
1397
+ clear_neigh=protocol['clear_neigh'],
1398
+ event_time_col=protocol['event_time_col'],
1399
+ neighborhood_kwargs=protocol['neighborhood_kwargs'],
1400
+ )
1401
+
1402
+ elif protocol['neighborhood_type']=='mask_contact':
1403
+
1404
+ compute_contact_neighborhood_at_position(self.pos,
1405
+ protocol['distance'],
1406
+ population=protocol['population'],
1407
+ theta_dist=None,
1408
+ img_shape=(self.parent_window.shape_x,self.parent_window.shape_y),
1124
1409
  return_tables=False,
1125
1410
  clear_neigh=protocol['clear_neigh'],
1126
1411
  event_time_col=protocol['event_time_col'],
1127
1412
  neighborhood_kwargs=protocol['neighborhood_kwargs'],
1128
1413
  )
1414
+ if self.measure_pairs_action.isChecked():
1415
+ rel_measure_at_position(self.pos)
1129
1416
 
1130
- elif protocol['neighborhood_type']=='mask_contact':
1131
-
1132
- compute_contact_neighborhood_at_position(self.pos,
1133
- protocol['distance'],
1134
- population=protocol['population'],
1135
- theta_dist=None,
1136
- img_shape=(self.parent_window.shape_x,self.parent_window.shape_y),
1137
- return_tables=False,
1138
- clear_neigh=protocol['clear_neigh'],
1139
- event_time_col=protocol['event_time_col'],
1140
- neighborhood_kwargs=protocol['neighborhood_kwargs'],
1141
- )
1417
+ if self.signal_analysis_action.isChecked():
1418
+
1419
+ # df_targets = get_position_pickle(self.pos, population='targets')
1420
+ # df_effectors = get_position_pickle(self.pos, population='effectors')
1421
+ # self.dataframes = {
1422
+ # 'targets': df_targets,
1423
+ # 'effectors': df_effectors,
1424
+ # }
1425
+
1426
+ # df_pairs = get_position_table(self.pos, population='pairs')
1427
+
1428
+ # # Need to identify expected reference / neighbor tables
1429
+ # model_path = locate_signal_model(self.pair_signal_models_list.currentText(), pairs=True)
1430
+ # print(f'Looking for model in {model_path}...')
1431
+ # complete_path = model_path
1432
+ # complete_path = rf"{complete_path}"
1433
+ # model_config_path = os.sep.join([complete_path, 'config_input.json'])
1434
+ # model_config_path = rf"{model_config_path}"
1435
+ # f = open(model_config_path)
1436
+ # model_config_path = json.load(f)
1437
+
1438
+ # reference_population = model_config_path['reference_population']
1439
+ # neighbor_population = model_config_path['neighbor_population']
1440
+
1441
+ # analyze_pair_signals(df_pairs, self.dataframes[reference_population], self.dataframes[neighbor_population], model=self.pair_signal_models_list.currentText())
1442
+ analyze_pair_signals_at_position(self.pos, self.pair_signal_models_list.currentText(), use_gpu=self.parent_window.parent_window.use_gpu)
1443
+ self.parent_window.update_position_options()
1142
1444
  print('Done.')
1143
1445
 
1144
1446
 
1447
+ def check_signals2(self):
1448
+
1449
+ test = self.parent_window.locate_selected_position()
1450
+ if test:
1451
+ self.SignalAnnotator2 = SignalAnnotator2(self)
1452
+ self.SignalAnnotator2.show()
1453
+
1454
+ def check_measurements2(self):
1455
+
1456
+ test = self.parent_window.locate_selected_position()
1457
+ if test:
1458
+ self.MeasurementAnnotator2 = MeasureAnnotator2(self)
1459
+ self.MeasurementAnnotator2.show()
1460
+
1461
+
1462
+
1145
1463
  class PreprocessingPanel(QFrame, Styles):
1146
-
1464
+
1147
1465
  def __init__(self, parent_window):
1148
1466
 
1149
- super().__init__()
1467
+ super().__init__()
1150
1468
  self.parent_window = parent_window
1151
1469
  self.exp_channels = self.parent_window.exp_channels
1152
1470
  self.exp_dir = self.parent_window.exp_dir
@@ -1157,12 +1475,12 @@ class PreprocessingPanel(QFrame, Styles):
1157
1475
  self.background_correction = []
1158
1476
  self.onlyFloat = QDoubleValidator()
1159
1477
  self.onlyInt = QIntValidator()
1160
-
1478
+
1161
1479
  self.setFrameStyle(QFrame.StyledPanel | QFrame.Raised)
1162
1480
  self.grid = QGridLayout(self)
1163
1481
 
1164
1482
  self.generate_header()
1165
-
1483
+
1166
1484
  def generate_header(self):
1167
1485
 
1168
1486
  """
@@ -1186,7 +1504,7 @@ class PreprocessingPanel(QFrame, Styles):
1186
1504
  self.select_all_btn.setStyleSheet(self.button_select_all)
1187
1505
  self.grid.addWidget(self.select_all_btn, 0, 0, 1, 4, alignment=Qt.AlignLeft)
1188
1506
  #self.to_disable.append(self.all_tc_actions)
1189
-
1507
+
1190
1508
  self.collapse_btn = QPushButton()
1191
1509
  self.collapse_btn.setIcon(icon(MDI6.chevron_down,color="black"))
1192
1510
  self.collapse_btn.setIconSize(QSize(25, 25))
@@ -1194,7 +1512,7 @@ class PreprocessingPanel(QFrame, Styles):
1194
1512
  self.grid.addWidget(self.collapse_btn, 0, 0, 1, 4, alignment=Qt.AlignRight)
1195
1513
 
1196
1514
  self.populate_contents()
1197
-
1515
+
1198
1516
  self.grid.addWidget(self.ContentsFrame, 1, 0, 1, 4, alignment=Qt.AlignTop)
1199
1517
  self.collapse_btn.clicked.connect(lambda: self.ContentsFrame.setHidden(not self.ContentsFrame.isHidden()))
1200
1518
  self.collapse_btn.clicked.connect(self.collapse_advanced)
@@ -1213,7 +1531,7 @@ class PreprocessingPanel(QFrame, Styles):
1213
1531
  self.collapse_btn.setIconSize(QSize(20, 20))
1214
1532
  #self.parent.w.adjustSize()
1215
1533
  #self.parent.adjustSize()
1216
- self.parent_window.scroll.setMinimumHeight(min(int(880), int(0.8*self.parent_window.screen_height)))
1534
+ self.parent_window.scroll.setMinimumHeight(min(int(930), int(0.9*self.parent_window.screen_height)))
1217
1535
  self.parent_window.scroll.setMinimumWidth(425)
1218
1536
 
1219
1537
  def populate_contents(self):
@@ -1237,7 +1555,7 @@ class PreprocessingPanel(QFrame, Styles):
1237
1555
 
1238
1556
 
1239
1557
  def launch_preprocessing(self):
1240
-
1558
+
1241
1559
  msgBox1 = QMessageBox()
1242
1560
  msgBox1.setIcon(QMessageBox.Question)
1243
1561
  msgBox1.setText("Do you want to apply the preprocessing\nto all wells and positions?")
@@ -1260,7 +1578,7 @@ class PreprocessingPanel(QFrame, Styles):
1260
1578
  return None
1261
1579
  if returnValue == QMessageBox.No:
1262
1580
  return None
1263
-
1581
+
1264
1582
  print('Proceed with correction...')
1265
1583
 
1266
1584
  if self.parent_window.well_list.currentText()=='*':
@@ -1275,7 +1593,7 @@ class PreprocessingPanel(QFrame, Styles):
1275
1593
 
1276
1594
 
1277
1595
  for k,correction_protocol in enumerate(self.protocol_layout.protocols):
1278
-
1596
+
1279
1597
  movie_prefix = None
1280
1598
  export_prefix = 'Corrected'
1281
1599
  if k>0:
@@ -1299,7 +1617,7 @@ class PreprocessingPanel(QFrame, Styles):
1299
1617
 
1300
1618
  elif correction_protocol['correction_type']=='fit':
1301
1619
 
1302
- correct_background_model(self.exp_dir,
1620
+ correct_background_model(self.exp_dir,
1303
1621
  well_option=well_option,
1304
1622
  position_option=pos_option,
1305
1623
  export= True,