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.
- celldetective/__init__.py +2 -1
- celldetective/__main__.py +17 -0
- celldetective/extra_properties.py +62 -34
- celldetective/gui/__init__.py +1 -0
- celldetective/gui/analyze_block.py +2 -1
- celldetective/gui/classifier_widget.py +18 -10
- celldetective/gui/control_panel.py +57 -6
- celldetective/gui/layouts.py +14 -11
- celldetective/gui/neighborhood_options.py +21 -13
- celldetective/gui/plot_signals_ui.py +39 -11
- celldetective/gui/process_block.py +413 -95
- celldetective/gui/retrain_segmentation_model_options.py +17 -4
- celldetective/gui/retrain_signal_model_options.py +106 -6
- celldetective/gui/signal_annotator.py +110 -30
- celldetective/gui/signal_annotator2.py +2708 -0
- celldetective/gui/signal_annotator_options.py +3 -1
- celldetective/gui/survival_ui.py +15 -6
- celldetective/gui/tableUI.py +248 -43
- celldetective/io.py +598 -416
- celldetective/measure.py +919 -969
- celldetective/models/pair_signal_detection/blank +0 -0
- celldetective/neighborhood.py +482 -340
- celldetective/preprocessing.py +81 -61
- celldetective/relative_measurements.py +648 -0
- celldetective/scripts/analyze_signals.py +1 -1
- celldetective/scripts/measure_cells.py +28 -8
- celldetective/scripts/measure_relative.py +103 -0
- celldetective/scripts/segment_cells.py +5 -5
- celldetective/scripts/track_cells.py +4 -1
- celldetective/scripts/train_segmentation_model.py +23 -18
- celldetective/scripts/train_signal_model.py +33 -0
- celldetective/segmentation.py +67 -29
- celldetective/signals.py +402 -8
- celldetective/tracking.py +8 -2
- celldetective/utils.py +144 -12
- {celldetective-1.1.1.post3.dist-info → celldetective-1.2.0.dist-info}/METADATA +8 -8
- {celldetective-1.1.1.post3.dist-info → celldetective-1.2.0.dist-info}/RECORD +42 -38
- {celldetective-1.1.1.post3.dist-info → celldetective-1.2.0.dist-info}/WHEEL +1 -1
- tests/test_segmentation.py +1 -1
- {celldetective-1.1.1.post3.dist-info → celldetective-1.2.0.dist-info}/LICENSE +0 -0
- {celldetective-1.1.1.post3.dist-info → celldetective-1.2.0.dist-info}/entry_points.txt +0 -0
- {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.
|
|
11
|
-
from celldetective.io import
|
|
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(
|
|
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
|
-
|
|
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"
|
|
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(
|
|
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(
|
|
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
|
-
|
|
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.
|
|
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,
|
|
1038
|
-
self.grid_contents.addWidget(self.protocol_list,
|
|
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,
|
|
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
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
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
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
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(
|
|
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,
|