celldetective 1.3.3.post1__py3-none-any.whl → 1.3.4__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 +30 -4
- celldetective/_version.py +1 -1
- celldetective/extra_properties.py +21 -0
- celldetective/filters.py +15 -2
- celldetective/gui/InitWindow.py +28 -34
- celldetective/gui/analyze_block.py +3 -498
- celldetective/gui/classifier_widget.py +1 -1
- celldetective/gui/control_panel.py +98 -27
- celldetective/gui/generic_signal_plot.py +35 -18
- celldetective/gui/gui_utils.py +143 -2
- celldetective/gui/layouts.py +7 -6
- celldetective/gui/measurement_options.py +3 -11
- celldetective/gui/plot_measurements.py +5 -13
- celldetective/gui/plot_signals_ui.py +30 -30
- celldetective/gui/process_block.py +61 -103
- celldetective/gui/signal_annotator.py +50 -32
- celldetective/gui/signal_annotator2.py +7 -4
- celldetective/gui/styles.py +13 -0
- celldetective/gui/survival_ui.py +8 -21
- celldetective/gui/tableUI.py +1 -2
- celldetective/gui/thresholds_gui.py +0 -6
- celldetective/gui/viewers.py +1 -5
- celldetective/io.py +31 -4
- celldetective/measure.py +8 -5
- celldetective/neighborhood.py +0 -2
- celldetective/scripts/measure_cells.py +21 -9
- celldetective/signals.py +77 -66
- celldetective/tracking.py +19 -13
- {celldetective-1.3.3.post1.dist-info → celldetective-1.3.4.dist-info}/METADATA +2 -1
- {celldetective-1.3.3.post1.dist-info → celldetective-1.3.4.dist-info}/RECORD +35 -35
- tests/test_qt.py +5 -3
- {celldetective-1.3.3.post1.dist-info → celldetective-1.3.4.dist-info}/LICENSE +0 -0
- {celldetective-1.3.3.post1.dist-info → celldetective-1.3.4.dist-info}/WHEEL +0 -0
- {celldetective-1.3.3.post1.dist-info → celldetective-1.3.4.dist-info}/entry_points.txt +0 -0
- {celldetective-1.3.3.post1.dist-info → celldetective-1.3.4.dist-info}/top_level.txt +0 -0
|
@@ -47,8 +47,8 @@ class ConfigSignalPlot(QWidget, Styles):
|
|
|
47
47
|
self.ax2=None
|
|
48
48
|
self.auto_close = False
|
|
49
49
|
|
|
50
|
-
self.well_option = self.parent_window.parent_window.well_list.
|
|
51
|
-
self.position_option = self.parent_window.parent_window.position_list.
|
|
50
|
+
self.well_option = self.parent_window.parent_window.well_list.getSelectedIndices()
|
|
51
|
+
self.position_option = self.parent_window.parent_window.position_list.getSelectedIndices()
|
|
52
52
|
self.interpret_pos_location()
|
|
53
53
|
|
|
54
54
|
self.screen_height = self.parent_window.parent_window.parent_window.screen_height
|
|
@@ -67,15 +67,11 @@ class ConfigSignalPlot(QWidget, Styles):
|
|
|
67
67
|
|
|
68
68
|
"""
|
|
69
69
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
self.well_indices = np.array([self.well_option],dtype=int)
|
|
74
|
-
|
|
75
|
-
if self.position_option==0:
|
|
70
|
+
self.well_indices = self.parent_window.parent_window.well_list.getSelectedIndices()
|
|
71
|
+
self.position_indices = self.parent_window.parent_window.position_list.getSelectedIndices()
|
|
72
|
+
if not self.parent_window.parent_window.position_list.isAnySelected():
|
|
76
73
|
self.position_indices = None
|
|
77
|
-
|
|
78
|
-
self.position_indices = np.array([self.position_option],dtype=int)
|
|
74
|
+
|
|
79
75
|
|
|
80
76
|
def populate_widget(self):
|
|
81
77
|
|
|
@@ -188,11 +184,21 @@ class ConfigSignalPlot(QWidget, Styles):
|
|
|
188
184
|
if 't0' in self.all_columns:
|
|
189
185
|
time_columns.append('t0')
|
|
190
186
|
|
|
187
|
+
self.class_columns = np.unique(class_columns)
|
|
188
|
+
self.time_columns = np.unique(time_columns)
|
|
189
|
+
thresh = 18
|
|
190
|
+
self.class_truncated = [w[:thresh - 3]+'...' if len(w)>thresh else w for w in self.class_columns]
|
|
191
|
+
self.time_truncated = [w[:thresh - 3]+'...' if len(w)>thresh else w for w in self.time_columns]
|
|
192
|
+
|
|
191
193
|
self.cbs[2].clear()
|
|
192
|
-
self.cbs[2].addItems(
|
|
194
|
+
self.cbs[2].addItems(self.time_truncated)
|
|
195
|
+
for i in range(len(self.time_columns)):
|
|
196
|
+
self.cbs[2].setItemData(i, self.time_columns[i], Qt.ToolTipRole)
|
|
193
197
|
|
|
194
198
|
self.cbs[1].clear()
|
|
195
|
-
self.cbs[1].addItems(
|
|
199
|
+
self.cbs[1].addItems(self.class_truncated)
|
|
200
|
+
for i in range(len(self.class_columns)):
|
|
201
|
+
self.cbs[1].setItemData(i, self.class_columns[i], Qt.ToolTipRole)
|
|
196
202
|
|
|
197
203
|
def ask_for_feature(self):
|
|
198
204
|
|
|
@@ -273,7 +279,8 @@ class ConfigSignalPlot(QWidget, Styles):
|
|
|
273
279
|
|
|
274
280
|
# read instructions from combobox options
|
|
275
281
|
self.load_available_tables()
|
|
276
|
-
class_col = self.cbs[1].
|
|
282
|
+
class_col = self.class_columns[self.cbs[1].currentIndex()]
|
|
283
|
+
print(f"{class_col=}")
|
|
277
284
|
|
|
278
285
|
if self.df is not None:
|
|
279
286
|
|
|
@@ -300,18 +307,10 @@ class ConfigSignalPlot(QWidget, Styles):
|
|
|
300
307
|
|
|
301
308
|
"""
|
|
302
309
|
|
|
303
|
-
self.well_option = self.parent_window.parent_window.well_list.
|
|
304
|
-
|
|
305
|
-
wo = '*'
|
|
306
|
-
else:
|
|
307
|
-
wo = self.well_option
|
|
308
|
-
self.position_option = self.parent_window.parent_window.position_list.currentIndex()
|
|
309
|
-
if self.position_option==0:
|
|
310
|
-
po = '*'
|
|
311
|
-
else:
|
|
312
|
-
po = self.position_option - 1
|
|
310
|
+
self.well_option = self.parent_window.parent_window.well_list.getSelectedIndices()
|
|
311
|
+
self.position_option = self.parent_window.parent_window.position_list.getSelectedIndices()
|
|
313
312
|
|
|
314
|
-
self.df, self.df_pos_info = load_experiment_tables(self.exp_dir, well_option=
|
|
313
|
+
self.df, self.df_pos_info = load_experiment_tables(self.exp_dir, well_option=self.well_option, position_option=self.position_option, population=self.cbs[0].currentText(), return_pos_info=True)
|
|
315
314
|
|
|
316
315
|
if self.df is None:
|
|
317
316
|
|
|
@@ -337,8 +336,8 @@ class ConfigSignalPlot(QWidget, Styles):
|
|
|
337
336
|
|
|
338
337
|
# Per position signal
|
|
339
338
|
max_time = int(self.df.FRAME.max()) + 1
|
|
340
|
-
class_col = self.cbs[1].
|
|
341
|
-
time_col = self.cbs[2].
|
|
339
|
+
class_col = self.class_columns[self.cbs[1].currentIndex()]
|
|
340
|
+
time_col = self.time_columns[self.cbs[2].currentIndex()]
|
|
342
341
|
if self.abs_time_checkbox.isChecked():
|
|
343
342
|
time_col = self.frame_slider.value()
|
|
344
343
|
|
|
@@ -375,6 +374,9 @@ class ConfigSignalPlot(QWidget, Styles):
|
|
|
375
374
|
if isinstance(cclass,int):
|
|
376
375
|
cclass = [cclass]
|
|
377
376
|
|
|
377
|
+
class_col = self.class_columns[self.cbs[1].currentIndex()]
|
|
378
|
+
time_col = self.time_columns[self.cbs[2].currentIndex()]
|
|
379
|
+
|
|
378
380
|
n_cells = len(well_group.groupby(['position','TRACK_ID']))
|
|
379
381
|
depth = int(2*max_time + 3)
|
|
380
382
|
matrix = np.zeros((n_cells, depth))
|
|
@@ -382,14 +384,14 @@ class ConfigSignalPlot(QWidget, Styles):
|
|
|
382
384
|
mapping = np.arange(-max_time-1, max_time+2)
|
|
383
385
|
cid=0
|
|
384
386
|
for block,movie_group in well_group.groupby('position'):
|
|
385
|
-
for tid,track_group in movie_group.loc[movie_group[
|
|
387
|
+
for tid,track_group in movie_group.loc[movie_group[class_col].isin(cclass)].groupby('TRACK_ID'):
|
|
386
388
|
try:
|
|
387
389
|
timeline = track_group['FRAME'].to_numpy().astype(int)
|
|
388
390
|
feature = track_group[feature_selected].to_numpy()
|
|
389
391
|
if self.checkBox_feature.isChecked():
|
|
390
392
|
second_feature=track_group[self.second_feature_selected].to_numpy()
|
|
391
393
|
if self.cbs[2].currentText().startswith('t') and not self.abs_time_checkbox.isChecked():
|
|
392
|
-
t0 = math.floor(track_group[
|
|
394
|
+
t0 = math.floor(track_group[time_col].to_numpy()[0])
|
|
393
395
|
timeline -= t0
|
|
394
396
|
elif self.cbs[2].currentText()=='first detection' and not self.abs_time_checkbox.isChecked():
|
|
395
397
|
|
|
@@ -401,7 +403,6 @@ class ConfigSignalPlot(QWidget, Styles):
|
|
|
401
403
|
|
|
402
404
|
first_detection = timeline[feat==feat][0]
|
|
403
405
|
timeline -= first_detection
|
|
404
|
-
print(first_detection, timeline)
|
|
405
406
|
|
|
406
407
|
elif self.abs_time_checkbox.isChecked():
|
|
407
408
|
timeline -= int(self.frame_slider.value())
|
|
@@ -410,7 +411,6 @@ class ConfigSignalPlot(QWidget, Styles):
|
|
|
410
411
|
matrix[cid,loc_t] = feature
|
|
411
412
|
if second_feature:
|
|
412
413
|
matrix[cid,loc_t+1]=second_feature
|
|
413
|
-
print(timeline, loc_t)
|
|
414
414
|
|
|
415
415
|
cid+=1
|
|
416
416
|
except:
|
|
@@ -186,11 +186,8 @@ class ProcessPanel(QFrame, Styles):
|
|
|
186
186
|
measure_layout = QHBoxLayout()
|
|
187
187
|
|
|
188
188
|
self.measure_action = QCheckBox("MEASURE")
|
|
189
|
-
self.measure_action.setStyleSheet(
|
|
190
|
-
|
|
191
|
-
padding-left: 10px;
|
|
192
|
-
padding-top: 5px;
|
|
193
|
-
""")
|
|
189
|
+
self.measure_action.setStyleSheet(self.menu_check_style)
|
|
190
|
+
|
|
194
191
|
self.measure_action.setIcon(icon(MDI6.eyedropper,color="black"))
|
|
195
192
|
self.measure_action.setIconSize(QSize(20, 20))
|
|
196
193
|
self.measure_action.setToolTip("Measure.")
|
|
@@ -229,11 +226,7 @@ class ProcessPanel(QFrame, Styles):
|
|
|
229
226
|
signal_layout = QVBoxLayout()
|
|
230
227
|
signal_hlayout = QHBoxLayout()
|
|
231
228
|
self.signal_analysis_action = QCheckBox("DETECT EVENTS")
|
|
232
|
-
self.signal_analysis_action.setStyleSheet(
|
|
233
|
-
font-size: 10px;
|
|
234
|
-
padding-left: 10px;
|
|
235
|
-
padding-top: 5px;
|
|
236
|
-
""")
|
|
229
|
+
self.signal_analysis_action.setStyleSheet(self.menu_check_style)
|
|
237
230
|
self.signal_analysis_action.setIcon(icon(MDI6.chart_bell_curve_cumulative,color="black"))
|
|
238
231
|
self.signal_analysis_action.setIconSize(QSize(20, 20))
|
|
239
232
|
self.signal_analysis_action.setToolTip("Detect events in single-cell signals.")
|
|
@@ -295,14 +288,10 @@ class ProcessPanel(QFrame, Styles):
|
|
|
295
288
|
grid_track = QHBoxLayout()
|
|
296
289
|
|
|
297
290
|
self.track_action = QCheckBox("TRACK")
|
|
291
|
+
self.track_action.setStyleSheet(self.menu_check_style)
|
|
298
292
|
self.track_action.setIcon(icon(MDI6.chart_timeline_variant,color="black"))
|
|
299
293
|
self.track_action.setIconSize(QSize(20, 20))
|
|
300
294
|
self.track_action.setToolTip("Track the target cells using bTrack.")
|
|
301
|
-
self.track_action.setStyleSheet("""
|
|
302
|
-
font-size: 10px;
|
|
303
|
-
padding-left: 10px;
|
|
304
|
-
padding-top: 5px;
|
|
305
|
-
""")
|
|
306
295
|
grid_track.addWidget(self.track_action, 75)
|
|
307
296
|
|
|
308
297
|
self.delete_tracks_btn = QPushButton()
|
|
@@ -372,10 +361,7 @@ class ProcessPanel(QFrame, Styles):
|
|
|
372
361
|
grid_segment.setSpacing(0)
|
|
373
362
|
|
|
374
363
|
self.segment_action = QCheckBox("SEGMENT")
|
|
375
|
-
self.segment_action.setStyleSheet(
|
|
376
|
-
font-size: 10px;
|
|
377
|
-
padding-left: 10px;
|
|
378
|
-
""")
|
|
364
|
+
self.segment_action.setStyleSheet(self.menu_check_style)
|
|
379
365
|
self.segment_action.setIcon(icon(MDI6.bacteria, color='black'))
|
|
380
366
|
self.segment_action.setToolTip(f"Segment the {self.mode} cells on the images.")
|
|
381
367
|
self.segment_action.toggled.connect(self.enable_segmentation_model_list)
|
|
@@ -698,11 +684,24 @@ class ProcessPanel(QFrame, Styles):
|
|
|
698
684
|
|
|
699
685
|
def process_population(self):
|
|
700
686
|
|
|
701
|
-
if self.parent_window.well_list.currentText()
|
|
702
|
-
|
|
703
|
-
else:
|
|
704
|
-
|
|
705
|
-
|
|
687
|
+
# if self.parent_window.well_list.currentText().startswith('Multiple'):
|
|
688
|
+
# self.well_index = np.linspace(0,len(self.wells)-1,len(self.wells),dtype=int)
|
|
689
|
+
# else:
|
|
690
|
+
|
|
691
|
+
self.well_index = self.parent_window.well_list.getSelectedIndices()
|
|
692
|
+
if len(self.well_index)==0:
|
|
693
|
+
msgBox = QMessageBox()
|
|
694
|
+
msgBox.setIcon(QMessageBox.Warning)
|
|
695
|
+
msgBox.setText("Please select at least one well first...")
|
|
696
|
+
msgBox.setWindowTitle("Warning")
|
|
697
|
+
msgBox.setStandardButtons(QMessageBox.Ok)
|
|
698
|
+
returnValue = msgBox.exec()
|
|
699
|
+
if returnValue == QMessageBox.Ok:
|
|
700
|
+
return None
|
|
701
|
+
else:
|
|
702
|
+
return None
|
|
703
|
+
|
|
704
|
+
print(f"Processing {self.parent_window.well_list.currentText()}...")
|
|
706
705
|
|
|
707
706
|
# self.freeze()
|
|
708
707
|
# QApplication.setOverrideCursor(Qt.WaitCursor)
|
|
@@ -735,10 +734,10 @@ class ProcessPanel(QFrame, Styles):
|
|
|
735
734
|
|
|
736
735
|
loop_iter=0
|
|
737
736
|
|
|
738
|
-
if self.parent_window.position_list.
|
|
737
|
+
if self.parent_window.position_list.isMultipleSelection():
|
|
739
738
|
msgBox = QMessageBox()
|
|
740
739
|
msgBox.setIcon(QMessageBox.Question)
|
|
741
|
-
msgBox.setText("If you continue,
|
|
740
|
+
msgBox.setText("If you continue, several positions will be processed.\nDo you want to proceed?")
|
|
742
741
|
msgBox.setWindowTitle("Info")
|
|
743
742
|
msgBox.setStandardButtons(QMessageBox.Yes | QMessageBox.No)
|
|
744
743
|
returnValue = msgBox.exec()
|
|
@@ -767,12 +766,8 @@ class ProcessPanel(QFrame, Styles):
|
|
|
767
766
|
for w_idx in self.well_index:
|
|
768
767
|
|
|
769
768
|
pos = self.parent_window.positions[w_idx]
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
print("Processing all positions...")
|
|
773
|
-
else:
|
|
774
|
-
pos_indices = natsorted([pos.index(self.parent_window.position_list.currentText())])
|
|
775
|
-
print(f"Processing position {self.parent_window.position_list.currentText()}...")
|
|
769
|
+
pos_indices = self.parent_window.position_list.getSelectedIndices()
|
|
770
|
+
#print(f"Processing position {self.parent_window.position_list.currentText()}...")
|
|
776
771
|
|
|
777
772
|
well = self.parent_window.wells[w_idx]
|
|
778
773
|
|
|
@@ -788,7 +783,7 @@ class ProcessPanel(QFrame, Styles):
|
|
|
788
783
|
|
|
789
784
|
if self.segment_action.isChecked():
|
|
790
785
|
|
|
791
|
-
if len(glob(os.sep.join([self.pos, f'labels_{self.mode}','*.tif'])))>0 and self.parent_window.position_list.
|
|
786
|
+
if len(glob(os.sep.join([self.pos, f'labels_{self.mode}','*.tif'])))>0 and not self.parent_window.position_list.isMultipleSelection():
|
|
792
787
|
msgBox = QMessageBox()
|
|
793
788
|
msgBox.setIcon(QMessageBox.Question)
|
|
794
789
|
msgBox.setText("Labels have already been produced for this position. Do you want to segment again?")
|
|
@@ -815,7 +810,7 @@ class ProcessPanel(QFrame, Styles):
|
|
|
815
810
|
segment_at_position(self.pos, self.mode, self.model_name, stack_prefix=self.parent_window.movie_prefix, use_gpu=self.parent_window.parent_window.use_gpu, threads=self.parent_window.parent_window.n_threads)
|
|
816
811
|
|
|
817
812
|
if self.track_action.isChecked():
|
|
818
|
-
if os.path.exists(os.sep.join([self.pos, 'output', 'tables', f'trajectories_{self.mode}.csv'])) and self.parent_window.position_list.
|
|
813
|
+
if os.path.exists(os.sep.join([self.pos, 'output', 'tables', f'trajectories_{self.mode}.csv'])) and not self.parent_window.position_list.isMultipleSelection():
|
|
819
814
|
msgBox = QMessageBox()
|
|
820
815
|
msgBox.setIcon(QMessageBox.Question)
|
|
821
816
|
msgBox.setText("A trajectory set already exists. Previously annotated data for\nthis position will be lost. Do you want to proceed?")
|
|
@@ -831,15 +826,12 @@ class ProcessPanel(QFrame, Styles):
|
|
|
831
826
|
|
|
832
827
|
table = os.sep.join([self.pos, 'output', 'tables', f'trajectories_{self.mode}.csv'])
|
|
833
828
|
if self.signal_analysis_action.isChecked() and os.path.exists(table):
|
|
834
|
-
print('table exists')
|
|
835
829
|
table = pd.read_csv(table)
|
|
836
830
|
cols = list(table.columns)
|
|
837
|
-
print(table, cols)
|
|
838
831
|
if 'class_color' in cols:
|
|
839
|
-
print(cols, 'class_color in cols')
|
|
840
832
|
colors = list(table['class_color'].to_numpy())
|
|
841
833
|
if 'tab:orange' in colors or 'tab:cyan' in colors:
|
|
842
|
-
if self.parent_window.position_list.
|
|
834
|
+
if not self.parent_window.position_list.isMultipleSelection():
|
|
843
835
|
msgBox = QMessageBox()
|
|
844
836
|
msgBox.setIcon(QMessageBox.Question)
|
|
845
837
|
msgBox.setText("The signals of the cells in the position appear to have been annotated... Do you want to proceed?")
|
|
@@ -871,7 +863,7 @@ class ProcessPanel(QFrame, Styles):
|
|
|
871
863
|
plot_mode = 'plot_track_signals'
|
|
872
864
|
if 'TRACK_ID' not in list(self.df.columns):
|
|
873
865
|
plot_mode = 'static'
|
|
874
|
-
self.tab_ui = TableUI(self.df, f"
|
|
866
|
+
self.tab_ui = TableUI(self.df, f"{self.parent_window.well_list.currentText()}; Position {self.parent_window.position_list.currentText()}", population=self.mode, plot_mode=plot_mode, save_inplace_option=True)
|
|
875
867
|
self.tab_ui.show()
|
|
876
868
|
else:
|
|
877
869
|
print('Table could not be loaded...')
|
|
@@ -891,18 +883,10 @@ class ProcessPanel(QFrame, Styles):
|
|
|
891
883
|
|
|
892
884
|
"""
|
|
893
885
|
|
|
894
|
-
self.well_option = self.parent_window.well_list.
|
|
895
|
-
|
|
896
|
-
wo = '*'
|
|
897
|
-
else:
|
|
898
|
-
wo = self.well_option
|
|
899
|
-
self.position_option = self.parent_window.position_list.currentIndex()
|
|
900
|
-
if self.position_option==0:
|
|
901
|
-
po = '*'
|
|
902
|
-
else:
|
|
903
|
-
po = self.position_option - 1
|
|
886
|
+
self.well_option = self.parent_window.well_list.getSelectedIndices()
|
|
887
|
+
self.position_option = self.parent_window.position_list.getSelectedIndices()
|
|
904
888
|
|
|
905
|
-
self.df, self.df_pos_info = load_experiment_tables(self.exp_dir, well_option=
|
|
889
|
+
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)
|
|
906
890
|
if self.df is None:
|
|
907
891
|
print('No table could be found...')
|
|
908
892
|
|
|
@@ -1027,11 +1011,8 @@ class NeighPanel(QFrame, Styles):
|
|
|
1027
1011
|
# Button to compute the neighborhoods
|
|
1028
1012
|
neigh_option_hbox = QHBoxLayout()
|
|
1029
1013
|
self.neigh_action = QCheckBox('NEIGHBORHOODS')
|
|
1030
|
-
self.neigh_action.setStyleSheet(
|
|
1031
|
-
|
|
1032
|
-
padding-left: 10px;
|
|
1033
|
-
padding-top: 5px;
|
|
1034
|
-
""")
|
|
1014
|
+
self.neigh_action.setStyleSheet(self.menu_check_style)
|
|
1015
|
+
|
|
1035
1016
|
#self.neigh_action.setIcon(icon(MDI6.eyedropper, color="black"))
|
|
1036
1017
|
#self.neigh_action.setIconSize(QSize(20, 20))
|
|
1037
1018
|
self.neigh_action.setToolTip(
|
|
@@ -1131,11 +1112,8 @@ class NeighPanel(QFrame, Styles):
|
|
|
1131
1112
|
|
|
1132
1113
|
rel_layout = QHBoxLayout()
|
|
1133
1114
|
self.measure_pairs_action = QCheckBox("MEASURE PAIRS")
|
|
1134
|
-
self.measure_pairs_action.setStyleSheet(
|
|
1135
|
-
|
|
1136
|
-
padding-left: 10px;
|
|
1137
|
-
padding-top: 5px;
|
|
1138
|
-
""")
|
|
1115
|
+
self.measure_pairs_action.setStyleSheet(self.menu_check_style)
|
|
1116
|
+
|
|
1139
1117
|
self.measure_pairs_action.setIcon(icon(MDI6.eyedropper, color="black"))
|
|
1140
1118
|
self.measure_pairs_action.setIconSize(QSize(20, 20))
|
|
1141
1119
|
self.measure_pairs_action.setToolTip("Measure the relative quantities defined for the cell pairs, for all neighborhoods.")
|
|
@@ -1154,10 +1132,7 @@ class NeighPanel(QFrame, Styles):
|
|
|
1154
1132
|
signal_layout = QVBoxLayout()
|
|
1155
1133
|
signal_hlayout = QHBoxLayout()
|
|
1156
1134
|
self.signal_analysis_action = QCheckBox("DETECT PAIR EVENTS")
|
|
1157
|
-
self.signal_analysis_action.setStyleSheet(
|
|
1158
|
-
font-size: 10px;
|
|
1159
|
-
padding-left: 10px;
|
|
1160
|
-
padding-top: 5px;""")
|
|
1135
|
+
self.signal_analysis_action.setStyleSheet(self.menu_check_style)
|
|
1161
1136
|
|
|
1162
1137
|
self.signal_analysis_action.setIcon(icon(MDI6.chart_bell_curve_cumulative, color="black"))
|
|
1163
1138
|
self.signal_analysis_action.setIconSize(QSize(20, 20))
|
|
@@ -1282,18 +1257,10 @@ class NeighPanel(QFrame, Styles):
|
|
|
1282
1257
|
|
|
1283
1258
|
"""
|
|
1284
1259
|
|
|
1285
|
-
self.well_option = self.parent_window.well_list.
|
|
1286
|
-
|
|
1287
|
-
wo = '*'
|
|
1288
|
-
else:
|
|
1289
|
-
wo = self.well_option
|
|
1290
|
-
self.position_option = self.parent_window.position_list.currentIndex()
|
|
1291
|
-
if self.position_option==0:
|
|
1292
|
-
po = '*'
|
|
1293
|
-
else:
|
|
1294
|
-
po = self.position_option - 1
|
|
1260
|
+
self.well_option = self.parent_window.well_list.getSelectedIndices()
|
|
1261
|
+
self.position_option = self.parent_window.position_list.getSelectedIndices()
|
|
1295
1262
|
|
|
1296
|
-
self.df, self.df_pos_info = load_experiment_tables(self.exp_dir, well_option=
|
|
1263
|
+
self.df, self.df_pos_info = load_experiment_tables(self.exp_dir, well_option=self.well_option, position_option=self.position_option, population="pairs", return_pos_info=True)
|
|
1297
1264
|
if self.df is None:
|
|
1298
1265
|
print('No table could be found...')
|
|
1299
1266
|
|
|
@@ -1305,7 +1272,7 @@ class NeighPanel(QFrame, Styles):
|
|
|
1305
1272
|
|
|
1306
1273
|
if self.df is not None:
|
|
1307
1274
|
plot_mode = 'static'
|
|
1308
|
-
self.tab_ui = TableUI(self.df, f"
|
|
1275
|
+
self.tab_ui = TableUI(self.df, f"{self.parent_window.well_list.currentText()}; Position {self.parent_window.position_list.currentText()}", population='pairs', plot_mode=plot_mode, save_inplace_option=True)
|
|
1309
1276
|
self.tab_ui.show()
|
|
1310
1277
|
else:
|
|
1311
1278
|
print('Table could not be loaded...')
|
|
@@ -1382,18 +1349,18 @@ class NeighPanel(QFrame, Styles):
|
|
|
1382
1349
|
|
|
1383
1350
|
def process_neighborhood(self):
|
|
1384
1351
|
|
|
1385
|
-
if self.parent_window.well_list.currentText()
|
|
1386
|
-
|
|
1387
|
-
else:
|
|
1388
|
-
|
|
1389
|
-
|
|
1352
|
+
# if self.parent_window.well_list.currentText().startswith('Multiple'):
|
|
1353
|
+
# self.well_index = np.linspace(0,len(self.wells)-1,len(self.wells),dtype=int)
|
|
1354
|
+
# else:
|
|
1355
|
+
self.well_index = self.parent_window.well_list.getSelectedIndices()
|
|
1356
|
+
print(f"Processing well {self.parent_window.well_list.currentText()}...")
|
|
1390
1357
|
|
|
1391
1358
|
# self.freeze()
|
|
1392
1359
|
# QApplication.setOverrideCursor(Qt.WaitCursor)
|
|
1393
1360
|
|
|
1394
1361
|
loop_iter=0
|
|
1395
1362
|
|
|
1396
|
-
if self.parent_window.position_list.
|
|
1363
|
+
if self.parent_window.position_list.isMultipleSelection():
|
|
1397
1364
|
msgBox = QMessageBox()
|
|
1398
1365
|
msgBox.setIcon(QMessageBox.Question)
|
|
1399
1366
|
msgBox.setText("If you continue, all positions will be processed.\nDo you want to proceed?")
|
|
@@ -1406,12 +1373,7 @@ class NeighPanel(QFrame, Styles):
|
|
|
1406
1373
|
for w_idx in self.well_index:
|
|
1407
1374
|
|
|
1408
1375
|
pos = self.parent_window.positions[w_idx]
|
|
1409
|
-
|
|
1410
|
-
pos_indices = np.linspace(0,len(pos)-1,len(pos),dtype=int)
|
|
1411
|
-
print("Processing all positions...")
|
|
1412
|
-
else:
|
|
1413
|
-
pos_indices = natsorted([pos.index(self.parent_window.position_list.currentText())])
|
|
1414
|
-
print(f"Processing position {self.parent_window.position_list.currentText()}...")
|
|
1376
|
+
pos_indices = self.parent_window.position_list.getSelectedIndices()
|
|
1415
1377
|
|
|
1416
1378
|
well = self.parent_window.wells[w_idx]
|
|
1417
1379
|
|
|
@@ -1618,8 +1580,8 @@ class PreprocessingPanel(QFrame, Styles):
|
|
|
1618
1580
|
if returnValue == QMessageBox.Cancel:
|
|
1619
1581
|
return None
|
|
1620
1582
|
elif returnValue == QMessageBox.Yes:
|
|
1621
|
-
self.parent_window.well_list.
|
|
1622
|
-
self.parent_window.position_list.
|
|
1583
|
+
self.parent_window.well_list.selectAll()
|
|
1584
|
+
self.parent_window.position_list.selectAll()
|
|
1623
1585
|
elif returnValue == QMessageBox.No:
|
|
1624
1586
|
msgBox2 = QMessageBox()
|
|
1625
1587
|
msgBox2.setIcon(QMessageBox.Question)
|
|
@@ -1634,16 +1596,11 @@ class PreprocessingPanel(QFrame, Styles):
|
|
|
1634
1596
|
|
|
1635
1597
|
print('Proceed with correction...')
|
|
1636
1598
|
|
|
1637
|
-
if self.parent_window.well_list.currentText()=='*':
|
|
1638
|
-
|
|
1639
|
-
else:
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
if self.parent_window.position_list.currentText()=='*':
|
|
1643
|
-
pos_option = "*"
|
|
1644
|
-
else:
|
|
1645
|
-
pos_option = self.parent_window.position_list.currentIndex()-1
|
|
1646
|
-
|
|
1599
|
+
# if self.parent_window.well_list.currentText()=='*':
|
|
1600
|
+
# well_option = "*"
|
|
1601
|
+
# else:
|
|
1602
|
+
well_option = self.parent_window.well_list.getSelectedIndices()
|
|
1603
|
+
position_option = self.parent_window.position_list.getSelectedIndices()
|
|
1647
1604
|
|
|
1648
1605
|
for k,correction_protocol in enumerate(self.protocol_layout.protocols):
|
|
1649
1606
|
|
|
@@ -1658,7 +1615,7 @@ class PreprocessingPanel(QFrame, Styles):
|
|
|
1658
1615
|
print(f'Model-free correction; {movie_prefix=} {export_prefix=}')
|
|
1659
1616
|
correct_background_model_free(self.exp_dir,
|
|
1660
1617
|
well_option=well_option,
|
|
1661
|
-
position_option=
|
|
1618
|
+
position_option=position_option,
|
|
1662
1619
|
export = True,
|
|
1663
1620
|
return_stacks=False,
|
|
1664
1621
|
show_progress_per_well = True,
|
|
@@ -1672,7 +1629,7 @@ class PreprocessingPanel(QFrame, Styles):
|
|
|
1672
1629
|
print(f'Fit correction; {movie_prefix=} {export_prefix=} {correction_protocol=}')
|
|
1673
1630
|
correct_background_model(self.exp_dir,
|
|
1674
1631
|
well_option=well_option,
|
|
1675
|
-
position_option=
|
|
1632
|
+
position_option=position_option,
|
|
1676
1633
|
export= True,
|
|
1677
1634
|
return_stacks=False,
|
|
1678
1635
|
show_progress_per_well = True,
|
|
@@ -1685,7 +1642,7 @@ class PreprocessingPanel(QFrame, Styles):
|
|
|
1685
1642
|
print(f'Offset correction; {movie_prefix=} {export_prefix=} {correction_protocol=}')
|
|
1686
1643
|
correct_channel_offset(self.exp_dir,
|
|
1687
1644
|
well_option=well_option,
|
|
1688
|
-
position_option=
|
|
1645
|
+
position_option=position_option,
|
|
1689
1646
|
export= True,
|
|
1690
1647
|
return_stacks=False,
|
|
1691
1648
|
show_progress_per_well = True,
|
|
@@ -1703,6 +1660,7 @@ class PreprocessingPanel(QFrame, Styles):
|
|
|
1703
1660
|
Load the first frame of the first movie found in the experiment folder as a sample.
|
|
1704
1661
|
"""
|
|
1705
1662
|
|
|
1663
|
+
print(f"{self.parent_window.pos}")
|
|
1706
1664
|
movies = glob(self.parent_window.pos + os.sep.join(['movie', f"{self.parent_window.movie_prefix}*.tif"]))
|
|
1707
1665
|
|
|
1708
1666
|
if len(movies) == 0:
|
|
@@ -50,6 +50,7 @@ class SignalAnnotator(QMainWindow, Styles):
|
|
|
50
50
|
self.soft_path = get_software_location()
|
|
51
51
|
self.recently_modified = False
|
|
52
52
|
self.selection = []
|
|
53
|
+
|
|
53
54
|
if self.mode == "targets":
|
|
54
55
|
self.instructions_path = self.exp_dir + os.sep.join(['configs', 'signal_annotator_config_targets.json'])
|
|
55
56
|
self.trajectories_path = self.pos + os.sep.join(['output','tables','trajectories_targets.csv'])
|
|
@@ -505,6 +506,11 @@ class SignalAnnotator(QMainWindow, Styles):
|
|
|
505
506
|
self.df_tracks['class_color'] = [color_from_class(i) for i in self.df_tracks[self.class_name].to_numpy()]
|
|
506
507
|
|
|
507
508
|
self.extract_scatter_from_trajectories()
|
|
509
|
+
if len(self.selection)>0:
|
|
510
|
+
self.select_single_cell(self.selection[0][0], self.selection[0][1])
|
|
511
|
+
|
|
512
|
+
self.fcanvas.canvas.draw()
|
|
513
|
+
|
|
508
514
|
|
|
509
515
|
def contrast_slider_action(self):
|
|
510
516
|
|
|
@@ -527,14 +533,14 @@ class SignalAnnotator(QMainWindow, Styles):
|
|
|
527
533
|
try:
|
|
528
534
|
self.selection.pop(0)
|
|
529
535
|
except Exception as e:
|
|
530
|
-
print(e)
|
|
536
|
+
print(f"L 536 {e=}")
|
|
531
537
|
|
|
532
538
|
try:
|
|
533
539
|
for k, (t, idx) in enumerate(zip(self.loc_t, self.loc_idx)):
|
|
534
540
|
self.colors[t][idx, 0] = self.previous_color[k][0]
|
|
535
541
|
self.colors[t][idx, 1] = self.previous_color[k][1]
|
|
536
542
|
except Exception as e:
|
|
537
|
-
print(f'{e=}')
|
|
543
|
+
print(f'L 543 {e=}')
|
|
538
544
|
|
|
539
545
|
def hide_annotation_buttons(self):
|
|
540
546
|
|
|
@@ -589,7 +595,7 @@ class SignalAnnotator(QMainWindow, Styles):
|
|
|
589
595
|
self.line_dt.set_xdata([t0, t0])
|
|
590
596
|
self.cell_fcanvas.canvas.draw_idle()
|
|
591
597
|
except Exception as e:
|
|
592
|
-
print(e)
|
|
598
|
+
print(f"L 598 {e=}")
|
|
593
599
|
t0 = -1
|
|
594
600
|
cclass = 2
|
|
595
601
|
elif self.no_event_btn.isChecked():
|
|
@@ -611,9 +617,14 @@ class SignalAnnotator(QMainWindow, Styles):
|
|
|
611
617
|
status[:] = 2
|
|
612
618
|
if cclass > 2:
|
|
613
619
|
status[:] = 42
|
|
620
|
+
|
|
614
621
|
status_color = [color_from_status(s, recently_modified=True) for s in status]
|
|
615
622
|
class_color = [color_from_class(cclass, recently_modified=True) for i in range(len(status))]
|
|
616
623
|
|
|
624
|
+
|
|
625
|
+
# self.df_tracks['status_color'] = [color_from_status(i) for i in self.df_tracks[self.status_name].to_numpy()]
|
|
626
|
+
# self.df_tracks['class_color'] = [color_from_class(i) for i in self.df_tracks[self.class_name].to_numpy()]
|
|
627
|
+
|
|
617
628
|
self.df_tracks.loc[indices, self.status_name] = status
|
|
618
629
|
self.df_tracks.loc[indices, 'status_color'] = status_color
|
|
619
630
|
self.df_tracks.loc[indices, 'class_color'] = class_color
|
|
@@ -984,13 +995,9 @@ class SignalAnnotator(QMainWindow, Styles):
|
|
|
984
995
|
self.stack[np.where(self.stack > 0.)] = np.log(self.stack[np.where(self.stack > 0.)])
|
|
985
996
|
|
|
986
997
|
def closeEvent(self, event):
|
|
998
|
+
|
|
987
999
|
try:
|
|
988
1000
|
self.stop()
|
|
989
|
-
# result = QMessageBox.question(self,
|
|
990
|
-
# "Confirm Exit...",
|
|
991
|
-
# "Are you sure you want to exit ?",
|
|
992
|
-
# QMessageBox.Yes| QMessageBox.No,
|
|
993
|
-
# )
|
|
994
1001
|
del self.stack
|
|
995
1002
|
gc.collect()
|
|
996
1003
|
except:
|
|
@@ -1068,6 +1075,8 @@ class SignalAnnotator(QMainWindow, Styles):
|
|
|
1068
1075
|
|
|
1069
1076
|
def on_scatter_pick(self, event):
|
|
1070
1077
|
|
|
1078
|
+
self.event = event
|
|
1079
|
+
|
|
1071
1080
|
self.correct_btn.disconnect()
|
|
1072
1081
|
self.correct_btn.clicked.connect(self.show_annotation_buttons)
|
|
1073
1082
|
|
|
@@ -1082,36 +1091,41 @@ class SignalAnnotator(QMainWindow, Styles):
|
|
|
1082
1091
|
ind = [ind[np.argmin(dist)]]
|
|
1083
1092
|
|
|
1084
1093
|
if len(ind) > 0 and (len(self.selection) == 0):
|
|
1085
|
-
|
|
1086
|
-
self.selection.append(ind)
|
|
1087
|
-
self.
|
|
1088
|
-
self.cancel_btn.setEnabled(True)
|
|
1089
|
-
self.del_shortcut.setEnabled(True)
|
|
1090
|
-
self.no_event_shortcut.setEnabled(True)
|
|
1091
|
-
|
|
1092
|
-
self.track_of_interest = self.tracks[self.framedata][ind]
|
|
1093
|
-
print(f'You selected cell #{self.track_of_interest}...')
|
|
1094
|
-
self.give_cell_information()
|
|
1095
|
-
self.plot_signals()
|
|
1096
|
-
|
|
1097
|
-
self.loc_t = []
|
|
1098
|
-
self.loc_idx = []
|
|
1099
|
-
for t in range(len(self.tracks)):
|
|
1100
|
-
indices = np.where(self.tracks[t] == self.track_of_interest)[0]
|
|
1101
|
-
if len(indices) > 0:
|
|
1102
|
-
self.loc_t.append(t)
|
|
1103
|
-
self.loc_idx.append(indices[0])
|
|
1104
|
-
|
|
1105
|
-
self.previous_color = []
|
|
1106
|
-
for t, idx in zip(self.loc_t, self.loc_idx):
|
|
1107
|
-
self.previous_color.append(self.colors[t][idx].copy())
|
|
1108
|
-
self.colors[t][idx] = 'lime'
|
|
1094
|
+
|
|
1095
|
+
self.selection.append([ind[0],self.framedata])
|
|
1096
|
+
self.select_single_cell(ind[0], self.framedata)
|
|
1109
1097
|
|
|
1110
1098
|
elif len(ind) > 0 and len(self.selection) == 1:
|
|
1111
1099
|
self.cancel_btn.click()
|
|
1112
1100
|
else:
|
|
1113
1101
|
pass
|
|
1114
1102
|
|
|
1103
|
+
def select_single_cell(self, index, timepoint):
|
|
1104
|
+
|
|
1105
|
+
self.correct_btn.setEnabled(True)
|
|
1106
|
+
self.cancel_btn.setEnabled(True)
|
|
1107
|
+
self.del_shortcut.setEnabled(True)
|
|
1108
|
+
self.no_event_shortcut.setEnabled(True)
|
|
1109
|
+
|
|
1110
|
+
self.track_of_interest = self.tracks[timepoint][index]
|
|
1111
|
+
print(f'You selected cell #{self.track_of_interest}...')
|
|
1112
|
+
self.give_cell_information()
|
|
1113
|
+
self.plot_signals()
|
|
1114
|
+
|
|
1115
|
+
self.loc_t = []
|
|
1116
|
+
self.loc_idx = []
|
|
1117
|
+
for t in range(len(self.tracks)):
|
|
1118
|
+
indices = np.where(self.tracks[t] == self.track_of_interest)[0]
|
|
1119
|
+
if len(indices) > 0:
|
|
1120
|
+
self.loc_t.append(t)
|
|
1121
|
+
self.loc_idx.append(indices[0])
|
|
1122
|
+
|
|
1123
|
+
self.previous_color = []
|
|
1124
|
+
for t, idx in zip(self.loc_t, self.loc_idx):
|
|
1125
|
+
self.previous_color.append(self.colors[t][idx].copy())
|
|
1126
|
+
self.colors[t][idx] = 'lime'
|
|
1127
|
+
|
|
1128
|
+
|
|
1115
1129
|
def shortcut_suppr(self):
|
|
1116
1130
|
self.correct_btn.click()
|
|
1117
1131
|
self.suppr_btn.click()
|
|
@@ -1158,6 +1172,7 @@ class SignalAnnotator(QMainWindow, Styles):
|
|
|
1158
1172
|
if len(min_values) > 0:
|
|
1159
1173
|
self.cell_ax.set_ylim(smallest_value - pad_small, largest_value + pad_large)
|
|
1160
1174
|
except Exception as e:
|
|
1175
|
+
print(f"L1170 {e=}")
|
|
1161
1176
|
pass
|
|
1162
1177
|
|
|
1163
1178
|
def draw_frame(self, framedata):
|
|
@@ -1220,6 +1235,7 @@ class SignalAnnotator(QMainWindow, Styles):
|
|
|
1220
1235
|
self.df_tracks = self.df_tracks.drop(self.df_tracks[self.df_tracks[self.class_name] > 2].index)
|
|
1221
1236
|
self.df_tracks.to_csv(self.trajectories_path, index=False)
|
|
1222
1237
|
print('Table successfully exported...')
|
|
1238
|
+
self.compute_status_and_colors(0)
|
|
1223
1239
|
self.extract_scatter_from_trajectories()
|
|
1224
1240
|
|
|
1225
1241
|
# self.give_cell_information()
|
|
@@ -2424,6 +2440,8 @@ class MeasureAnnotator(SignalAnnotator):
|
|
|
2424
2440
|
except Exception as e:
|
|
2425
2441
|
print("cancel_selection: ",f'{e=}')
|
|
2426
2442
|
|
|
2443
|
+
self.event = None
|
|
2444
|
+
|
|
2427
2445
|
def locate_stack(self):
|
|
2428
2446
|
|
|
2429
2447
|
"""
|
|
@@ -2213,10 +2213,13 @@ class SignalAnnotator2(QMainWindow,Styles):
|
|
|
2213
2213
|
self.index = ind[0]
|
|
2214
2214
|
elif len(ind)>1:
|
|
2215
2215
|
# More than one point in vicinity
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
2216
|
+
try:
|
|
2217
|
+
datax,datay = [positions[self.framedata][i,0] for i in ind],[positions[self.framedata][i,1] for i in ind]
|
|
2218
|
+
msx, msy = event.mouseevent.xdata, event.mouseevent.ydata
|
|
2219
|
+
dist = np.sqrt((np.array(datax)-msx)**2+(np.array(datay)-msy)**2)
|
|
2220
|
+
self.index = ind[np.argmin(dist)]
|
|
2221
|
+
except Exception as e:
|
|
2222
|
+
print(f"{e=}")
|
|
2220
2223
|
else:
|
|
2221
2224
|
self.index = None
|
|
2222
2225
|
|