celldetective 1.3.2__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 +100 -29
- 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 +38 -43
- celldetective/gui/plot_measurements.py +5 -13
- celldetective/gui/plot_signals_ui.py +30 -30
- celldetective/gui/process_block.py +66 -197
- celldetective/gui/retrain_segmentation_model_options.py +3 -1
- 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 +195 -205
- celldetective/gui/viewers.py +262 -12
- celldetective/io.py +85 -11
- celldetective/measure.py +128 -88
- celldetective/models/segmentation_effectors/ricm_bf_all_last/config_input.json +79 -0
- celldetective/models/segmentation_effectors/ricm_bf_all_last/ricm_bf_all_last +0 -0
- celldetective/models/segmentation_effectors/ricm_bf_all_last/training_instructions.json +37 -0
- celldetective/models/segmentation_effectors/test-transfer/config_input.json +39 -0
- celldetective/models/segmentation_effectors/test-transfer/test-transfer +0 -0
- 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.2.dist-info → celldetective-1.3.4.dist-info}/METADATA +12 -10
- {celldetective-1.3.2.dist-info → celldetective-1.3.4.dist-info}/RECORD +41 -36
- {celldetective-1.3.2.dist-info → celldetective-1.3.4.dist-info}/WHEEL +1 -1
- tests/test_qt.py +5 -3
- {celldetective-1.3.2.dist-info → celldetective-1.3.4.dist-info}/LICENSE +0 -0
- {celldetective-1.3.2.dist-info → celldetective-1.3.4.dist-info}/entry_points.txt +0 -0
- {celldetective-1.3.2.dist-info → celldetective-1.3.4.dist-info}/top_level.txt +0 -0
|
@@ -10,7 +10,7 @@ from superqt import QLabeledDoubleSlider
|
|
|
10
10
|
from superqt.fonticon import icon
|
|
11
11
|
from fonticon_mdi6 import MDI6
|
|
12
12
|
|
|
13
|
-
from celldetective.gui.thresholds_gui import ThresholdSpot
|
|
13
|
+
#from celldetective.gui.thresholds_gui import ThresholdSpot
|
|
14
14
|
from celldetective.utils import extract_experiment_channels, get_software_location
|
|
15
15
|
from celldetective.io import load_frames, auto_load_number_of_frames
|
|
16
16
|
from celldetective.measure import compute_haralick_features
|
|
@@ -24,9 +24,8 @@ from glob import glob
|
|
|
24
24
|
from natsort import natsorted
|
|
25
25
|
from tifffile import imread
|
|
26
26
|
from pathlib import Path
|
|
27
|
-
import gc
|
|
28
27
|
|
|
29
|
-
from celldetective.gui.viewers import CellEdgeVisualizer
|
|
28
|
+
from celldetective.gui.viewers import CellEdgeVisualizer, SpotDetectionVisualizer
|
|
30
29
|
from celldetective.gui.layouts import ProtocolDesignerLayout, BackgroundFitCorrectionLayout, LocalCorrectionLayout
|
|
31
30
|
from celldetective.gui.gui_utils import ThresholdLineEdit
|
|
32
31
|
from celldetective.gui import Styles
|
|
@@ -726,18 +725,10 @@ class ConfigMeasurements(QMainWindow, Styles):
|
|
|
726
725
|
else:
|
|
727
726
|
self.current_stack = movies[0]
|
|
728
727
|
self.stack_length = auto_load_number_of_frames(self.current_stack)
|
|
729
|
-
|
|
730
|
-
if self.stack_length is None:
|
|
731
|
-
stack = imread(self.current_stack)
|
|
732
|
-
self.stack_length = len(stack)
|
|
733
|
-
del stack
|
|
734
|
-
gc.collect()
|
|
735
|
-
|
|
736
728
|
self.mid_time = self.stack_length // 2
|
|
737
|
-
indices = self.mid_time + np.arange(len(self.channel_names))
|
|
729
|
+
indices = len(self.channel_names) * self.mid_time + np.arange(len(self.channel_names))
|
|
738
730
|
self.test_frame = load_frames(list(indices.astype(int)),self.current_stack, normalize_input=False)
|
|
739
731
|
|
|
740
|
-
|
|
741
732
|
def control_haralick_digitalization(self):
|
|
742
733
|
|
|
743
734
|
"""
|
|
@@ -746,9 +737,10 @@ class ConfigMeasurements(QMainWindow, Styles):
|
|
|
746
737
|
|
|
747
738
|
"""
|
|
748
739
|
|
|
749
|
-
self.locate_image()
|
|
740
|
+
self.locate_image() # pb here
|
|
750
741
|
self.extract_haralick_options()
|
|
751
742
|
if self.test_frame is not None:
|
|
743
|
+
|
|
752
744
|
digitized_img = compute_haralick_features(self.test_frame, np.zeros(self.test_frame.shape[:2]),
|
|
753
745
|
channels=self.channel_names, return_digit_image_only=True,
|
|
754
746
|
**self.haralick_options
|
|
@@ -951,51 +943,54 @@ class ConfigMeasurements(QMainWindow, Styles):
|
|
|
951
943
|
|
|
952
944
|
layout.addWidget(self.threshold_lbl, 4, 0)
|
|
953
945
|
layout.addWidget(self.threshold_value, 4, 1)
|
|
954
|
-
self.preview_spot = QPushButton('Preview')
|
|
955
|
-
self.preview_spot.clicked.connect(self.spot_preview)
|
|
956
|
-
self.preview_spot.setStyleSheet(self.button_style_sheet_2)
|
|
957
|
-
layout.addWidget(self.preview_spot, 5, 0, 1, 2)
|
|
958
|
-
self.spot_channel.setEnabled(False)
|
|
959
|
-
self.spot_channel_lbl.setEnabled(False)
|
|
960
|
-
self.diameter_value.setEnabled(False)
|
|
961
|
-
self.diameter_lbl.setEnabled(False)
|
|
962
|
-
self.threshold_value.setEnabled(False)
|
|
963
|
-
self.threshold_lbl.setEnabled(False)
|
|
964
|
-
self.preview_spot.setEnabled(False)
|
|
965
946
|
|
|
947
|
+
self.spot_viewer_btn = QPushButton()
|
|
948
|
+
self.spot_viewer_btn.clicked.connect(self.spot_preview)
|
|
949
|
+
self.spot_viewer_btn.setIcon(icon(MDI6.image_check, color="k"))
|
|
950
|
+
self.spot_viewer_btn.setStyleSheet(self.button_select_all)
|
|
951
|
+
self.spot_viewer_btn.setToolTip('Set detection parameters visually.')
|
|
952
|
+
layout.addWidget(self.spot_viewer_btn, 1, 1, 1, 1, alignment=Qt.AlignRight)
|
|
953
|
+
|
|
954
|
+
self.spot_detection_widgets = [self.spot_channel, self.spot_channel_lbl, self.diameter_value, self.diameter_lbl, self.threshold_value, self.threshold_lbl, self.spot_viewer_btn]
|
|
955
|
+
for wg in self.spot_detection_widgets:
|
|
956
|
+
wg.setEnabled(False)
|
|
966
957
|
|
|
967
958
|
def enable_spot_preview(self):
|
|
968
959
|
|
|
969
960
|
diam = self.diameter_value.text().replace(',','').replace('.','')
|
|
970
961
|
thresh = self.threshold_value.text().replace(',','').replace('.','')
|
|
971
962
|
if diam.isnumeric() and thresh.isnumeric():
|
|
972
|
-
self.
|
|
963
|
+
self.spot_viewer_btn.setEnabled(True)
|
|
973
964
|
else:
|
|
974
|
-
self.
|
|
965
|
+
self.spot_viewer_btn.setEnabled(False)
|
|
975
966
|
|
|
976
967
|
def spot_preview(self):
|
|
977
968
|
self.locate_image()
|
|
978
969
|
if self.test_frame is not None:
|
|
979
970
|
self.locate_mask()
|
|
980
971
|
if self.test_mask is not None:
|
|
981
|
-
self.spot_visual =
|
|
982
|
-
|
|
972
|
+
self.spot_visual = SpotDetectionVisualizer(frame_slider=True,
|
|
973
|
+
contrast_slider=True,
|
|
974
|
+
cell_type=self.mode,
|
|
975
|
+
channel_cb=True,
|
|
976
|
+
channel_names = self.channel_names,
|
|
977
|
+
stack_path=self.current_stack,
|
|
978
|
+
n_channels=len(self.channel_names),
|
|
979
|
+
target_channel=self.spot_channel.currentIndex(),
|
|
980
|
+
window_title='Detect spots',
|
|
981
|
+
parent_channel_cb=self.spot_channel,
|
|
982
|
+
parent_diameter_le=self.diameter_value,
|
|
983
|
+
parent_threshold_le=self.threshold_value,
|
|
984
|
+
PxToUm = 1,)
|
|
985
|
+
self.spot_visual.show()
|
|
986
|
+
#self.spot_visual = ThresholdSpot(current_channel=self.spot_channel.currentIndex(), img=self.test_frame,
|
|
987
|
+
# mask=self.test_mask, parent_window=self)
|
|
983
988
|
|
|
984
989
|
def enable_spot_detection(self):
|
|
985
|
-
if self.spot_check.isChecked():
|
|
986
|
-
self.spot_channel.setEnabled(True)
|
|
987
|
-
self.spot_channel_lbl.setEnabled(True)
|
|
988
|
-
self.diameter_value.setEnabled(True)
|
|
989
|
-
self.diameter_lbl.setEnabled(True)
|
|
990
|
-
self.threshold_value.setEnabled(True)
|
|
991
|
-
self.threshold_lbl.setEnabled(True)
|
|
992
|
-
self.preview_spot.setEnabled(True)
|
|
993
990
|
|
|
991
|
+
if self.spot_check.isChecked():
|
|
992
|
+
for wg in self.spot_detection_widgets:
|
|
993
|
+
wg.setEnabled(True)
|
|
994
994
|
else:
|
|
995
|
-
self.
|
|
996
|
-
|
|
997
|
-
self.diameter_value.setEnabled(False)
|
|
998
|
-
self.diameter_lbl.setEnabled(False)
|
|
999
|
-
self.threshold_value.setEnabled(False)
|
|
1000
|
-
self.threshold_lbl.setEnabled(False)
|
|
1001
|
-
self.preview_spot.setEnabled(False)
|
|
995
|
+
for wg in self.spot_detection_widgets:
|
|
996
|
+
wg.setEnabled(False)
|
|
@@ -56,8 +56,8 @@ class ConfigMeasurementsPlot(QWidget,Styles):
|
|
|
56
56
|
|
|
57
57
|
print('Parent wells: ', self.wells)
|
|
58
58
|
|
|
59
|
-
self.well_option = self.parent_window.parent_window.well_list.
|
|
60
|
-
self.position_option = self.parent_window.parent_window.position_list.
|
|
59
|
+
self.well_option = self.parent_window.parent_window.well_list.getSelectedIndices()
|
|
60
|
+
self.position_option = self.parent_window.parent_window.position_list.getSelectedIndices()
|
|
61
61
|
self.interpret_pos_location()
|
|
62
62
|
# self.load_available_tables()
|
|
63
63
|
# self.config_path = self.exp_dir + self.config_name
|
|
@@ -526,18 +526,10 @@ class ConfigMeasurementsPlot(QWidget,Styles):
|
|
|
526
526
|
|
|
527
527
|
"""
|
|
528
528
|
|
|
529
|
-
self.well_option = self.parent_window.parent_window.well_list.
|
|
530
|
-
|
|
531
|
-
wo = '*'
|
|
532
|
-
else:
|
|
533
|
-
wo = self.well_option
|
|
534
|
-
self.position_option = self.parent_window.parent_window.position_list.currentIndex()
|
|
535
|
-
if self.position_option == 0:
|
|
536
|
-
po = '*'
|
|
537
|
-
else:
|
|
538
|
-
po = self.position_option - 1
|
|
529
|
+
self.well_option = self.parent_window.parent_window.well_list.getSelectedIndices()
|
|
530
|
+
self.position_option = self.parent_window.parent_window.position_list.getSelectedIndices()
|
|
539
531
|
|
|
540
|
-
self.df, self.df_pos_info = load_experiment_tables(self.exp_dir, well_option=
|
|
532
|
+
self.df, self.df_pos_info = load_experiment_tables(self.exp_dir, well_option=self.well_option, position_option=self.position_option,
|
|
541
533
|
population=self.cbs[0].currentText(), return_pos_info=True)
|
|
542
534
|
|
|
543
535
|
if self.df is None:
|
|
@@ -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:
|