celldetective 1.3.9.post4__py3-none-any.whl → 1.4.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 +0 -3
- celldetective/_version.py +1 -1
- celldetective/events.py +2 -4
- celldetective/extra_properties.py +320 -24
- celldetective/gui/InitWindow.py +33 -45
- celldetective/gui/__init__.py +1 -0
- celldetective/gui/about.py +19 -15
- celldetective/gui/analyze_block.py +34 -19
- celldetective/gui/base_components.py +23 -0
- celldetective/gui/btrack_options.py +26 -34
- celldetective/gui/classifier_widget.py +71 -80
- celldetective/gui/configure_new_exp.py +113 -17
- celldetective/gui/control_panel.py +68 -141
- celldetective/gui/generic_signal_plot.py +9 -12
- celldetective/gui/gui_utils.py +49 -21
- celldetective/gui/json_readers.py +5 -4
- celldetective/gui/layouts.py +246 -22
- celldetective/gui/measurement_options.py +32 -17
- celldetective/gui/neighborhood_options.py +10 -13
- celldetective/gui/plot_measurements.py +21 -17
- celldetective/gui/plot_signals_ui.py +131 -75
- celldetective/gui/process_block.py +180 -123
- celldetective/gui/processes/compute_neighborhood.py +594 -0
- celldetective/gui/processes/measure_cells.py +5 -0
- celldetective/gui/processes/segment_cells.py +27 -6
- celldetective/gui/processes/track_cells.py +6 -0
- celldetective/gui/retrain_segmentation_model_options.py +12 -20
- celldetective/gui/retrain_signal_model_options.py +57 -56
- celldetective/gui/seg_model_loader.py +21 -62
- celldetective/gui/signal_annotator.py +139 -72
- celldetective/gui/signal_annotator2.py +431 -635
- celldetective/gui/signal_annotator_options.py +8 -11
- celldetective/gui/survival_ui.py +49 -95
- celldetective/gui/tableUI.py +28 -25
- celldetective/gui/thresholds_gui.py +617 -1221
- celldetective/gui/viewers.py +106 -39
- celldetective/gui/workers.py +9 -3
- celldetective/io.py +73 -27
- celldetective/measure.py +63 -27
- celldetective/neighborhood.py +342 -268
- celldetective/preprocessing.py +25 -17
- celldetective/relative_measurements.py +50 -29
- celldetective/scripts/analyze_signals.py +4 -1
- celldetective/scripts/measure_relative.py +4 -1
- celldetective/scripts/segment_cells.py +0 -6
- celldetective/scripts/track_cells.py +3 -1
- celldetective/scripts/train_segmentation_model.py +7 -4
- celldetective/signals.py +29 -14
- celldetective/tracking.py +7 -2
- celldetective/utils.py +36 -8
- {celldetective-1.3.9.post4.dist-info → celldetective-1.4.0.dist-info}/METADATA +24 -16
- {celldetective-1.3.9.post4.dist-info → celldetective-1.4.0.dist-info}/RECORD +57 -55
- {celldetective-1.3.9.post4.dist-info → celldetective-1.4.0.dist-info}/WHEEL +1 -1
- tests/test_qt.py +21 -21
- {celldetective-1.3.9.post4.dist-info → celldetective-1.4.0.dist-info}/entry_points.txt +0 -0
- {celldetective-1.3.9.post4.dist-info → celldetective-1.4.0.dist-info/licenses}/LICENSE +0 -0
- {celldetective-1.3.9.post4.dist-info → celldetective-1.4.0.dist-info}/top_level.txt +0 -0
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
from PyQt5.QtWidgets import QDialog, QFrame, QGridLayout, QComboBox, QListWidget, QLabel, QPushButton, QVBoxLayout, QHBoxLayout, QCheckBox, \
|
|
2
|
-
QMessageBox
|
|
2
|
+
QMessageBox
|
|
3
3
|
from PyQt5.QtCore import Qt, QSize
|
|
4
4
|
from superqt.fonticon import icon
|
|
5
5
|
from fonticon_mdi6 import MDI6
|
|
6
6
|
import gc
|
|
7
7
|
from PyQt5.QtGui import QDoubleValidator, QIntValidator
|
|
8
8
|
|
|
9
|
+
from celldetective.gui.processes.compute_neighborhood import NeighborhoodProcess
|
|
9
10
|
from celldetective.gui.signal_annotator import MeasureAnnotator
|
|
10
11
|
from celldetective.gui.signal_annotator2 import SignalAnnotator2
|
|
11
12
|
from celldetective.io import get_segmentation_models_list, control_segmentation_napari, get_signal_models_list, \
|
|
12
13
|
control_tracks, load_experiment_tables, get_pair_signal_models_list
|
|
13
|
-
from celldetective.io import locate_segmentation_model, extract_position_name, fix_missing_labels,
|
|
14
|
-
from celldetective.gui import SegmentationModelLoader, ClassifierWidget, ConfigNeighborhoods,
|
|
14
|
+
from celldetective.io import locate_segmentation_model, extract_position_name, fix_missing_labels, locate_signal_model
|
|
15
|
+
from celldetective.gui import SegmentationModelLoader, ClassifierWidget, ConfigNeighborhoods, \
|
|
16
|
+
ConfigSegmentationModelTraining, ConfigTracking, SignalAnnotator, ConfigSignalModelTraining, ConfigMeasurements, \
|
|
17
|
+
ConfigSignalAnnotator, TableUI, CelldetectiveWidget
|
|
15
18
|
from celldetective.gui.gui_utils import QHSeperationLine
|
|
16
19
|
from celldetective.relative_measurements import rel_measure_at_position
|
|
17
|
-
from celldetective.segmentation import segment_at_position, segment_from_threshold_at_position
|
|
18
|
-
from celldetective.tracking import track_at_position
|
|
19
|
-
from celldetective.measure import measure_at_position
|
|
20
20
|
from celldetective.signals import analyze_signals_at_position, analyze_pair_signals_at_position
|
|
21
21
|
from celldetective.utils import extract_experiment_channels
|
|
22
22
|
import numpy as np
|
|
@@ -27,13 +27,9 @@ import pandas as pd
|
|
|
27
27
|
from celldetective.gui.gui_utils import center_window
|
|
28
28
|
from tifffile import imwrite
|
|
29
29
|
import json
|
|
30
|
-
import psutil
|
|
31
|
-
from celldetective.neighborhood import compute_neighborhood_at_position, compute_contact_neighborhood_at_position
|
|
32
|
-
from celldetective.gui.gui_utils import FigureCanvas
|
|
33
30
|
from celldetective.preprocessing import correct_background_model_free, correct_background_model, correct_channel_offset
|
|
34
|
-
from celldetective.
|
|
35
|
-
from celldetective.gui.
|
|
36
|
-
from celldetective.gui.layouts import CellposeParamsWidget, StarDistParamsWidget, BackgroundModelFreeCorrectionLayout, ProtocolDesignerLayout, BackgroundFitCorrectionLayout, ChannelOffsetOptionsLayout
|
|
31
|
+
from celldetective.gui.gui_utils import help_generic
|
|
32
|
+
from celldetective.gui.layouts import SignalModelParamsWidget, SegModelParamsWidget, CellposeParamsWidget, StarDistParamsWidget, BackgroundModelFreeCorrectionLayout, ProtocolDesignerLayout, BackgroundFitCorrectionLayout, ChannelOffsetOptionsLayout
|
|
37
33
|
from celldetective.gui import Styles
|
|
38
34
|
from celldetective.utils import get_software_location
|
|
39
35
|
|
|
@@ -42,10 +38,8 @@ from celldetective.gui.processes.segment_cells import SegmentCellThresholdProces
|
|
|
42
38
|
from celldetective.gui.processes.track_cells import TrackingProcess
|
|
43
39
|
from celldetective.gui.processes.measure_cells import MeasurementProcess
|
|
44
40
|
|
|
45
|
-
import time
|
|
46
|
-
import asyncio
|
|
47
|
-
|
|
48
41
|
class ProcessPanel(QFrame, Styles):
|
|
42
|
+
|
|
49
43
|
def __init__(self, parent_window, mode):
|
|
50
44
|
|
|
51
45
|
super().__init__()
|
|
@@ -55,17 +49,20 @@ class ProcessPanel(QFrame, Styles):
|
|
|
55
49
|
self.exp_dir = self.parent_window.exp_dir
|
|
56
50
|
self.exp_config = self.parent_window.exp_config
|
|
57
51
|
self.movie_prefix = self.parent_window.movie_prefix
|
|
58
|
-
self.
|
|
59
|
-
self.
|
|
60
|
-
self.wells = np.array(self.parent_window.wells,dtype=str)
|
|
52
|
+
self.threshold_configs = [None for _ in range(len(self.parent_window.populations))]
|
|
53
|
+
self.wells = np.array(self.parent_window.wells, dtype=str)
|
|
61
54
|
self.cellpose_calibrated = False
|
|
62
55
|
self.stardist_calibrated = False
|
|
56
|
+
self.segChannelsSet = False
|
|
57
|
+
self.signalChannelsSet = False
|
|
58
|
+
self.flipSeg = False
|
|
59
|
+
|
|
63
60
|
self.use_gpu = self.parent_window.parent_window.use_gpu
|
|
64
61
|
self.n_threads = self.parent_window.parent_window.n_threads
|
|
65
62
|
|
|
66
63
|
self.setFrameStyle(QFrame.StyledPanel | QFrame.Raised)
|
|
67
64
|
self.grid = QGridLayout(self)
|
|
68
|
-
self.grid.setContentsMargins(5,5,5,5)
|
|
65
|
+
self.grid.setContentsMargins(5, 5, 5, 5)
|
|
69
66
|
self.generate_header()
|
|
70
67
|
|
|
71
68
|
def generate_header(self):
|
|
@@ -85,35 +82,34 @@ class ProcessPanel(QFrame, Styles):
|
|
|
85
82
|
self.grid.addWidget(panel_title, 0, 0, 1, 4, alignment=Qt.AlignCenter)
|
|
86
83
|
|
|
87
84
|
self.help_pop_btn = QPushButton()
|
|
88
|
-
self.help_pop_btn.setIcon(icon(MDI6.help_circle,color=self.help_color))
|
|
85
|
+
self.help_pop_btn.setIcon(icon(MDI6.help_circle, color=self.help_color))
|
|
89
86
|
self.help_pop_btn.setIconSize(QSize(20, 20))
|
|
90
87
|
self.help_pop_btn.clicked.connect(self.help_population)
|
|
91
88
|
self.help_pop_btn.setStyleSheet(self.button_select_all)
|
|
92
89
|
self.help_pop_btn.setToolTip("Help.")
|
|
93
|
-
|
|
90
|
+
self.grid.addWidget(self.help_pop_btn, 0, 0, 1, 3, alignment=Qt.AlignRight)
|
|
94
91
|
|
|
95
|
-
|
|
96
|
-
self.select_all_btn
|
|
97
|
-
self.select_all_btn.
|
|
98
|
-
self.
|
|
99
|
-
self.
|
|
100
|
-
self.select_all_btn.
|
|
101
|
-
self.select_all_btn.setStyleSheet(self.button_select_all)
|
|
92
|
+
# self.select_all_btn = QPushButton()
|
|
93
|
+
# self.select_all_btn.setIcon(icon(MDI6.checkbox_blank_outline,color="black"))
|
|
94
|
+
# self.select_all_btn.setIconSize(QSize(20, 20))
|
|
95
|
+
# self.all_ticked = False
|
|
96
|
+
# self.select_all_btn.clicked.connect(self.tick_all_actions)
|
|
97
|
+
# self.select_all_btn.setStyleSheet(self.button_select_all)
|
|
102
98
|
#self.grid.addWidget(self.select_all_btn, 0, 0, 1, 4, alignment=Qt.AlignLeft)
|
|
103
99
|
#self.to_disable.append(self.all_tc_actions)
|
|
104
100
|
|
|
105
101
|
self.collapse_btn = QPushButton()
|
|
106
|
-
self.collapse_btn.setIcon(icon(MDI6.chevron_down,color="black"))
|
|
102
|
+
self.collapse_btn.setIcon(icon(MDI6.chevron_down, color="black"))
|
|
107
103
|
self.collapse_btn.setIconSize(QSize(25, 25))
|
|
108
104
|
self.collapse_btn.setStyleSheet(self.button_select_all)
|
|
109
105
|
#self.grid.addWidget(self.collapse_btn, 0, 0, 1, 4, alignment=Qt.AlignRight)
|
|
110
106
|
|
|
111
|
-
title_hbox.addWidget(
|
|
107
|
+
title_hbox.addWidget(QLabel(), 5) #self.select_all_btn
|
|
112
108
|
title_hbox.addWidget(QLabel(), 85, alignment=Qt.AlignCenter)
|
|
113
109
|
title_hbox.addWidget(self.help_pop_btn, 5)
|
|
114
110
|
title_hbox.addWidget(self.collapse_btn, 5)
|
|
115
111
|
|
|
116
|
-
self.grid.addLayout(title_hbox, 0,0,1,4)
|
|
112
|
+
self.grid.addLayout(title_hbox, 0, 0, 1, 4)
|
|
117
113
|
self.populate_contents()
|
|
118
114
|
|
|
119
115
|
self.grid.addWidget(self.ContentsFrame, 1, 0, 1, 4, alignment=Qt.AlignTop)
|
|
@@ -123,20 +119,19 @@ class ProcessPanel(QFrame, Styles):
|
|
|
123
119
|
|
|
124
120
|
def collapse_advanced(self):
|
|
125
121
|
|
|
126
|
-
|
|
127
|
-
targets_open = not self.parent_window.ProcessTargets.ContentsFrame.isHidden()
|
|
122
|
+
panels_open = [not p.ContentsFrame.isHidden() for p in self.parent_window.ProcessPopulations]
|
|
128
123
|
interactions_open = not self.parent_window.NeighPanel.ContentsFrame.isHidden()
|
|
129
124
|
preprocessing_open = not self.parent_window.PreprocessingPanel.ContentsFrame.isHidden()
|
|
130
|
-
is_open = np.array([
|
|
125
|
+
is_open = np.array(panels_open+[interactions_open, preprocessing_open])
|
|
131
126
|
|
|
132
127
|
if self.ContentsFrame.isHidden():
|
|
133
|
-
self.collapse_btn.setIcon(icon(MDI6.chevron_down,color="black"))
|
|
128
|
+
self.collapse_btn.setIcon(icon(MDI6.chevron_down, color="black"))
|
|
134
129
|
self.collapse_btn.setIconSize(QSize(20, 20))
|
|
135
130
|
if len(is_open[is_open])==0:
|
|
136
131
|
self.parent_window.scroll.setMinimumHeight(int(550))
|
|
137
132
|
self.parent_window.adjustSize()
|
|
138
133
|
else:
|
|
139
|
-
self.collapse_btn.setIcon(icon(MDI6.chevron_up,color="black"))
|
|
134
|
+
self.collapse_btn.setIcon(icon(MDI6.chevron_up, color="black"))
|
|
140
135
|
self.collapse_btn.setIconSize(QSize(20, 20))
|
|
141
136
|
self.parent_window.scroll.setMinimumHeight(min(int(930), int(0.9*self.parent_window.screen_height)))
|
|
142
137
|
|
|
@@ -352,14 +347,14 @@ class ProcessPanel(QFrame, Styles):
|
|
|
352
347
|
if returnValue == QMessageBox.No:
|
|
353
348
|
return None
|
|
354
349
|
elif returnValue == QMessageBox.Yes:
|
|
355
|
-
if os.path.exists(os.sep.join([self.parent_window.pos,'output','tables',f'trajectories_{self.mode}.csv'])):
|
|
356
|
-
os.remove(os.sep.join([self.parent_window.pos,'output','tables',f'trajectories_{self.mode}.csv']))
|
|
357
|
-
if os.path.exists(os.sep.join([self.parent_window.pos,'output','tables',f'trajectories_{self.mode}.pkl'])):
|
|
358
|
-
os.remove(os.sep.join([self.parent_window.pos,'output','tables',f'trajectories_{self.mode}.pkl']))
|
|
359
|
-
if os.path.exists(os.sep.join([self.parent_window.pos,'output','tables',f'napari_{self.mode[:-1]}_trajectories.npy'])):
|
|
360
|
-
os.remove(os.sep.join([self.parent_window.pos,'output','tables',f'napari_{self.mode[:-1]}_trajectories.npy']))
|
|
361
|
-
if os.path.exists(os.sep.join([self.parent_window.pos,'output','tables',f'trajectories_pairs.csv'])):
|
|
362
|
-
os.remove(os.sep.join([self.parent_window.pos,'output','tables',f'trajectories_pairs.csv']))
|
|
350
|
+
if os.path.exists(os.sep.join([self.parent_window.pos, 'output', 'tables', f'trajectories_{self.mode}.csv'])):
|
|
351
|
+
os.remove(os.sep.join([self.parent_window.pos, 'output', 'tables', f'trajectories_{self.mode}.csv']))
|
|
352
|
+
if os.path.exists(os.sep.join([self.parent_window.pos, 'output', 'tables', f'trajectories_{self.mode}.pkl'])):
|
|
353
|
+
os.remove(os.sep.join([self.parent_window.pos, 'output', 'tables', f'trajectories_{self.mode}.pkl']))
|
|
354
|
+
if os.path.exists(os.sep.join([self.parent_window.pos, 'output', 'tables', f'napari_{self.mode[:-1]}_trajectories.npy'])):
|
|
355
|
+
os.remove(os.sep.join([self.parent_window.pos, 'output', 'tables', f'napari_{self.mode[:-1]}_trajectories.npy']))
|
|
356
|
+
if os.path.exists(os.sep.join([self.parent_window.pos, 'output', 'tables', f'trajectories_pairs.csv'])):
|
|
357
|
+
os.remove(os.sep.join([self.parent_window.pos, 'output', 'tables', f'trajectories_pairs.csv']))
|
|
363
358
|
self.parent_window.update_position_options()
|
|
364
359
|
else:
|
|
365
360
|
return None
|
|
@@ -378,6 +373,15 @@ class ProcessPanel(QFrame, Styles):
|
|
|
378
373
|
#self.to_disable.append(self.segment_action)
|
|
379
374
|
grid_segment.addWidget(self.segment_action, 90)
|
|
380
375
|
|
|
376
|
+
self.flip_segment_btn = QPushButton()
|
|
377
|
+
self.flip_segment_btn.setIcon(icon(MDI6.camera_flip_outline,color="black"))
|
|
378
|
+
self.flip_segment_btn.setIconSize(QSize(20, 20))
|
|
379
|
+
self.flip_segment_btn.clicked.connect(self.flip_segmentation)
|
|
380
|
+
self.flip_segment_btn.setStyleSheet(self.button_select_all)
|
|
381
|
+
self.flip_segment_btn.setToolTip("Flip the order of the frames for segmentation.")
|
|
382
|
+
grid_segment.addWidget(self.flip_segment_btn, 5)
|
|
383
|
+
|
|
384
|
+
|
|
381
385
|
self.check_seg_btn = QPushButton()
|
|
382
386
|
self.check_seg_btn.setIcon(icon(MDI6.eye_check_outline,color="black"))
|
|
383
387
|
self.check_seg_btn.setIconSize(QSize(20, 20))
|
|
@@ -430,13 +434,25 @@ class ProcessPanel(QFrame, Styles):
|
|
|
430
434
|
self.seg_model_list.setEnabled(False)
|
|
431
435
|
self.grid_contents.addLayout(seg_option_vbox, 2, 0, 1, 4)
|
|
432
436
|
|
|
437
|
+
def flip_segmentation(self):
|
|
438
|
+
if not self.flipSeg:
|
|
439
|
+
self.flipSeg = True
|
|
440
|
+
self.flip_segment_btn.setIcon(icon(MDI6.camera_flip,color=self.celldetective_blue))
|
|
441
|
+
self.flip_segment_btn.setIconSize(QSize(20, 20))
|
|
442
|
+
self.flip_segment_btn.setToolTip("Unflip the order of the frames for segmentation.")
|
|
443
|
+
else:
|
|
444
|
+
self.flipSeg = False
|
|
445
|
+
self.flip_segment_btn.setIcon(icon(MDI6.camera_flip_outline,color='black'))
|
|
446
|
+
self.flip_segment_btn.setIconSize(QSize(20, 20))
|
|
447
|
+
self.flip_segment_btn.setToolTip("Flip the order of the frames for segmentation.")
|
|
448
|
+
|
|
433
449
|
def help_segmentation(self):
|
|
434
450
|
|
|
435
451
|
"""
|
|
436
452
|
Widget with different decision helper decision trees.
|
|
437
453
|
"""
|
|
438
454
|
|
|
439
|
-
self.help_w =
|
|
455
|
+
self.help_w = CelldetectiveWidget()
|
|
440
456
|
self.help_w.setWindowTitle('Helper')
|
|
441
457
|
layout = QVBoxLayout()
|
|
442
458
|
seg_strategy_btn = QPushButton('A guide to choose a segmentation strategy.')
|
|
@@ -552,16 +568,18 @@ class ProcessPanel(QFrame, Styles):
|
|
|
552
568
|
#QApplication.setOverrideCursor(Qt.WaitCursor)
|
|
553
569
|
test = self.parent_window.locate_selected_position()
|
|
554
570
|
if test:
|
|
555
|
-
print('Memory use: ', dict(psutil.virtual_memory()._asdict()))
|
|
571
|
+
#print('Memory use: ', dict(psutil.virtual_memory()._asdict()))
|
|
572
|
+
print(f"Loading images and labels into napari...")
|
|
556
573
|
try:
|
|
557
574
|
control_segmentation_napari(self.parent_window.pos, prefix=self.parent_window.movie_prefix, population=self.mode,flush_memory=True)
|
|
558
575
|
except Exception as e:
|
|
576
|
+
print(f'Task unsuccessful... Exception {e}...')
|
|
559
577
|
msgBox = QMessageBox()
|
|
560
578
|
msgBox.setIcon(QMessageBox.Warning)
|
|
561
579
|
msgBox.setText(str(e))
|
|
562
580
|
msgBox.setWindowTitle("Warning")
|
|
563
581
|
msgBox.setStandardButtons(QMessageBox.Ok)
|
|
564
|
-
|
|
582
|
+
_ = msgBox.exec()
|
|
565
583
|
|
|
566
584
|
msgBox = QMessageBox()
|
|
567
585
|
msgBox.setIcon(QMessageBox.Question)
|
|
@@ -611,7 +629,8 @@ class ProcessPanel(QFrame, Styles):
|
|
|
611
629
|
def init_seg_model_list(self):
|
|
612
630
|
|
|
613
631
|
self.seg_model_list.clear()
|
|
614
|
-
self.
|
|
632
|
+
self.seg_models_specific = get_segmentation_models_list(mode=self.mode, return_path=False)
|
|
633
|
+
self.seg_models = self.seg_models_specific.copy() #get_segmentation_models_list(mode=self.mode, return_path=False)
|
|
615
634
|
thresh = 40
|
|
616
635
|
self.models_truncated = [m[:thresh - 3]+'...' if len(m)>thresh else m for m in self.seg_models]
|
|
617
636
|
#self.seg_model_list.addItems(models_truncated)
|
|
@@ -628,22 +647,22 @@ class ProcessPanel(QFrame, Styles):
|
|
|
628
647
|
|
|
629
648
|
self.seg_model_list.insertSeparator(len(self.models_truncated))
|
|
630
649
|
|
|
631
|
-
def tick_all_actions(self):
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
def switch_all_ticks_option(self):
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
650
|
+
# def tick_all_actions(self):
|
|
651
|
+
# self.switch_all_ticks_option()
|
|
652
|
+
# if self.all_ticked:
|
|
653
|
+
# self.select_all_btn.setIcon(icon(MDI6.checkbox_outline,color="black"))
|
|
654
|
+
# self.select_all_btn.setIconSize(QSize(20, 20))
|
|
655
|
+
# self.segment_action.setChecked(True)
|
|
656
|
+
# else:
|
|
657
|
+
# self.select_all_btn.setIcon(icon(MDI6.checkbox_blank_outline,color="black"))
|
|
658
|
+
# self.select_all_btn.setIconSize(QSize(20, 20))
|
|
659
|
+
# self.segment_action.setChecked(False)
|
|
660
|
+
|
|
661
|
+
# def switch_all_ticks_option(self):
|
|
662
|
+
# if self.all_ticked == True:
|
|
663
|
+
# self.all_ticked = False
|
|
664
|
+
# else:
|
|
665
|
+
# self.all_ticked = True
|
|
647
666
|
|
|
648
667
|
def upload_segmentation_model(self):
|
|
649
668
|
print('Load a segmentation model or pipeline...')
|
|
@@ -696,6 +715,10 @@ class ProcessPanel(QFrame, Styles):
|
|
|
696
715
|
def reset_generalist_setup(self, index):
|
|
697
716
|
self.cellpose_calibrated = False
|
|
698
717
|
self.stardist_calibrated = False
|
|
718
|
+
self.segChannelsSet = False
|
|
719
|
+
|
|
720
|
+
def reset_signals(self):
|
|
721
|
+
self.signalChannelsSet = False
|
|
699
722
|
|
|
700
723
|
def process_population(self):
|
|
701
724
|
|
|
@@ -721,10 +744,8 @@ class ProcessPanel(QFrame, Styles):
|
|
|
721
744
|
# self.freeze()
|
|
722
745
|
# QApplication.setOverrideCursor(Qt.WaitCursor)
|
|
723
746
|
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
elif self.mode=="effectors":
|
|
727
|
-
self.threshold_config = self.threshold_config_effectors
|
|
747
|
+
idx = self.parent_window.populations.index(self.mode)
|
|
748
|
+
self.threshold_config = self.threshold_configs[idx]
|
|
728
749
|
|
|
729
750
|
self.load_available_tables()
|
|
730
751
|
|
|
@@ -742,6 +763,8 @@ class ProcessPanel(QFrame, Styles):
|
|
|
742
763
|
else:
|
|
743
764
|
print('erase tabs!')
|
|
744
765
|
tabs = [pos+os.sep.join(['output', 'tables', f'trajectories_{self.mode}.csv']) for pos in self.df_pos_info['pos_path'].unique()]
|
|
766
|
+
#tabs += [pos+os.sep.join(['output', 'tables', f'trajectories_pairs.csv']) for pos in self.df_pos_info['pos_path'].unique()]
|
|
767
|
+
tabs += [pos+os.sep.join(['output', 'tables', f'napari_{self.mode}_trajectories.npy']) for pos in self.df_pos_info['pos_path'].unique()]
|
|
745
768
|
for t in tabs:
|
|
746
769
|
if os.path.exists(t.replace('.csv','.pkl')):
|
|
747
770
|
os.remove(t.replace('.csv','.pkl'))
|
|
@@ -763,7 +786,6 @@ class ProcessPanel(QFrame, Styles):
|
|
|
763
786
|
self.model_name = self.seg_models[self.seg_model_list.currentIndex()-1]
|
|
764
787
|
else:
|
|
765
788
|
self.model_name = self.seg_models[self.seg_model_list.currentIndex()]
|
|
766
|
-
print(self.model_name, self.seg_model_list.currentIndex())
|
|
767
789
|
|
|
768
790
|
if self.segment_action.isChecked() and self.model_name.startswith('CP') and self.model_name in self.seg_models_generic and not self.cellpose_calibrated:
|
|
769
791
|
|
|
@@ -771,12 +793,24 @@ class ProcessPanel(QFrame, Styles):
|
|
|
771
793
|
self.diamWidget.show()
|
|
772
794
|
return None
|
|
773
795
|
|
|
774
|
-
|
|
796
|
+
elif self.segment_action.isChecked() and self.model_name.startswith('SD') and self.model_name in self.seg_models_generic and not self.stardist_calibrated:
|
|
775
797
|
|
|
776
798
|
self.diamWidget = StarDistParamsWidget(self, model_name = self.model_name)
|
|
777
799
|
self.diamWidget.show()
|
|
778
800
|
return None
|
|
779
801
|
|
|
802
|
+
elif self.segment_action.isChecked() and self.model_name in self.seg_models_specific and not self.segChannelsSet:
|
|
803
|
+
|
|
804
|
+
self.segChannelWidget = SegModelParamsWidget(self, model_name = self.model_name)
|
|
805
|
+
self.segChannelWidget.show()
|
|
806
|
+
return None
|
|
807
|
+
|
|
808
|
+
if self.signal_analysis_action.isChecked() and not self.signalChannelsSet:
|
|
809
|
+
self.signalChannelWidget = SignalModelParamsWidget(self, model_name = self.signal_models_list.currentText())
|
|
810
|
+
self.signalChannelWidget.show()
|
|
811
|
+
return None
|
|
812
|
+
|
|
813
|
+
|
|
780
814
|
self.movie_prefix = self.parent_window.movie_prefix
|
|
781
815
|
|
|
782
816
|
for w_idx in self.well_index:
|
|
@@ -822,12 +856,13 @@ class ProcessPanel(QFrame, Styles):
|
|
|
822
856
|
return None
|
|
823
857
|
else:
|
|
824
858
|
print(f"Segmentation from threshold config: {self.threshold_config}")
|
|
825
|
-
process_args = {"pos": self.pos, "mode": self.mode, "n_threads": self.n_threads, "threshold_instructions": self.threshold_config, "use_gpu": self.use_gpu}
|
|
859
|
+
process_args = {"pos": self.pos, "mode": self.mode, "n_threads": self.n_threads, "threshold_instructions": self.threshold_config, "use_gpu": self.use_gpu, 'flip': self.flipSeg}
|
|
826
860
|
self.job = ProgressWindow(SegmentCellThresholdProcess, parent_window=self, title="Segment", process_args = process_args)
|
|
827
861
|
result = self.job.exec_()
|
|
828
862
|
if result == QDialog.Accepted:
|
|
829
863
|
pass
|
|
830
864
|
elif result == QDialog.Rejected:
|
|
865
|
+
self.reset_generalist_setup(0)
|
|
831
866
|
return None
|
|
832
867
|
#segment_from_threshold_at_position(self.pos, self.mode, self.threshold_config, threads=self.parent_window.parent_window.n_threads)
|
|
833
868
|
else:
|
|
@@ -836,12 +871,13 @@ class ProcessPanel(QFrame, Styles):
|
|
|
836
871
|
# process = {"output_dir": self.output_dir, "file": self.model_name}
|
|
837
872
|
# self.download_model_job = ProgressWindow(DownloadProcess, parent_window=self, title="Download", process_args = args)
|
|
838
873
|
|
|
839
|
-
process_args = {"pos": self.pos, "mode": self.mode, "n_threads": self.n_threads, "model_name": self.model_name, "use_gpu": self.use_gpu}
|
|
874
|
+
process_args = {"pos": self.pos, "mode": self.mode, "n_threads": self.n_threads, "model_name": self.model_name, "use_gpu": self.use_gpu, 'flip': self.flipSeg}
|
|
840
875
|
self.job = ProgressWindow(SegmentCellDLProcess, parent_window=self, title="Segment", process_args = process_args)
|
|
841
876
|
result = self.job.exec_()
|
|
842
877
|
if result == QDialog.Accepted:
|
|
843
878
|
pass
|
|
844
879
|
elif result == QDialog.Rejected:
|
|
880
|
+
self.reset_generalist_setup(0)
|
|
845
881
|
return None
|
|
846
882
|
|
|
847
883
|
if self.track_action.isChecked():
|
|
@@ -900,6 +936,7 @@ class ProcessPanel(QFrame, Styles):
|
|
|
900
936
|
action.setChecked(False)
|
|
901
937
|
|
|
902
938
|
self.reset_generalist_setup(0)
|
|
939
|
+
self.reset_signals()
|
|
903
940
|
|
|
904
941
|
def open_napari_tracking(self):
|
|
905
942
|
print(f'View the tracks before post-processing for position {self.parent_window.pos} in napari...')
|
|
@@ -938,8 +975,11 @@ class ProcessPanel(QFrame, Styles):
|
|
|
938
975
|
self.position_option = self.parent_window.position_list.getSelectedIndices()
|
|
939
976
|
|
|
940
977
|
self.df, self.df_pos_info = load_experiment_tables(self.exp_dir, well_option=self.well_option, position_option=self.position_option, population=self.mode, return_pos_info=True)
|
|
978
|
+
self.signals = []
|
|
979
|
+
if self.df is not None:
|
|
980
|
+
self.signals = list(self.df.columns)
|
|
941
981
|
if self.df is None:
|
|
942
|
-
print('No table could be found...')
|
|
982
|
+
print('No table could be found for the selected position(s)...')
|
|
943
983
|
|
|
944
984
|
def set_cellpose_scale(self):
|
|
945
985
|
|
|
@@ -951,7 +991,6 @@ class ProcessPanel(QFrame, Styles):
|
|
|
951
991
|
model_complete_path = locate_segmentation_model(self.model_name)
|
|
952
992
|
input_config_path = model_complete_path+"config_input.json"
|
|
953
993
|
new_channels = [self.diamWidget.cellpose_channel_cb[i].currentText() for i in range(2)]
|
|
954
|
-
print(new_channels)
|
|
955
994
|
with open(input_config_path) as config_file:
|
|
956
995
|
input_config = json.load(config_file)
|
|
957
996
|
|
|
@@ -983,6 +1022,46 @@ class ProcessPanel(QFrame, Styles):
|
|
|
983
1022
|
self.diamWidget.close()
|
|
984
1023
|
self.process_population()
|
|
985
1024
|
|
|
1025
|
+
def set_selected_channels_for_segmentation(self):
|
|
1026
|
+
|
|
1027
|
+
model_complete_path = locate_segmentation_model(self.model_name)
|
|
1028
|
+
input_config_path = model_complete_path+"config_input.json"
|
|
1029
|
+
new_channels = [self.segChannelWidget.channel_cbs[i].currentText() for i in range(len(self.segChannelWidget.channel_cbs))]
|
|
1030
|
+
target_cell_size = None
|
|
1031
|
+
if hasattr(self.segChannelWidget, "diameter_le"):
|
|
1032
|
+
target_cell_size = float(self.segChannelWidget.diameter_le.get_threshold())
|
|
1033
|
+
|
|
1034
|
+
with open(input_config_path) as config_file:
|
|
1035
|
+
input_config = json.load(config_file)
|
|
1036
|
+
|
|
1037
|
+
input_config.update({'selected_channels': new_channels, 'target_cell_size_um': target_cell_size})
|
|
1038
|
+
|
|
1039
|
+
#input_config['channels'] = new_channels
|
|
1040
|
+
with open(input_config_path, 'w') as f:
|
|
1041
|
+
json.dump(input_config, f, indent=4)
|
|
1042
|
+
|
|
1043
|
+
self.segChannelsSet = True
|
|
1044
|
+
self.segChannelWidget.close()
|
|
1045
|
+
self.process_population()
|
|
1046
|
+
|
|
1047
|
+
def set_selected_signals_for_event_detection(self):
|
|
1048
|
+
|
|
1049
|
+
model_complete_path = locate_signal_model(self.signal_models_list.currentText())
|
|
1050
|
+
input_config_path = model_complete_path+"config_input.json"
|
|
1051
|
+
new_channels = [self.signalChannelWidget.channel_cbs[i].currentText() for i in range(len(self.signalChannelWidget.channel_cbs))]
|
|
1052
|
+
with open(input_config_path) as config_file:
|
|
1053
|
+
input_config = json.load(config_file)
|
|
1054
|
+
|
|
1055
|
+
input_config.update({'selected_channels': new_channels})
|
|
1056
|
+
|
|
1057
|
+
#input_config['channels'] = new_channels
|
|
1058
|
+
with open(input_config_path, 'w') as f:
|
|
1059
|
+
json.dump(input_config, f, indent=4)
|
|
1060
|
+
|
|
1061
|
+
self.signalChannelsSet = True
|
|
1062
|
+
self.signalChannelWidget.close()
|
|
1063
|
+
self.process_population()
|
|
1064
|
+
|
|
986
1065
|
|
|
987
1066
|
|
|
988
1067
|
class NeighPanel(QFrame, Styles):
|
|
@@ -1034,11 +1113,10 @@ class NeighPanel(QFrame, Styles):
|
|
|
1034
1113
|
|
|
1035
1114
|
def collapse_advanced(self):
|
|
1036
1115
|
|
|
1037
|
-
|
|
1038
|
-
targets_open = not self.parent_window.ProcessTargets.ContentsFrame.isHidden()
|
|
1116
|
+
panels_open = [not p.ContentsFrame.isHidden() for p in self.parent_window.ProcessPopulations]
|
|
1039
1117
|
interactions_open = not self.parent_window.NeighPanel.ContentsFrame.isHidden()
|
|
1040
1118
|
preprocessing_open = not self.parent_window.PreprocessingPanel.ContentsFrame.isHidden()
|
|
1041
|
-
is_open = np.array([
|
|
1119
|
+
is_open = np.array(panels_open+[interactions_open, preprocessing_open])
|
|
1042
1120
|
|
|
1043
1121
|
if self.ContentsFrame.isHidden():
|
|
1044
1122
|
self.collapse_btn.setIcon(icon(MDI6.chevron_down,color="black"))
|
|
@@ -1432,6 +1510,7 @@ class NeighPanel(QFrame, Styles):
|
|
|
1432
1510
|
for pos_idx in pos_indices:
|
|
1433
1511
|
|
|
1434
1512
|
self.pos = natsorted(glob(well+f"{os.path.split(well)[-1].replace('W','').replace(os.sep,'')}*{os.sep}"))[pos_idx]
|
|
1513
|
+
self.pos_name = extract_position_name(self.pos)
|
|
1435
1514
|
print(f"Position {self.pos}...\nLoading stack movie...")
|
|
1436
1515
|
|
|
1437
1516
|
if not os.path.exists(self.pos + 'output' + os.sep):
|
|
@@ -1442,39 +1521,27 @@ class NeighPanel(QFrame, Styles):
|
|
|
1442
1521
|
if self.neigh_action.isChecked():
|
|
1443
1522
|
for protocol in self.protocols:
|
|
1444
1523
|
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
event_time_col=protocol['event_time_col'],
|
|
1455
|
-
neighborhood_kwargs=protocol['neighborhood_kwargs'],
|
|
1456
|
-
)
|
|
1457
|
-
|
|
1458
|
-
elif protocol['neighborhood_type']=='mask_contact':
|
|
1459
|
-
|
|
1460
|
-
compute_contact_neighborhood_at_position(self.pos,
|
|
1461
|
-
protocol['distance'],
|
|
1462
|
-
population=protocol['population'],
|
|
1463
|
-
theta_dist=None,
|
|
1464
|
-
img_shape=(self.parent_window.shape_x,self.parent_window.shape_y),
|
|
1465
|
-
return_tables=False,
|
|
1466
|
-
clear_neigh=protocol['clear_neigh'],
|
|
1467
|
-
event_time_col=protocol['event_time_col'],
|
|
1468
|
-
neighborhood_kwargs=protocol['neighborhood_kwargs'],
|
|
1469
|
-
)
|
|
1524
|
+
process_args = {"pos": self.pos, "pos_name": self.pos_name,"protocol": protocol,"img_shape": (self.parent_window.shape_x,self.parent_window.shape_y)} #"n_threads": self.n_threads
|
|
1525
|
+
self.job = ProgressWindow(NeighborhoodProcess, parent_window=self, title="Neighborhood",
|
|
1526
|
+
process_args=process_args)
|
|
1527
|
+
result = self.job.exec_()
|
|
1528
|
+
if result == QDialog.Accepted:
|
|
1529
|
+
pass
|
|
1530
|
+
elif result == QDialog.Rejected:
|
|
1531
|
+
return None
|
|
1532
|
+
|
|
1470
1533
|
if self.measure_pairs_action.isChecked():
|
|
1471
1534
|
rel_measure_at_position(self.pos)
|
|
1472
1535
|
|
|
1473
1536
|
if self.signal_analysis_action.isChecked():
|
|
1474
1537
|
|
|
1475
|
-
analyze_pair_signals_at_position(self.pos, self.pair_signal_models_list.currentText(), use_gpu=self.parent_window.parent_window.use_gpu)
|
|
1538
|
+
analyze_pair_signals_at_position(self.pos, self.pair_signal_models_list.currentText(), use_gpu=self.parent_window.parent_window.use_gpu, populations=self.parent_window.populations)
|
|
1476
1539
|
|
|
1477
1540
|
self.parent_window.update_position_options()
|
|
1541
|
+
for action in [self.neigh_action, self.measure_pairs_action, self.signal_analysis_action]:
|
|
1542
|
+
if action.isChecked():
|
|
1543
|
+
action.setChecked(False)
|
|
1544
|
+
|
|
1478
1545
|
print('Done.')
|
|
1479
1546
|
|
|
1480
1547
|
def check_signals2(self):
|
|
@@ -1484,14 +1551,6 @@ class NeighPanel(QFrame, Styles):
|
|
|
1484
1551
|
self.SignalAnnotator2 = SignalAnnotator2(self)
|
|
1485
1552
|
self.SignalAnnotator2.show()
|
|
1486
1553
|
|
|
1487
|
-
def check_measurements2(self):
|
|
1488
|
-
|
|
1489
|
-
test = self.parent_window.locate_selected_position()
|
|
1490
|
-
if test:
|
|
1491
|
-
self.MeasurementAnnotator2 = MeasureAnnotator2(self)
|
|
1492
|
-
self.MeasurementAnnotator2.show()
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
1554
|
|
|
1496
1555
|
class PreprocessingPanel(QFrame, Styles):
|
|
1497
1556
|
|
|
@@ -1529,13 +1588,13 @@ class PreprocessingPanel(QFrame, Styles):
|
|
|
1529
1588
|
|
|
1530
1589
|
self.grid.addWidget(panel_title, 0, 0, 1, 4, alignment=Qt.AlignCenter)
|
|
1531
1590
|
|
|
1532
|
-
self.select_all_btn = QPushButton()
|
|
1533
|
-
self.select_all_btn.setIcon(icon(MDI6.checkbox_blank_outline,color="black"))
|
|
1534
|
-
self.select_all_btn.setIconSize(QSize(20, 20))
|
|
1535
|
-
self.all_ticked = False
|
|
1536
|
-
#self.select_all_btn.clicked.connect(self.tick_all_actions)
|
|
1537
|
-
self.select_all_btn.setStyleSheet(self.button_select_all)
|
|
1538
|
-
self.grid.addWidget(self.select_all_btn, 0, 0, 1, 4, alignment=Qt.AlignLeft)
|
|
1591
|
+
# self.select_all_btn = QPushButton()
|
|
1592
|
+
# self.select_all_btn.setIcon(icon(MDI6.checkbox_blank_outline,color="black"))
|
|
1593
|
+
# self.select_all_btn.setIconSize(QSize(20, 20))
|
|
1594
|
+
# self.all_ticked = False
|
|
1595
|
+
# #self.select_all_btn.clicked.connect(self.tick_all_actions)
|
|
1596
|
+
# self.select_all_btn.setStyleSheet(self.button_select_all)
|
|
1597
|
+
# self.grid.addWidget(self.select_all_btn, 0, 0, 1, 4, alignment=Qt.AlignLeft)
|
|
1539
1598
|
#self.to_disable.append(self.all_tc_actions)
|
|
1540
1599
|
|
|
1541
1600
|
self.collapse_btn = QPushButton()
|
|
@@ -1553,12 +1612,11 @@ class PreprocessingPanel(QFrame, Styles):
|
|
|
1553
1612
|
|
|
1554
1613
|
def collapse_advanced(self):
|
|
1555
1614
|
|
|
1556
|
-
|
|
1557
|
-
targets_open = not self.parent_window.ProcessTargets.ContentsFrame.isHidden()
|
|
1615
|
+
panels_open = [not p.ContentsFrame.isHidden() for p in self.parent_window.ProcessPopulations]
|
|
1558
1616
|
interactions_open = not self.parent_window.NeighPanel.ContentsFrame.isHidden()
|
|
1559
1617
|
preprocessing_open = not self.parent_window.PreprocessingPanel.ContentsFrame.isHidden()
|
|
1560
|
-
is_open = np.array([
|
|
1561
|
-
|
|
1618
|
+
is_open = np.array(panels_open+[interactions_open, preprocessing_open])
|
|
1619
|
+
|
|
1562
1620
|
if self.ContentsFrame.isHidden():
|
|
1563
1621
|
self.collapse_btn.setIcon(icon(MDI6.chevron_down,color="black"))
|
|
1564
1622
|
self.collapse_btn.setIconSize(QSize(20, 20))
|
|
@@ -1592,7 +1650,6 @@ class PreprocessingPanel(QFrame, Styles):
|
|
|
1592
1650
|
self.help_background_btn.setToolTip("Help.")
|
|
1593
1651
|
|
|
1594
1652
|
self.protocol_layout.title_layout.addWidget(self.help_background_btn, 5, alignment=Qt.AlignRight)
|
|
1595
|
-
|
|
1596
1653
|
|
|
1597
1654
|
self.channel_offset_correction_layout = QVBoxLayout()
|
|
1598
1655
|
|