celldetective 1.0.2.post1__py3-none-any.whl → 1.1.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/__main__.py +2 -2
- celldetective/events.py +2 -44
- celldetective/filters.py +4 -5
- celldetective/gui/__init__.py +1 -1
- celldetective/gui/analyze_block.py +37 -10
- celldetective/gui/btrack_options.py +24 -23
- celldetective/gui/classifier_widget.py +62 -19
- celldetective/gui/configure_new_exp.py +32 -35
- celldetective/gui/control_panel.py +115 -81
- celldetective/gui/gui_utils.py +674 -396
- celldetective/gui/json_readers.py +7 -6
- celldetective/gui/layouts.py +755 -0
- celldetective/gui/measurement_options.py +168 -487
- celldetective/gui/neighborhood_options.py +322 -270
- celldetective/gui/plot_measurements.py +1114 -0
- celldetective/gui/plot_signals_ui.py +20 -20
- celldetective/gui/process_block.py +449 -169
- celldetective/gui/retrain_segmentation_model_options.py +27 -26
- celldetective/gui/retrain_signal_model_options.py +25 -24
- celldetective/gui/seg_model_loader.py +31 -27
- celldetective/gui/signal_annotator.py +2326 -2295
- celldetective/gui/signal_annotator_options.py +18 -16
- celldetective/gui/styles.py +16 -1
- celldetective/gui/survival_ui.py +61 -39
- celldetective/gui/tableUI.py +60 -23
- celldetective/gui/thresholds_gui.py +68 -66
- celldetective/gui/viewers.py +596 -0
- celldetective/io.py +234 -23
- celldetective/measure.py +37 -32
- celldetective/neighborhood.py +495 -27
- celldetective/preprocessing.py +683 -0
- celldetective/scripts/analyze_signals.py +7 -0
- celldetective/scripts/measure_cells.py +12 -0
- celldetective/scripts/segment_cells.py +5 -0
- celldetective/scripts/track_cells.py +11 -0
- celldetective/signals.py +221 -98
- celldetective/tracking.py +0 -1
- celldetective/utils.py +178 -36
- celldetective-1.1.0.dist-info/METADATA +305 -0
- celldetective-1.1.0.dist-info/RECORD +80 -0
- {celldetective-1.0.2.post1.dist-info → celldetective-1.1.0.dist-info}/top_level.txt +1 -0
- tests/__init__.py +0 -0
- tests/test_events.py +28 -0
- tests/test_filters.py +24 -0
- tests/test_io.py +70 -0
- tests/test_measure.py +141 -0
- tests/test_neighborhood.py +70 -0
- tests/test_segmentation.py +93 -0
- tests/test_signals.py +135 -0
- tests/test_tracking.py +164 -0
- tests/test_utils.py +71 -0
- celldetective-1.0.2.post1.dist-info/METADATA +0 -221
- celldetective-1.0.2.post1.dist-info/RECORD +0 -66
- {celldetective-1.0.2.post1.dist-info → celldetective-1.1.0.dist-info}/LICENSE +0 -0
- {celldetective-1.0.2.post1.dist-info → celldetective-1.1.0.dist-info}/WHEEL +0 -0
- {celldetective-1.0.2.post1.dist-info → celldetective-1.1.0.dist-info}/entry_points.txt +0 -0
|
@@ -12,27 +12,28 @@ import numpy as np
|
|
|
12
12
|
from superqt.fonticon import icon
|
|
13
13
|
from fonticon_mdi6 import MDI6
|
|
14
14
|
import os
|
|
15
|
+
from celldetective.gui import Styles
|
|
15
16
|
|
|
16
|
-
class ConfigSignalAnnotator(QMainWindow):
|
|
17
|
+
class ConfigSignalAnnotator(QMainWindow, Styles):
|
|
17
18
|
|
|
18
19
|
"""
|
|
19
20
|
UI to set normalization and animation parameters for the annotator tool.
|
|
20
21
|
|
|
21
22
|
"""
|
|
22
23
|
|
|
23
|
-
def __init__(self,
|
|
24
|
+
def __init__(self, parent_window=None):
|
|
24
25
|
|
|
25
26
|
super().__init__()
|
|
26
|
-
self.
|
|
27
|
+
self.parent_window = parent_window
|
|
27
28
|
self.setWindowTitle("Configure signal annotator")
|
|
28
|
-
self.mode = self.
|
|
29
|
-
self.exp_dir = self.
|
|
29
|
+
self.mode = self.parent_window.mode
|
|
30
|
+
self.exp_dir = self.parent_window.exp_dir
|
|
30
31
|
self.soft_path = get_software_location()
|
|
31
32
|
|
|
32
33
|
if self.mode=="targets":
|
|
33
|
-
self.instructions_path = self.
|
|
34
|
+
self.instructions_path = self.parent_window.exp_dir + "configs/signal_annotator_config_targets.json"
|
|
34
35
|
elif self.mode=="effectors":
|
|
35
|
-
self.instructions_path = self.
|
|
36
|
+
self.instructions_path = self.parent_window.exp_dir + "configs/signal_annotator_config_effectors.json"
|
|
36
37
|
|
|
37
38
|
exp_config = self.exp_dir +"config.ini"
|
|
38
39
|
#self.config_path = self.exp_dir + self.config_name
|
|
@@ -41,7 +42,7 @@ class ConfigSignalAnnotator(QMainWindow):
|
|
|
41
42
|
self.channels = np.array(self.channels)
|
|
42
43
|
self.log_option = False
|
|
43
44
|
|
|
44
|
-
self.screen_height = self.
|
|
45
|
+
self.screen_height = self.parent_window.parent_window.parent_window.screen_height
|
|
45
46
|
center_window(self)
|
|
46
47
|
|
|
47
48
|
self.setMinimumHeight(int(0.4*self.screen_height))
|
|
@@ -49,6 +50,7 @@ class ConfigSignalAnnotator(QMainWindow):
|
|
|
49
50
|
self.populate_widget()
|
|
50
51
|
#self.load_previous_measurement_instructions()
|
|
51
52
|
|
|
53
|
+
|
|
52
54
|
def populate_widget(self):
|
|
53
55
|
|
|
54
56
|
"""
|
|
@@ -59,13 +61,13 @@ class ConfigSignalAnnotator(QMainWindow):
|
|
|
59
61
|
self.scroll_area = QScrollArea(self)
|
|
60
62
|
self.button_widget = QWidget()
|
|
61
63
|
|
|
62
|
-
main_layout = QVBoxLayout()
|
|
63
|
-
main_layout.setContentsMargins(30,30,30,30)
|
|
64
|
+
self.main_layout = QVBoxLayout()
|
|
65
|
+
self.main_layout.setContentsMargins(30,30,30,30)
|
|
64
66
|
|
|
65
67
|
sub_layout = QVBoxLayout()
|
|
66
68
|
sub_layout.setContentsMargins(10,10,10,20)
|
|
67
69
|
|
|
68
|
-
self.button_widget.setLayout(main_layout)
|
|
70
|
+
self.button_widget.setLayout(self.main_layout)
|
|
69
71
|
sub_layout.setContentsMargins(30,30,30,30)
|
|
70
72
|
|
|
71
73
|
sub_layout.addWidget(QLabel('Modality: '))
|
|
@@ -85,13 +87,13 @@ class ConfigSignalAnnotator(QMainWindow):
|
|
|
85
87
|
self.percentile_btn = QPushButton()
|
|
86
88
|
self.percentile_btn.setIcon(icon(MDI6.percent_circle_outline,color="black"))
|
|
87
89
|
self.percentile_btn.setIconSize(QSize(20, 20))
|
|
88
|
-
self.percentile_btn.setStyleSheet(self.
|
|
90
|
+
self.percentile_btn.setStyleSheet(self.button_select_all)
|
|
89
91
|
self.percentile_btn.setToolTip("Switch to percentile normalization values.")
|
|
90
92
|
self.percentile_btn.clicked.connect(self.switch_to_absolute_normalization_mode)
|
|
91
93
|
|
|
92
94
|
self.log_btn = QPushButton()
|
|
93
95
|
self.log_btn.setIcon(icon(MDI6.math_log,color="black"))
|
|
94
|
-
self.log_btn.setStyleSheet(self.
|
|
96
|
+
self.log_btn.setStyleSheet(self.button_select_all)
|
|
95
97
|
self.log_btn.clicked.connect(self.switch_to_log)
|
|
96
98
|
self.log_btn.setToolTip("Log-transform the intensities.")
|
|
97
99
|
self.log_btn.setIconSize(QSize(20, 20))
|
|
@@ -168,12 +170,12 @@ class ConfigSignalAnnotator(QMainWindow):
|
|
|
168
170
|
hbox_interval.addWidget(self.interval_slider, 80)
|
|
169
171
|
sub_layout.addLayout(hbox_interval)
|
|
170
172
|
|
|
171
|
-
main_layout.addLayout(sub_layout)
|
|
173
|
+
self.main_layout.addLayout(sub_layout)
|
|
172
174
|
|
|
173
175
|
self.submit_btn = QPushButton('Save')
|
|
174
|
-
self.submit_btn.setStyleSheet(self.
|
|
176
|
+
self.submit_btn.setStyleSheet(self.button_style_sheet)
|
|
175
177
|
self.submit_btn.clicked.connect(self.write_instructions)
|
|
176
|
-
main_layout.addWidget(self.submit_btn)
|
|
178
|
+
self.main_layout.addWidget(self.submit_btn)
|
|
177
179
|
|
|
178
180
|
|
|
179
181
|
self.button_widget.adjustSize()
|
celldetective/gui/styles.py
CHANGED
|
@@ -4,6 +4,14 @@ class Styles(object):
|
|
|
4
4
|
|
|
5
5
|
self.init_button_styles()
|
|
6
6
|
self.init_tab_styles()
|
|
7
|
+
self.init_label_styles()
|
|
8
|
+
|
|
9
|
+
self.celldetective_blue = "#1565c0"
|
|
10
|
+
|
|
11
|
+
self.action_lbl_style_sheet = """
|
|
12
|
+
font-size: 10px;
|
|
13
|
+
padding-left: 10px;
|
|
14
|
+
"""
|
|
7
15
|
|
|
8
16
|
def init_button_styles(self):
|
|
9
17
|
|
|
@@ -214,4 +222,11 @@ class Styles(object):
|
|
|
214
222
|
QTabBar::tab:left:only-one, QTabBar::tab:right:only-one {
|
|
215
223
|
margin-bottom: 0;
|
|
216
224
|
}
|
|
217
|
-
"""
|
|
225
|
+
"""
|
|
226
|
+
|
|
227
|
+
def init_label_styles(self):
|
|
228
|
+
|
|
229
|
+
self.block_title = '''
|
|
230
|
+
font-weight: bold;
|
|
231
|
+
padding: 0px;
|
|
232
|
+
'''
|
celldetective/gui/survival_ui.py
CHANGED
|
@@ -2,7 +2,7 @@ from PyQt5.QtWidgets import QMainWindow, QApplication, QMessageBox, QScrollArea,
|
|
|
2
2
|
from PyQt5.QtCore import Qt, QSize
|
|
3
3
|
from PyQt5.QtGui import QIcon, QDoubleValidator
|
|
4
4
|
from celldetective.gui.gui_utils import center_window, FeatureChoice, ListWidget, QHSeperationLine, FigureCanvas, GeometryChoice, OperationChoice
|
|
5
|
-
from superqt import QLabeledDoubleRangeSlider, QLabeledDoubleSlider,QLabeledSlider
|
|
5
|
+
from superqt import QLabeledDoubleRangeSlider, QLabeledDoubleSlider,QLabeledSlider, QColormapComboBox
|
|
6
6
|
from superqt.fonticon import icon
|
|
7
7
|
from fonticon_mdi6 import MDI6
|
|
8
8
|
from celldetective.utils import extract_experiment_channels, get_software_location, _extract_labels_from_config
|
|
@@ -26,40 +26,38 @@ from tqdm import tqdm
|
|
|
26
26
|
from lifelines import KaplanMeierFitter
|
|
27
27
|
import matplotlib.cm as mcm
|
|
28
28
|
import math
|
|
29
|
-
from celldetective.events import
|
|
29
|
+
from celldetective.events import switch_to_events
|
|
30
|
+
from celldetective.gui import Styles
|
|
30
31
|
|
|
31
|
-
class ConfigSurvival(QWidget):
|
|
32
|
+
class ConfigSurvival(QWidget, Styles):
|
|
32
33
|
|
|
33
34
|
"""
|
|
34
35
|
UI to set survival instructions.
|
|
35
36
|
|
|
36
37
|
"""
|
|
37
38
|
|
|
38
|
-
def __init__(self,
|
|
39
|
+
def __init__(self, parent_window=None):
|
|
39
40
|
|
|
40
41
|
super().__init__()
|
|
41
|
-
self.
|
|
42
|
+
self.parent_window = parent_window
|
|
42
43
|
self.setWindowTitle("Configure survival")
|
|
43
|
-
self.setWindowIcon(QIcon(os.sep.join(['celldetective','icons','
|
|
44
|
+
self.setWindowIcon(QIcon(os.sep.join(['celldetective','icons','logo.png'])))
|
|
44
45
|
|
|
45
|
-
self.exp_dir = self.
|
|
46
|
+
self.exp_dir = self.parent_window.exp_dir
|
|
46
47
|
self.soft_path = get_software_location()
|
|
47
48
|
self.exp_config = self.exp_dir +"config.ini"
|
|
48
|
-
self.wells = np.array(self.
|
|
49
|
+
self.wells = np.array(self.parent_window.parent_window.wells,dtype=str)
|
|
49
50
|
self.well_labels = _extract_labels_from_config(self.exp_config,len(self.wells))
|
|
50
|
-
self.FrameToMin = self.
|
|
51
|
+
self.FrameToMin = self.parent_window.parent_window.FrameToMin
|
|
51
52
|
self.float_validator = QDoubleValidator()
|
|
52
53
|
self.auto_close = False
|
|
53
54
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
self.well_option = self.parent.parent.well_list.currentIndex()
|
|
58
|
-
self.position_option = self.parent.parent.position_list.currentIndex()
|
|
55
|
+
self.well_option = self.parent_window.parent_window.well_list.currentIndex()
|
|
56
|
+
self.position_option = self.parent_window.parent_window.position_list.currentIndex()
|
|
59
57
|
self.interpret_pos_location()
|
|
60
58
|
#self.config_path = self.exp_dir + self.config_name
|
|
61
59
|
|
|
62
|
-
self.screen_height = self.
|
|
60
|
+
self.screen_height = self.parent_window.parent_window.parent_window.screen_height
|
|
63
61
|
center_window(self)
|
|
64
62
|
|
|
65
63
|
self.setMinimumWidth(350)
|
|
@@ -69,6 +67,7 @@ class ConfigSurvival(QWidget):
|
|
|
69
67
|
#self.load_previous_measurement_instructions()
|
|
70
68
|
if self.auto_close:
|
|
71
69
|
self.close()
|
|
70
|
+
self.setAttribute(Qt.WA_DeleteOnClose)
|
|
72
71
|
|
|
73
72
|
def interpret_pos_location(self):
|
|
74
73
|
|
|
@@ -109,9 +108,10 @@ class ConfigSurvival(QWidget):
|
|
|
109
108
|
main_layout.addWidget(panel_title, alignment=Qt.AlignCenter)
|
|
110
109
|
|
|
111
110
|
|
|
112
|
-
labels = [QLabel('population: '), QLabel('time of\
|
|
113
|
-
self.cb_options = [['targets','effectors'],['
|
|
111
|
+
labels = [QLabel('population: '), QLabel('time of\nreference: '), QLabel('time of\ninterest: '), QLabel('exclude\nclass: '), QLabel('cmap: ')] #QLabel('class: '),
|
|
112
|
+
self.cb_options = [['targets','effectors'], ['0','t_firstdetection'], ['t0'], ['--'], list(plt.colormaps())] #['class'],
|
|
114
113
|
self.cbs = [QComboBox() for i in range(len(labels))]
|
|
114
|
+
self.cbs[-1] = QColormapComboBox()
|
|
115
115
|
self.cbs[0].currentIndexChanged.connect(self.set_classes_and_times)
|
|
116
116
|
|
|
117
117
|
choice_layout = QVBoxLayout()
|
|
@@ -120,12 +120,15 @@ class ConfigSurvival(QWidget):
|
|
|
120
120
|
hbox = QHBoxLayout()
|
|
121
121
|
hbox.addWidget(labels[i], 33)
|
|
122
122
|
hbox.addWidget(self.cbs[i],66)
|
|
123
|
-
|
|
123
|
+
if i < len(labels)-1:
|
|
124
|
+
self.cbs[i].addItems(self.cb_options[i])
|
|
124
125
|
choice_layout.addLayout(hbox)
|
|
126
|
+
|
|
127
|
+
self.cbs[-1].addColormaps(self.cb_options[-1])
|
|
125
128
|
main_layout.addLayout(choice_layout)
|
|
126
129
|
|
|
127
|
-
self.cbs[0].setCurrentIndex(1)
|
|
128
130
|
self.cbs[0].setCurrentIndex(0)
|
|
131
|
+
self.cbs[1].setCurrentText('t_firstdetection')
|
|
129
132
|
|
|
130
133
|
time_calib_layout = QHBoxLayout()
|
|
131
134
|
time_calib_layout.setContentsMargins(20,20,20,20)
|
|
@@ -137,7 +140,7 @@ class ConfigSurvival(QWidget):
|
|
|
137
140
|
main_layout.addLayout(time_calib_layout)
|
|
138
141
|
|
|
139
142
|
self.submit_btn = QPushButton('Submit')
|
|
140
|
-
self.submit_btn.setStyleSheet(self.
|
|
143
|
+
self.submit_btn.setStyleSheet(self.button_style_sheet)
|
|
141
144
|
self.submit_btn.clicked.connect(self.process_survival)
|
|
142
145
|
main_layout.addWidget(self.submit_btn)
|
|
143
146
|
|
|
@@ -150,7 +153,7 @@ class ConfigSurvival(QWidget):
|
|
|
150
153
|
def set_classes_and_times(self):
|
|
151
154
|
|
|
152
155
|
# Look for all classes and times
|
|
153
|
-
tables = glob(self.exp_dir+os.sep.join(['W*','*','output','tables',f'trajectories_
|
|
156
|
+
tables = glob(self.exp_dir+os.sep.join(['W*','*','output','tables',f'trajectories_*.csv']))
|
|
154
157
|
self.all_columns = []
|
|
155
158
|
for tab in tables:
|
|
156
159
|
cols = pd.read_csv(tab, nrows=1,encoding_errors='ignore').columns.tolist()
|
|
@@ -158,6 +161,8 @@ class ConfigSurvival(QWidget):
|
|
|
158
161
|
self.all_columns = np.unique(self.all_columns)
|
|
159
162
|
#class_idx = np.array([s.startswith('class_') for s in self.all_columns])
|
|
160
163
|
time_idx = np.array([s.startswith('t_') for s in self.all_columns])
|
|
164
|
+
class_idx = np.array([s.startswith('class') for s in self.all_columns])
|
|
165
|
+
|
|
161
166
|
# class_columns = list(self.all_columns[class_idx])
|
|
162
167
|
# for c in ['class_id', 'class_color']:
|
|
163
168
|
# if c in class_columns:
|
|
@@ -170,12 +175,22 @@ class ConfigSurvival(QWidget):
|
|
|
170
175
|
self.auto_close = True
|
|
171
176
|
return None
|
|
172
177
|
|
|
173
|
-
|
|
174
|
-
|
|
178
|
+
try:
|
|
179
|
+
class_columns = list(self.all_columns[class_idx])
|
|
180
|
+
self.cbs[3].clear()
|
|
181
|
+
self.cbs[3].addItems(np.unique(self.cb_options[3]+class_columns))
|
|
182
|
+
except:
|
|
183
|
+
print('no column starts with class')
|
|
184
|
+
self.auto_close = True
|
|
185
|
+
return None
|
|
175
186
|
|
|
176
187
|
self.cbs[2].clear()
|
|
177
188
|
self.cbs[2].addItems(np.unique(self.cb_options[2]+time_columns))
|
|
178
189
|
|
|
190
|
+
self.cbs[1].clear()
|
|
191
|
+
self.cbs[1].addItems(np.unique(self.cb_options[1]+time_columns))
|
|
192
|
+
self.cbs[1].setCurrentText('t_firstdetection')
|
|
193
|
+
|
|
179
194
|
# self.cbs[3].clear()
|
|
180
195
|
# self.cbs[3].addItems(np.unique(self.cb_options[3]+class_columns))
|
|
181
196
|
|
|
@@ -186,7 +201,7 @@ class ConfigSurvival(QWidget):
|
|
|
186
201
|
self.FrameToMin = float(self.time_calibration_le.text().replace(',','.'))
|
|
187
202
|
print(self.FrameToMin, 'set')
|
|
188
203
|
|
|
189
|
-
self.time_of_interest = self.cbs[
|
|
204
|
+
self.time_of_interest = self.cbs[2].currentText()
|
|
190
205
|
if self.time_of_interest=="t0":
|
|
191
206
|
self.class_of_interest = "class"
|
|
192
207
|
else:
|
|
@@ -194,7 +209,14 @@ class ConfigSurvival(QWidget):
|
|
|
194
209
|
|
|
195
210
|
# read instructions from combobox options
|
|
196
211
|
self.load_available_tables_local()
|
|
212
|
+
|
|
197
213
|
if self.df is not None:
|
|
214
|
+
|
|
215
|
+
excluded_class = self.cbs[3].currentText()
|
|
216
|
+
if excluded_class!='--':
|
|
217
|
+
print(f"Excluding {excluded_class}...")
|
|
218
|
+
self.df = self.df.loc[~(self.df[excluded_class].isin([0,2])),:]
|
|
219
|
+
|
|
198
220
|
self.compute_survival_functions()
|
|
199
221
|
# prepare survival
|
|
200
222
|
|
|
@@ -216,7 +238,7 @@ class ConfigSurvival(QWidget):
|
|
|
216
238
|
|
|
217
239
|
self.legend_btn = QPushButton('')
|
|
218
240
|
self.legend_btn.setIcon(icon(MDI6.text_box,color="black"))
|
|
219
|
-
self.legend_btn.setStyleSheet(self.
|
|
241
|
+
self.legend_btn.setStyleSheet(self.button_select_all)
|
|
220
242
|
self.legend_btn.setToolTip('Show or hide the legend')
|
|
221
243
|
self.legend_visible = True
|
|
222
244
|
self.legend_btn.clicked.connect(self.show_hide_legend)
|
|
@@ -225,7 +247,7 @@ class ConfigSurvival(QWidget):
|
|
|
225
247
|
|
|
226
248
|
self.log_btn = QPushButton('')
|
|
227
249
|
self.log_btn.setIcon(icon(MDI6.math_log,color="black"))
|
|
228
|
-
self.log_btn.setStyleSheet(self.
|
|
250
|
+
self.log_btn.setStyleSheet(self.button_select_all)
|
|
229
251
|
self.log_btn.clicked.connect(self.switch_to_log)
|
|
230
252
|
self.log_btn.setToolTip('Enable or disable log scale')
|
|
231
253
|
plot_buttons_hbox.addWidget(self.log_btn, 5, alignment=Qt.AlignRight)
|
|
@@ -369,12 +391,12 @@ class ConfigSurvival(QWidget):
|
|
|
369
391
|
|
|
370
392
|
"""
|
|
371
393
|
|
|
372
|
-
self.well_option = self.
|
|
394
|
+
self.well_option = self.parent_window.parent_window.well_list.currentIndex()
|
|
373
395
|
if self.well_option==len(self.wells):
|
|
374
396
|
wo = '*'
|
|
375
397
|
else:
|
|
376
398
|
wo = self.well_option
|
|
377
|
-
self.position_option = self.
|
|
399
|
+
self.position_option = self.parent_window.parent_window.position_list.currentIndex()
|
|
378
400
|
if self.position_option==0:
|
|
379
401
|
po = '*'
|
|
380
402
|
else:
|
|
@@ -403,14 +425,14 @@ class ConfigSurvival(QWidget):
|
|
|
403
425
|
for block,movie_group in self.df.groupby(['well','position']):
|
|
404
426
|
try:
|
|
405
427
|
classes = movie_group.groupby('TRACK_ID')[self.class_of_interest].min().values
|
|
406
|
-
times = movie_group.groupby('TRACK_ID')[self.cbs[
|
|
428
|
+
times = movie_group.groupby('TRACK_ID')[self.cbs[2].currentText()].min().values
|
|
407
429
|
except Exception as e:
|
|
408
430
|
print(e)
|
|
409
431
|
continue
|
|
410
432
|
max_times = movie_group.groupby('TRACK_ID')['FRAME'].max().values
|
|
411
433
|
first_detections = None
|
|
412
434
|
|
|
413
|
-
if self.cbs[
|
|
435
|
+
if self.cbs[1].currentText()=='first detection':
|
|
414
436
|
left_censored = True
|
|
415
437
|
|
|
416
438
|
first_detections = []
|
|
@@ -427,17 +449,17 @@ class ConfigSurvival(QWidget):
|
|
|
427
449
|
else:
|
|
428
450
|
continue
|
|
429
451
|
|
|
430
|
-
elif self.cbs[
|
|
452
|
+
elif self.cbs[1].currentText().startswith('t'):
|
|
431
453
|
left_censored = True
|
|
432
|
-
first_detections = movie_group.groupby('TRACK_ID')[self.cbs[
|
|
454
|
+
first_detections = movie_group.groupby('TRACK_ID')[self.cbs[1].currentText()].max().values
|
|
433
455
|
print(first_detections)
|
|
434
456
|
|
|
435
457
|
|
|
436
|
-
if self.cbs[
|
|
458
|
+
if self.cbs[1].currentText()=='first detection' or self.cbs[1].currentText().startswith('t'):
|
|
437
459
|
left_censored = True
|
|
438
460
|
else:
|
|
439
461
|
left_censored = False
|
|
440
|
-
events, survival_times =
|
|
462
|
+
events, survival_times = switch_to_events(classes, times, max_times, first_detections, left_censored=left_censored, FrameToMin=self.FrameToMin)
|
|
441
463
|
ks = KaplanMeierFitter()
|
|
442
464
|
if len(events)>0:
|
|
443
465
|
ks.fit(survival_times, event_observed=events)
|
|
@@ -455,14 +477,14 @@ class ConfigSurvival(QWidget):
|
|
|
455
477
|
for block,movie_group in well_group.groupby('position'):
|
|
456
478
|
try:
|
|
457
479
|
classes = movie_group.groupby('TRACK_ID')[self.class_of_interest].min().values
|
|
458
|
-
times = movie_group.groupby('TRACK_ID')[self.cbs[
|
|
480
|
+
times = movie_group.groupby('TRACK_ID')[self.cbs[2].currentText()].min().values
|
|
459
481
|
except Exception as e:
|
|
460
482
|
print(e)
|
|
461
483
|
continue
|
|
462
484
|
max_times = movie_group.groupby('TRACK_ID')['FRAME'].max().values
|
|
463
485
|
first_detections = None
|
|
464
486
|
|
|
465
|
-
if self.cbs[
|
|
487
|
+
if self.cbs[1].currentText()=='first detection':
|
|
466
488
|
|
|
467
489
|
left_censored = True
|
|
468
490
|
first_detections = []
|
|
@@ -477,9 +499,9 @@ class ConfigSurvival(QWidget):
|
|
|
477
499
|
# think about assymmetry with class and times
|
|
478
500
|
continue
|
|
479
501
|
|
|
480
|
-
elif self.cbs[
|
|
502
|
+
elif self.cbs[1].currentText().startswith('t'):
|
|
481
503
|
left_censored = True
|
|
482
|
-
first_detections = movie_group.groupby('TRACK_ID')[self.cbs[
|
|
504
|
+
first_detections = movie_group.groupby('TRACK_ID')[self.cbs[1].currentText()].max().values
|
|
483
505
|
|
|
484
506
|
else:
|
|
485
507
|
pass
|
|
@@ -494,7 +516,7 @@ class ConfigSurvival(QWidget):
|
|
|
494
516
|
well_first_detections = None
|
|
495
517
|
|
|
496
518
|
print(f"{well_classes=}; {well_times=}")
|
|
497
|
-
events, survival_times =
|
|
519
|
+
events, survival_times = switch_to_events(well_classes, well_times, well_max_times, well_first_detections,left_censored=left_censored, FrameToMin=self.FrameToMin)
|
|
498
520
|
print(f"{events=}; {survival_times=}")
|
|
499
521
|
ks = KaplanMeierFitter()
|
|
500
522
|
if len(survival_times)>0:
|
celldetective/gui/tableUI.py
CHANGED
|
@@ -9,6 +9,8 @@ import numpy as np
|
|
|
9
9
|
import seaborn as sns
|
|
10
10
|
import matplotlib.cm as mcm
|
|
11
11
|
import os
|
|
12
|
+
from celldetective.gui import Styles
|
|
13
|
+
from superqt import QColormapComboBox
|
|
12
14
|
|
|
13
15
|
class PandasModel(QAbstractTableModel):
|
|
14
16
|
|
|
@@ -36,10 +38,10 @@ class PandasModel(QAbstractTableModel):
|
|
|
36
38
|
|
|
37
39
|
class QueryWidget(QWidget):
|
|
38
40
|
|
|
39
|
-
def __init__(self,
|
|
41
|
+
def __init__(self, parent_window):
|
|
40
42
|
|
|
41
43
|
super().__init__()
|
|
42
|
-
self.
|
|
44
|
+
self.parent_window = parent_window
|
|
43
45
|
self.setWindowTitle("Filter table")
|
|
44
46
|
# Create the QComboBox and add some items
|
|
45
47
|
center_window(self)
|
|
@@ -57,7 +59,7 @@ class QueryWidget(QWidget):
|
|
|
57
59
|
def filter_table(self):
|
|
58
60
|
try:
|
|
59
61
|
query_text = self.query_le.text().replace('class', '`class`')
|
|
60
|
-
tab = self.
|
|
62
|
+
tab = self.parent_window.data.query(query_text)
|
|
61
63
|
self.subtable = TableUI(tab, query_text, plot_mode="scatter")
|
|
62
64
|
self.subtable.show()
|
|
63
65
|
self.close()
|
|
@@ -67,10 +69,10 @@ class QueryWidget(QWidget):
|
|
|
67
69
|
|
|
68
70
|
class RenameColWidget(QWidget):
|
|
69
71
|
|
|
70
|
-
def __init__(self,
|
|
72
|
+
def __init__(self, parent_window, column=None):
|
|
71
73
|
|
|
72
74
|
super().__init__()
|
|
73
|
-
self.
|
|
75
|
+
self.parent_window = parent_window
|
|
74
76
|
self.column = column
|
|
75
77
|
if self.column is None:
|
|
76
78
|
self.column = ''
|
|
@@ -93,15 +95,15 @@ class RenameColWidget(QWidget):
|
|
|
93
95
|
|
|
94
96
|
old_name = self.column
|
|
95
97
|
new_name = self.new_col_name.text()
|
|
96
|
-
self.
|
|
98
|
+
self.parent_window.data = self.parent_window.data.rename(columns={old_name: new_name})
|
|
97
99
|
print(self.parent.data.columns)
|
|
98
100
|
|
|
99
|
-
self.
|
|
100
|
-
self.
|
|
101
|
+
self.parent_window.model = PandasModel(self.parent_window.data)
|
|
102
|
+
self.parent_window.table_view.setModel(self.parent_window.model)
|
|
101
103
|
self.close()
|
|
102
104
|
|
|
103
105
|
|
|
104
|
-
class TableUI(QMainWindow):
|
|
106
|
+
class TableUI(QMainWindow, Styles):
|
|
105
107
|
def __init__(self, data, title, population='targets',plot_mode="plot_track_signals", *args, **kwargs):
|
|
106
108
|
|
|
107
109
|
QMainWindow.__init__(self, *args, **kwargs)
|
|
@@ -280,6 +282,7 @@ class TableUI(QMainWindow):
|
|
|
280
282
|
layout.addLayout(hbox)
|
|
281
283
|
|
|
282
284
|
self.set_projection_btn = QPushButton('set')
|
|
285
|
+
self.set_projection_btn.setStyleSheet(self.button_style_sheet)
|
|
283
286
|
self.set_projection_btn.clicked.connect(self.set_proj_mode)
|
|
284
287
|
layout.addWidget(self.set_projection_btn)
|
|
285
288
|
|
|
@@ -313,24 +316,33 @@ class TableUI(QMainWindow):
|
|
|
313
316
|
layout.addWidget(self.box_check)
|
|
314
317
|
layout.addWidget(self.boxenplot_check)
|
|
315
318
|
|
|
319
|
+
self.x_cb = QComboBox()
|
|
320
|
+
self.x_cb.addItems(['--']+list(self.data.columns))
|
|
321
|
+
|
|
316
322
|
self.hue_cb = QComboBox()
|
|
317
323
|
self.hue_cb.addItems(list(self.data.columns))
|
|
318
324
|
idx = self.hue_cb.findText('well_index')
|
|
319
|
-
|
|
325
|
+
|
|
326
|
+
self.x_cb.findText('--')
|
|
327
|
+
hbox = QHBoxLayout()
|
|
328
|
+
hbox.addWidget(QLabel('x: '), 33)
|
|
329
|
+
hbox.addWidget(self.x_cb, 66)
|
|
330
|
+
layout.addLayout(hbox)
|
|
331
|
+
|
|
320
332
|
hbox = QHBoxLayout()
|
|
321
333
|
hbox.addWidget(QLabel('hue: '), 33)
|
|
322
334
|
hbox.addWidget(self.hue_cb, 66)
|
|
323
335
|
layout.addLayout(hbox)
|
|
324
336
|
|
|
325
|
-
|
|
326
|
-
self.cmap_cb
|
|
327
|
-
self.cmap_cb.addItems(list(plt.colormaps()))
|
|
337
|
+
self.cmap_cb = QColormapComboBox()
|
|
338
|
+
self.cmap_cb.addColormaps(list(plt.colormaps()))
|
|
328
339
|
hbox = QHBoxLayout()
|
|
329
340
|
hbox.addWidget(QLabel('colormap: '), 33)
|
|
330
341
|
hbox.addWidget(self.cmap_cb, 66)
|
|
331
342
|
layout.addLayout(hbox)
|
|
332
343
|
|
|
333
344
|
self.plot1d_btn = QPushButton('set')
|
|
345
|
+
self.plot1d_btn.setStyleSheet(self.button_style_sheet)
|
|
334
346
|
self.plot1d_btn.clicked.connect(self.plot1d)
|
|
335
347
|
layout.addWidget(self.plot1d_btn)
|
|
336
348
|
|
|
@@ -340,6 +352,11 @@ class TableUI(QMainWindow):
|
|
|
340
352
|
|
|
341
353
|
def plot1d(self):
|
|
342
354
|
|
|
355
|
+
self.x_option = False
|
|
356
|
+
if self.x_cb.currentText()!='--':
|
|
357
|
+
self.x_option = True
|
|
358
|
+
self.x = self.x_cb.currentText()
|
|
359
|
+
|
|
343
360
|
x = self.table_view.selectedIndexes()
|
|
344
361
|
col_idx = np.array([l.column() for l in x])
|
|
345
362
|
row_idx = np.array([l.row() for l in x])
|
|
@@ -371,24 +388,44 @@ class TableUI(QMainWindow):
|
|
|
371
388
|
legend = False
|
|
372
389
|
|
|
373
390
|
if self.swarm_check.isChecked():
|
|
374
|
-
|
|
375
|
-
|
|
391
|
+
if self.x_option:
|
|
392
|
+
sns.swarmplot(data=self.data, x=self.x,y=column_names[unique_cols],dodge=True, hue=hue_variable,legend=legend, ax=self.ax, palette=colors)
|
|
393
|
+
legend = False
|
|
394
|
+
else:
|
|
395
|
+
sns.swarmplot(data=self.data, y=column_names[unique_cols],dodge=True, hue=hue_variable,legend=legend, ax=self.ax, palette=colors)
|
|
396
|
+
legend = False
|
|
376
397
|
|
|
377
398
|
if self.violin_check.isChecked():
|
|
378
|
-
|
|
379
|
-
|
|
399
|
+
if self.x_option:
|
|
400
|
+
sns.stripplot(data=self.data,x=self.x, y=column_names[unique_cols],dodge=True, ax=self.ax, hue=hue_variable, legend=legend, palette=colors)
|
|
401
|
+
legend = False
|
|
402
|
+
else:
|
|
403
|
+
sns.violinplot(data=self.data, y=column_names[unique_cols],dodge=True, hue=hue_variable,legend=legend, ax=self.ax, palette=colors, cut=0)
|
|
404
|
+
legend = False
|
|
380
405
|
|
|
381
406
|
if self.box_check.isChecked():
|
|
382
|
-
|
|
383
|
-
|
|
407
|
+
if self.x_option:
|
|
408
|
+
sns.boxplot(data=self.data, x=self.x, y=column_names[unique_cols],dodge=True, hue=hue_variable,legend=legend, ax=self.ax, fill=False,palette=colors, linewidth=2,)
|
|
409
|
+
legend = False
|
|
410
|
+
else:
|
|
411
|
+
sns.boxplot(data=self.data, y=column_names[unique_cols],dodge=True, hue=hue_variable,legend=legend, ax=self.ax, fill=False,palette=colors, linewidth=2,)
|
|
412
|
+
legend = False
|
|
384
413
|
|
|
385
414
|
if self.boxenplot_check.isChecked():
|
|
386
|
-
|
|
387
|
-
|
|
415
|
+
if self.x_option:
|
|
416
|
+
sns.boxenplot(data=self.data, x = self.x, y=column_names[unique_cols],dodge=True, hue=hue_variable,legend=legend, ax=self.ax, fill=False,palette=colors, linewidth=2,)
|
|
417
|
+
legend = False
|
|
418
|
+
else:
|
|
419
|
+
sns.boxenplot(data=self.data, y=column_names[unique_cols],dodge=True, hue=hue_variable,legend=legend, ax=self.ax, fill=False,palette=colors, linewidth=2,)
|
|
420
|
+
legend = False
|
|
388
421
|
|
|
389
422
|
if self.strip_check.isChecked():
|
|
390
|
-
|
|
391
|
-
|
|
423
|
+
if self.x_option:
|
|
424
|
+
sns.stripplot(data=self.data, x = self.x, y=column_names[unique_cols],dodge=True, ax=self.ax, hue=hue_variable, legend=legend, palette=colors)
|
|
425
|
+
legend = False
|
|
426
|
+
else:
|
|
427
|
+
sns.stripplot(data=self.data, y=column_names[unique_cols],dodge=True, ax=self.ax, hue=hue_variable, legend=legend, palette=colors)
|
|
428
|
+
legend = False
|
|
392
429
|
|
|
393
430
|
plt.tight_layout()
|
|
394
431
|
self.fig.set_facecolor('none') # or 'None'
|