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
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
Copright © 2023 Laboratoire Adhesion et Inflammation, Authored by Remy Torro.
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
-
from PyQt5.QtWidgets import
|
|
5
|
+
from PyQt5.QtWidgets import QComboBox, QLabel, QRadioButton, QLineEdit, QApplication, QPushButton, QScrollArea, QVBoxLayout, QHBoxLayout
|
|
6
6
|
from PyQt5.QtCore import Qt, QSize
|
|
7
7
|
from celldetective.gui.gui_utils import center_window, QHSeperationLine
|
|
8
8
|
from superqt import QLabeledDoubleSlider, QLabeledSlider
|
|
@@ -12,9 +12,9 @@ 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
|
|
15
|
+
from celldetective.gui import CelldetectiveWidget, CelldetectiveMainWindow
|
|
16
16
|
|
|
17
|
-
class ConfigSignalAnnotator(
|
|
17
|
+
class ConfigSignalAnnotator(CelldetectiveMainWindow):
|
|
18
18
|
|
|
19
19
|
"""
|
|
20
20
|
UI to set normalization and animation parameters for the annotator tool.
|
|
@@ -30,11 +30,8 @@ class ConfigSignalAnnotator(QMainWindow, Styles):
|
|
|
30
30
|
self.exp_dir = self.parent_window.exp_dir
|
|
31
31
|
self.soft_path = get_software_location()
|
|
32
32
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
elif self.mode=="effectors":
|
|
36
|
-
self.instructions_path = self.parent_window.exp_dir + "configs/signal_annotator_config_effectors.json"
|
|
37
|
-
elif self.mode == "pairs":
|
|
33
|
+
self.instructions_path = self.parent_window.exp_dir + f"configs/signal_annotator_config_{self.mode}.json"
|
|
34
|
+
if self.mode == "pairs":
|
|
38
35
|
self.instructions_path = self.parent_window.exp_dir + "configs/signal_annotator_config_neighborhood.json"
|
|
39
36
|
|
|
40
37
|
exp_config = self.exp_dir +"config.ini"
|
|
@@ -61,7 +58,7 @@ class ConfigSignalAnnotator(QMainWindow, Styles):
|
|
|
61
58
|
"""
|
|
62
59
|
|
|
63
60
|
self.scroll_area = QScrollArea(self)
|
|
64
|
-
self.button_widget =
|
|
61
|
+
self.button_widget = CelldetectiveWidget()
|
|
65
62
|
|
|
66
63
|
self.main_layout = QVBoxLayout()
|
|
67
64
|
self.main_layout.setContentsMargins(30,30,30,30)
|
|
@@ -151,7 +148,7 @@ class ConfigSignalAnnotator(QMainWindow, Styles):
|
|
|
151
148
|
self.fraction_slider.setSingleStep(0.05)
|
|
152
149
|
self.fraction_slider.setTickInterval(0.05)
|
|
153
150
|
self.fraction_slider.setSingleStep(1)
|
|
154
|
-
self.fraction_slider.setOrientation(
|
|
151
|
+
self.fraction_slider.setOrientation(Qt.Horizontal)
|
|
155
152
|
self.fraction_slider.setRange(0.1,1)
|
|
156
153
|
self.fraction_slider.setValue(0.25)
|
|
157
154
|
|
|
@@ -166,7 +163,7 @@ class ConfigSignalAnnotator(QMainWindow, Styles):
|
|
|
166
163
|
self.interval_slider.setSingleStep(1)
|
|
167
164
|
self.interval_slider.setTickInterval(1)
|
|
168
165
|
self.interval_slider.setSingleStep(1)
|
|
169
|
-
self.interval_slider.setOrientation(
|
|
166
|
+
self.interval_slider.setOrientation(Qt.Horizontal)
|
|
170
167
|
self.interval_slider.setRange(1,1000)
|
|
171
168
|
self.interval_slider.setValue(1)
|
|
172
169
|
hbox_interval.addWidget(self.interval_slider, 80)
|
celldetective/gui/survival_ui.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
from PyQt5.QtWidgets import QMessageBox, QComboBox, QLineEdit, QVBoxLayout,
|
|
1
|
+
from PyQt5.QtWidgets import QMessageBox, QComboBox, QLineEdit, QVBoxLayout, QLabel, QHBoxLayout, QPushButton
|
|
2
2
|
from PyQt5.QtCore import Qt
|
|
3
3
|
from PyQt5.QtGui import QDoubleValidator
|
|
4
|
-
from celldetective.gui.gui_utils import center_window
|
|
4
|
+
from celldetective.gui.gui_utils import center_window, generic_message
|
|
5
5
|
from superqt import QColormapComboBox
|
|
6
6
|
from celldetective.gui.generic_signal_plot import SurvivalPlotWidget
|
|
7
7
|
from celldetective.utils import get_software_location, _extract_labels_from_config, extract_cols_from_table_list
|
|
@@ -11,14 +11,14 @@ import os
|
|
|
11
11
|
import matplotlib.pyplot as plt
|
|
12
12
|
plt.rcParams['svg.fonttype'] = 'none'
|
|
13
13
|
from glob import glob
|
|
14
|
-
from celldetective.gui import Styles
|
|
14
|
+
from celldetective.gui import Styles, CelldetectiveWidget
|
|
15
15
|
from matplotlib import colormaps
|
|
16
16
|
from celldetective.events import compute_survival
|
|
17
17
|
from celldetective.relative_measurements import expand_pair_table
|
|
18
18
|
import matplotlib.cm
|
|
19
19
|
from celldetective.neighborhood import extract_neighborhood_in_pair_table
|
|
20
20
|
|
|
21
|
-
class ConfigSurvival(
|
|
21
|
+
class ConfigSurvival(CelldetectiveWidget):
|
|
22
22
|
|
|
23
23
|
"""
|
|
24
24
|
UI to set survival instructions.
|
|
@@ -30,7 +30,6 @@ class ConfigSurvival(QWidget, Styles):
|
|
|
30
30
|
super().__init__()
|
|
31
31
|
self.parent_window = parent_window
|
|
32
32
|
self.setWindowTitle("Configure survival")
|
|
33
|
-
self.setWindowIcon(self.celldetective_icon)
|
|
34
33
|
|
|
35
34
|
self.exp_dir = self.parent_window.exp_dir
|
|
36
35
|
self.soft_path = get_software_location()
|
|
@@ -53,8 +52,6 @@ class ConfigSurvival(QWidget, Styles):
|
|
|
53
52
|
self.populate_widget()
|
|
54
53
|
if self.auto_close:
|
|
55
54
|
self.close()
|
|
56
|
-
|
|
57
|
-
self.setAttribute(Qt.WA_DeleteOnClose)
|
|
58
55
|
|
|
59
56
|
def interpret_pos_location(self):
|
|
60
57
|
|
|
@@ -91,51 +88,27 @@ class ConfigSurvival(QWidget, Styles):
|
|
|
91
88
|
|
|
92
89
|
|
|
93
90
|
pops = []
|
|
94
|
-
|
|
91
|
+
self.cols_per_pop = {}
|
|
92
|
+
for population in self.parent_window.parent_window.populations:
|
|
95
93
|
tables = glob(self.exp_dir+os.sep.join(['W*','*','output','tables',f'trajectories_{population}.csv']))
|
|
96
94
|
if len(tables)>0:
|
|
97
95
|
pops.append(population)
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
pops.append('effectors-effectors')
|
|
111
|
-
elif 'pairs' in pops and not 'effectors' in pops:
|
|
112
|
-
# must be target-target
|
|
113
|
-
target_neighs = [c for c in self.cols_targets if c.startswith('inclusive_count_neighborhood')]
|
|
114
|
-
if len(target_neighs)>0:
|
|
115
|
-
pops.pop(pops.index('pairs'))
|
|
116
|
-
pops.append('targets-targets')
|
|
117
|
-
elif 'pairs' in pops:
|
|
118
|
-
# either effector-target or target-effector
|
|
119
|
-
target_neighs_cross = [c for c in self.cols_targets if c.startswith('inclusive_count_neighborhood') and '_2_' in c]
|
|
120
|
-
if len(target_neighs_cross)>0:
|
|
121
|
-
pops.append('targets-effectors')
|
|
122
|
-
effector_neighs_cross = [c for c in self.cols_effectors if c.startswith('inclusive_count_neighborhood') and '_2_' in c]
|
|
123
|
-
if len(effector_neighs_cross)>0:
|
|
124
|
-
pops.append('effectors-targets')
|
|
125
|
-
target_neighs = [c for c in self.cols_targets if c.startswith('inclusive_count_neighborhood') and 'self' in c]
|
|
126
|
-
if len(target_neighs)>0:
|
|
127
|
-
pops.append('targets-targets')
|
|
128
|
-
effector_neighs = [c for c in self.cols_effectors if c.startswith('inclusive_count_neighborhood') and 'self' in c]
|
|
129
|
-
if len(effector_neighs)>0:
|
|
130
|
-
pops.append('effectors-effectors')
|
|
131
|
-
pops.pop(pops.index('pairs'))
|
|
132
|
-
else:
|
|
133
|
-
pass
|
|
134
|
-
|
|
96
|
+
cols = extract_cols_from_table_list(tables)
|
|
97
|
+
|
|
98
|
+
# check for neighbor pairs
|
|
99
|
+
neigh_cols = [c for c in cols if c.startswith('inclusive_count_neighborhood')]
|
|
100
|
+
neigh_pairs = [c.split('_(')[-1].split(')_')[0].split('-') for c in neigh_cols]
|
|
101
|
+
neigh_pairs = ['-'.join(c) for c in neigh_pairs]
|
|
102
|
+
for k in range(len(neigh_pairs)):
|
|
103
|
+
if "_self_" in neigh_pairs[k]:
|
|
104
|
+
neigh_pairs[k] = '-'.join([population, population])
|
|
105
|
+
pops.extend(neigh_pairs)
|
|
106
|
+
|
|
107
|
+
self.cols_per_pop.update({population: cols})
|
|
135
108
|
|
|
136
109
|
labels = [QLabel('population: '), QLabel('time of\nreference: '), QLabel('time of\ninterest: '), QLabel('cmap: ')] #QLabel('class: '),
|
|
137
110
|
self.cb_options = [pops, ['0'], [], []] #['class'],
|
|
138
|
-
self.cbs = [QComboBox() for
|
|
111
|
+
self.cbs = [QComboBox() for _ in range(len(labels))]
|
|
139
112
|
|
|
140
113
|
self.cbs[-1] = QColormapComboBox()
|
|
141
114
|
self.cbs[0].currentIndexChanged.connect(self.set_classes_and_times)
|
|
@@ -155,12 +128,8 @@ class ConfigSurvival(QWidget, Styles):
|
|
|
155
128
|
if hasattr(matplotlib.cm, str(cm).lower()):
|
|
156
129
|
try:
|
|
157
130
|
self.cbs[-1].addColormap(cm.lower())
|
|
158
|
-
except:
|
|
131
|
+
except Exception as _:
|
|
159
132
|
pass
|
|
160
|
-
#try:
|
|
161
|
-
# self.cbs[-1].addColormap(cm)
|
|
162
|
-
# except:
|
|
163
|
-
# pass
|
|
164
133
|
|
|
165
134
|
main_layout.addLayout(choice_layout)
|
|
166
135
|
|
|
@@ -213,18 +182,16 @@ class ConfigSurvival(QWidget, Styles):
|
|
|
213
182
|
|
|
214
183
|
self.population = 'pairs'
|
|
215
184
|
tables_pairs = glob(self.exp_dir+os.sep.join(['W*','*','output','tables',f'trajectories_pairs.csv']))
|
|
185
|
+
if not tables_pairs:
|
|
186
|
+
print('No pair table found... please compute the pair measurements...')
|
|
187
|
+
return None
|
|
216
188
|
self.cols_pairs = extract_cols_from_table_list(tables_pairs)
|
|
217
189
|
|
|
218
190
|
self.population_reference = pop_split[0]
|
|
219
191
|
self.population_neigh = pop_split[1]
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
cols_ref = self.cols_effectors
|
|
224
|
-
if self.population_neigh=='targets':
|
|
225
|
-
cols_neigh = self.cols_targets
|
|
226
|
-
else:
|
|
227
|
-
cols_neigh = self.cols_effectors
|
|
192
|
+
|
|
193
|
+
cols_ref = self.cols_per_pop[self.population_reference]
|
|
194
|
+
cols_neigh = self.cols_per_pop[self.population_neigh]
|
|
228
195
|
|
|
229
196
|
time_cols_ref = np.array([s.startswith('t_') or s=='t0' for s in cols_ref])
|
|
230
197
|
if len(time_cols_ref)>0:
|
|
@@ -237,9 +204,11 @@ class ConfigSurvival(QWidget, Styles):
|
|
|
237
204
|
time_cols_neigh = ['neighbor_'+t for t in time_cols_neigh]
|
|
238
205
|
|
|
239
206
|
if self.population_reference!=self.population_neigh:
|
|
240
|
-
self.neighborhood_keys = [c[16:] for c in cols_ref if c.startswith('inclusive_count_neighborhood') and
|
|
207
|
+
self.neighborhood_keys = [c[16:] for c in cols_ref if c.startswith('inclusive_count_neighborhood') and str(self.population_neigh) in c]
|
|
241
208
|
else:
|
|
242
|
-
self.neighborhood_keys = [c[16:] for c in cols_ref if c.startswith('inclusive_count_neighborhood') and
|
|
209
|
+
self.neighborhood_keys = [c[16:] for c in cols_ref if c.startswith('inclusive_count_neighborhood') and str(self.population_neigh) not in c]
|
|
210
|
+
|
|
211
|
+
print(f"{self.neighborhood_keys=}")
|
|
243
212
|
|
|
244
213
|
time_idx = np.array([s.startswith('t_') or s.startswith('t0') for s in self.cols_pairs])
|
|
245
214
|
time_cols_pairs = list(self.cols_pairs[time_idx])
|
|
@@ -247,10 +216,7 @@ class ConfigSurvival(QWidget, Styles):
|
|
|
247
216
|
time_columns = time_cols_ref + time_cols_neigh + time_cols_pairs
|
|
248
217
|
|
|
249
218
|
else:
|
|
250
|
-
|
|
251
|
-
self.all_columns = self.cols_targets
|
|
252
|
-
else:
|
|
253
|
-
self.all_columns = self.cols_effectors
|
|
219
|
+
self.all_columns = self.cols_per_pop[self.population]
|
|
254
220
|
time_idx = np.array([s.startswith('t_') or s=='t0' for s in self.all_columns])
|
|
255
221
|
|
|
256
222
|
try:
|
|
@@ -274,6 +240,8 @@ class ConfigSurvival(QWidget, Styles):
|
|
|
274
240
|
self.time_of_interest = self.cbs[2].currentText()
|
|
275
241
|
if self.time_of_interest=="t0":
|
|
276
242
|
self.class_of_interest = "class"
|
|
243
|
+
elif self.time_of_interest.startswith('t0'):
|
|
244
|
+
self.class_of_interest = self.time_of_interest.replace('t0_','class_')
|
|
277
245
|
else:
|
|
278
246
|
self.class_of_interest = self.time_of_interest.replace('t_','class_')
|
|
279
247
|
|
|
@@ -290,29 +258,19 @@ class ConfigSurvival(QWidget, Styles):
|
|
|
290
258
|
print(e, ' The query is misunderstood and will not be applied...')
|
|
291
259
|
|
|
292
260
|
self.interpret_pos_location()
|
|
261
|
+
|
|
293
262
|
if self.class_of_interest in list(self.df.columns) and self.cbs[2].currentText() in list(self.df.columns):
|
|
294
263
|
self.compute_survival_functions()
|
|
295
264
|
else:
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
msgBox.setWindowTitle("Warning")
|
|
300
|
-
msgBox.setStandardButtons(QMessageBox.Ok)
|
|
301
|
-
returnValue = msgBox.exec()
|
|
302
|
-
if returnValue == QMessageBox.Ok:
|
|
303
|
-
return None
|
|
265
|
+
generic_message("The class and/or event time of interest is not found in the dataframe...")
|
|
266
|
+
return None
|
|
267
|
+
|
|
304
268
|
if 'survival_fit' in list(self.df_pos_info.columns):
|
|
305
269
|
self.plot_window = SurvivalPlotWidget(parent_window=self, df=self.df, df_pos_info = self.df_pos_info, df_well_info = self.df_well_info, title='plot survivals')
|
|
306
270
|
self.plot_window.show()
|
|
307
271
|
else:
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
msgBox.setText("No survival function was successfully computed...\nCheck your parameter choice.")
|
|
311
|
-
msgBox.setWindowTitle("Warning")
|
|
312
|
-
msgBox.setStandardButtons(QMessageBox.Ok)
|
|
313
|
-
returnValue = msgBox.exec()
|
|
314
|
-
if returnValue == QMessageBox.Ok:
|
|
315
|
-
return None
|
|
272
|
+
generic_message("No survival function was successfully computed...\nCheck your parameter choice.")
|
|
273
|
+
return None
|
|
316
274
|
|
|
317
275
|
def load_available_tables_local(self):
|
|
318
276
|
|
|
@@ -327,32 +285,26 @@ class ConfigSurvival(QWidget, Styles):
|
|
|
327
285
|
self.df, self.df_pos_info = load_experiment_tables(self.exp_dir, well_option=self.well_option, position_option=self.position_option, population=self.population, return_pos_info=True)
|
|
328
286
|
|
|
329
287
|
if self.df is None:
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
msgBox.setText("No table could be found.. Abort.")
|
|
333
|
-
msgBox.setWindowTitle("Warning")
|
|
334
|
-
msgBox.setStandardButtons(QMessageBox.Ok)
|
|
335
|
-
returnValue = msgBox.exec()
|
|
336
|
-
if returnValue == QMessageBox.Ok:
|
|
337
|
-
return None
|
|
288
|
+
generic_message("No table could be found.. Abort.")
|
|
289
|
+
return None
|
|
338
290
|
else:
|
|
339
291
|
self.df_well_info = self.df_pos_info.loc[:,['well_path', 'well_index', 'well_name', 'well_number', 'well_alias']].drop_duplicates()
|
|
340
|
-
#print(f"{self.df_well_info=}")
|
|
341
292
|
|
|
342
293
|
if self.population=='pairs':
|
|
343
294
|
self.df = expand_pair_table(self.df)
|
|
344
295
|
self.df = extract_neighborhood_in_pair_table(self.df, reference_population=self.population_reference, neighbor_population=self.population_neigh, neighborhood_key=self.neighborhood_keys[0], contact_only=True)
|
|
345
296
|
|
|
346
|
-
|
|
347
297
|
def compute_survival_functions(self):
|
|
348
298
|
|
|
349
299
|
cut_observation_time = None
|
|
350
300
|
try:
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
301
|
+
if self.query_time_cut.text()!='':
|
|
302
|
+
cut_observation_time = float(self.query_time_cut.text().replace(',','.')) / self.FrameToMin
|
|
303
|
+
if not 0<cut_observation_time<=(self.df['FRAME'].max()):
|
|
304
|
+
print('Invalid cut time (larger than movie length)... Not applied.')
|
|
305
|
+
cut_observation_time = None
|
|
355
306
|
except Exception as e:
|
|
307
|
+
print(f"{e=}")
|
|
356
308
|
pass
|
|
357
309
|
|
|
358
310
|
pairs = False
|
|
@@ -361,7 +313,9 @@ class ConfigSurvival(QWidget, Styles):
|
|
|
361
313
|
|
|
362
314
|
# Per position survival
|
|
363
315
|
for block,movie_group in self.df.groupby(['well','position']):
|
|
316
|
+
print(f"{block=}")
|
|
364
317
|
ks = compute_survival(movie_group, self.class_of_interest, self.cbs[2].currentText(), t_reference=self.cbs[1].currentText(), FrameToMin=self.FrameToMin, cut_observation_time=cut_observation_time, pairs=pairs)
|
|
318
|
+
print(f"{ks=}")
|
|
365
319
|
if ks is not None:
|
|
366
320
|
self.df_pos_info.loc[self.df_pos_info['pos_path']==block[1],'survival_fit'] = ks
|
|
367
321
|
|
celldetective/gui/tableUI.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from PyQt5.QtWidgets import QRadioButton, QButtonGroup,
|
|
1
|
+
from PyQt5.QtWidgets import QRadioButton, QButtonGroup, QTableView, QAction, QMenu,QFileDialog, QLineEdit, QHBoxLayout, QPushButton, QVBoxLayout, QComboBox, QLabel, QCheckBox, QMessageBox
|
|
2
2
|
from PyQt5.QtCore import Qt
|
|
3
3
|
from PyQt5.QtGui import QBrush, QColor, QDoubleValidator
|
|
4
4
|
import pandas as pd
|
|
@@ -12,7 +12,7 @@ import numpy as np
|
|
|
12
12
|
import seaborn as sns
|
|
13
13
|
import matplotlib.cm as mcm
|
|
14
14
|
import os
|
|
15
|
-
from celldetective.gui import
|
|
15
|
+
from celldetective.gui import CelldetectiveWidget, CelldetectiveMainWindow
|
|
16
16
|
from superqt import QColormapComboBox, QLabeledSlider, QSearchableComboBox
|
|
17
17
|
from superqt.fonticon import icon
|
|
18
18
|
from fonticon_mdi6 import MDI6
|
|
@@ -22,12 +22,13 @@ from matplotlib import colormaps
|
|
|
22
22
|
import matplotlib.cm
|
|
23
23
|
|
|
24
24
|
|
|
25
|
-
class QueryWidget(
|
|
25
|
+
class QueryWidget(CelldetectiveWidget):
|
|
26
26
|
|
|
27
27
|
def __init__(self, parent_window):
|
|
28
28
|
|
|
29
29
|
super().__init__()
|
|
30
30
|
self.parent_window = parent_window
|
|
31
|
+
|
|
31
32
|
self.setWindowTitle("Filter table")
|
|
32
33
|
# Create the QComboBox and add some items
|
|
33
34
|
|
|
@@ -39,7 +40,6 @@ class QueryWidget(QWidget):
|
|
|
39
40
|
self.submit_btn = QPushButton('submit')
|
|
40
41
|
self.submit_btn.clicked.connect(self.filter_table)
|
|
41
42
|
layout.addWidget(self.submit_btn, 30)
|
|
42
|
-
self.setAttribute(Qt.WA_DeleteOnClose)
|
|
43
43
|
center_window(self)
|
|
44
44
|
|
|
45
45
|
def filter_table(self):
|
|
@@ -54,7 +54,7 @@ class QueryWidget(QWidget):
|
|
|
54
54
|
return None
|
|
55
55
|
|
|
56
56
|
|
|
57
|
-
class MergeOneHotWidget(
|
|
57
|
+
class MergeOneHotWidget(CelldetectiveWidget):
|
|
58
58
|
|
|
59
59
|
def __init__(self, parent_window, selected_columns=None):
|
|
60
60
|
|
|
@@ -139,7 +139,7 @@ class MergeOneHotWidget(QWidget, Styles):
|
|
|
139
139
|
self.submit_btn.setEnabled(True)
|
|
140
140
|
|
|
141
141
|
|
|
142
|
-
class DifferentiateColWidget(
|
|
142
|
+
class DifferentiateColWidget(CelldetectiveWidget):
|
|
143
143
|
|
|
144
144
|
def __init__(self, parent_window, column=None):
|
|
145
145
|
|
|
@@ -217,7 +217,7 @@ class DifferentiateColWidget(QWidget, Styles):
|
|
|
217
217
|
|
|
218
218
|
|
|
219
219
|
|
|
220
|
-
class OperationOnColsWidget(
|
|
220
|
+
class OperationOnColsWidget(CelldetectiveWidget):
|
|
221
221
|
|
|
222
222
|
def __init__(self, parent_window, column1=None, column2=None, operation='divide'):
|
|
223
223
|
|
|
@@ -394,7 +394,7 @@ class LogColWidget(GenericOpColWidget):
|
|
|
394
394
|
self.parent_window.data['log10('+self.measurements_cb.currentText()+')'] = safe_log(self.parent_window.data[self.measurements_cb.currentText()].values)
|
|
395
395
|
|
|
396
396
|
|
|
397
|
-
class RenameColWidget(
|
|
397
|
+
class RenameColWidget(CelldetectiveWidget):
|
|
398
398
|
|
|
399
399
|
def __init__(self, parent_window, column=None):
|
|
400
400
|
|
|
@@ -429,11 +429,11 @@ class RenameColWidget(QWidget):
|
|
|
429
429
|
self.parent_window.table_view.setModel(self.parent_window.model)
|
|
430
430
|
self.close()
|
|
431
431
|
|
|
432
|
-
class PivotTableUI(
|
|
432
|
+
class PivotTableUI(CelldetectiveWidget):
|
|
433
433
|
|
|
434
434
|
def __init__(self, data, title="", mode=None, *args, **kwargs):
|
|
435
435
|
|
|
436
|
-
|
|
436
|
+
CelldetectiveWidget.__init__(self, *args, **kwargs)
|
|
437
437
|
|
|
438
438
|
self.data = data
|
|
439
439
|
self.title = title
|
|
@@ -535,11 +535,11 @@ class PivotTableUI(QWidget):
|
|
|
535
535
|
"""
|
|
536
536
|
self.information_label.setText(html_caption)
|
|
537
537
|
|
|
538
|
-
class TableUI(
|
|
538
|
+
class TableUI(CelldetectiveMainWindow):
|
|
539
539
|
|
|
540
540
|
def __init__(self, data, title, population='targets',plot_mode="plot_track_signals", save_inplace_option=False, collapse_tracks_option=True, *args, **kwargs):
|
|
541
541
|
|
|
542
|
-
|
|
542
|
+
CelldetectiveMainWindow.__init__(self, *args, **kwargs)
|
|
543
543
|
|
|
544
544
|
self.setWindowTitle(title)
|
|
545
545
|
self.setGeometry(100,100,1000,400)
|
|
@@ -574,7 +574,6 @@ class TableUI(QMainWindow, Styles):
|
|
|
574
574
|
self.model = PandasModel(data)
|
|
575
575
|
self.table_view.setModel(self.model)
|
|
576
576
|
self.table_view.resizeColumnsToContents()
|
|
577
|
-
self.setAttribute(Qt.WA_DeleteOnClose)
|
|
578
577
|
|
|
579
578
|
def resizeEvent(self, event):
|
|
580
579
|
|
|
@@ -696,7 +695,7 @@ class TableUI(QMainWindow, Styles):
|
|
|
696
695
|
|
|
697
696
|
def collapse_pairs_in_neigh(self):
|
|
698
697
|
|
|
699
|
-
self.selectNeighWidget =
|
|
698
|
+
self.selectNeighWidget = CelldetectiveWidget()
|
|
700
699
|
self.selectNeighWidget.setMinimumWidth(480)
|
|
701
700
|
self.selectNeighWidget.setWindowTitle('Set neighborhood of interest')
|
|
702
701
|
|
|
@@ -757,14 +756,20 @@ class TableUI(QMainWindow, Styles):
|
|
|
757
756
|
ref_pop = self.reference_pop_cb.currentText()
|
|
758
757
|
neighborhood = self.neigh_cb.currentText()
|
|
759
758
|
status_neigh = 'status_'+neighborhood
|
|
759
|
+
|
|
760
760
|
if 'self' in neighborhood:
|
|
761
761
|
neighbor_pop = ref_pop
|
|
762
|
-
elif ref_pop=='targets':
|
|
763
|
-
neighbor_pop = 'effectors'
|
|
764
|
-
elif ref_pop=='effectors':
|
|
765
|
-
neighbor_pop = "targets"
|
|
766
762
|
|
|
767
|
-
|
|
763
|
+
neigh_col = neighborhood.replace('status_','')
|
|
764
|
+
if '_(' in neigh_col and ')_' in neigh_col:
|
|
765
|
+
neighbor_pop = neigh_col.split('_(')[-1].split(')_')[0].split('-')[-1]
|
|
766
|
+
else:
|
|
767
|
+
if ref_pop=='targets':
|
|
768
|
+
neighbor_pop = 'effectors'
|
|
769
|
+
if ref_pop=='effectors':
|
|
770
|
+
neighbor_pop = "targets"
|
|
771
|
+
|
|
772
|
+
data = extract_neighborhood_in_pair_table(self.data, neighborhood_key=neighborhood, contact_only=self.contact_only_check.isChecked(), reference_population=ref_pop)
|
|
768
773
|
|
|
769
774
|
if self.groupby_pair_rb.isChecked():
|
|
770
775
|
self.groupby_cols = ['position', 'REFERENCE_ID', 'NEIGHBOR_ID']
|
|
@@ -774,6 +779,7 @@ class TableUI(QMainWindow, Styles):
|
|
|
774
779
|
self.current_data = data
|
|
775
780
|
skip_projection = False
|
|
776
781
|
if 'reference_tracked' in list(self.current_data.columns):
|
|
782
|
+
print(f"{self.current_data['reference_tracked']=} {(self.current_data['reference_tracked']==False)=} {np.all(self.current_data['reference_tracked']==False)=}")
|
|
777
783
|
if np.all(self.current_data['reference_tracked'].astype(bool)==False):
|
|
778
784
|
# reference not tracked
|
|
779
785
|
if self.groupby_reference_rb.isChecked():
|
|
@@ -1030,14 +1036,11 @@ class TableUI(QMainWindow, Styles):
|
|
|
1030
1036
|
|
|
1031
1037
|
x = self.table_view.selectedIndexes()
|
|
1032
1038
|
col_idx = np.unique(np.array([l.column() for l in x]))
|
|
1039
|
+
selected_cols = None
|
|
1033
1040
|
if isinstance(col_idx, (list, np.ndarray)):
|
|
1034
1041
|
cols = np.array(list(self.data.columns))
|
|
1035
1042
|
if len(col_idx)>0:
|
|
1036
1043
|
selected_col = str(cols[col_idx[0]])
|
|
1037
|
-
else:
|
|
1038
|
-
selected_col = None
|
|
1039
|
-
else:
|
|
1040
|
-
selected_col = None
|
|
1041
1044
|
|
|
1042
1045
|
self.mergewidget = MergeOneHotWidget(self, selected_columns=selected_cols)
|
|
1043
1046
|
self.mergewidget.show()
|
|
@@ -1091,7 +1094,7 @@ class TableUI(QMainWindow, Styles):
|
|
|
1091
1094
|
|
|
1092
1095
|
self.current_data = self.data
|
|
1093
1096
|
|
|
1094
|
-
self.projectionWidget =
|
|
1097
|
+
self.projectionWidget = CelldetectiveWidget()
|
|
1095
1098
|
self.projectionWidget.setMinimumWidth(500)
|
|
1096
1099
|
self.projectionWidget.setWindowTitle('Set projection mode')
|
|
1097
1100
|
|
|
@@ -1191,7 +1194,7 @@ class TableUI(QMainWindow, Styles):
|
|
|
1191
1194
|
|
|
1192
1195
|
def set_1D_plot_params(self):
|
|
1193
1196
|
|
|
1194
|
-
self.plot1Dparams =
|
|
1197
|
+
self.plot1Dparams = CelldetectiveWidget()
|
|
1195
1198
|
self.plot1Dparams.setWindowTitle('Set 1D plot parameters')
|
|
1196
1199
|
|
|
1197
1200
|
layout = QVBoxLayout()
|