celldetective 1.5.0b2__py3-none-any.whl → 1.5.0b4__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/_version.py +1 -1
- celldetective/gui/InitWindow.py +28 -11
- celldetective/gui/base/components.py +2 -0
- celldetective/gui/base_annotator.py +9 -2
- celldetective/gui/control_panel.py +21 -16
- celldetective/gui/gui_utils.py +14 -5
- celldetective/gui/measure_annotator.py +114 -18
- celldetective/gui/plot_measurements.py +2 -4
- celldetective/gui/plot_signals_ui.py +3 -4
- celldetective/gui/process_block.py +238 -66
- celldetective/gui/settings/_settings_segmentation_model_training.py +6 -0
- celldetective/gui/viewers/base_viewer.py +5 -0
- celldetective/utils/cellpose_utils/__init__.py +23 -7
- celldetective/utils/image_loaders.py +3 -0
- celldetective/utils/masks.py +1 -1
- {celldetective-1.5.0b2.dist-info → celldetective-1.5.0b4.dist-info}/METADATA +1 -1
- {celldetective-1.5.0b2.dist-info → celldetective-1.5.0b4.dist-info}/RECORD +25 -22
- tests/gui/test_enhancements.py +351 -0
- tests/gui/test_measure_annotator_bugfix.py +130 -0
- tests/test_cellpose_fallback.py +101 -0
- tests/test_notebooks.py +2 -1
- {celldetective-1.5.0b2.dist-info → celldetective-1.5.0b4.dist-info}/WHEEL +0 -0
- {celldetective-1.5.0b2.dist-info → celldetective-1.5.0b4.dist-info}/entry_points.txt +0 -0
- {celldetective-1.5.0b2.dist-info → celldetective-1.5.0b4.dist-info}/licenses/LICENSE +0 -0
- {celldetective-1.5.0b2.dist-info → celldetective-1.5.0b4.dist-info}/top_level.txt +0 -0
celldetective/_version.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = "1.5.
|
|
1
|
+
__version__ = "1.5.0b4"
|
celldetective/gui/InitWindow.py
CHANGED
|
@@ -325,14 +325,18 @@ class AppInitWindow(CelldetectiveMainWindow):
|
|
|
325
325
|
def reload_previous_experiments(self):
|
|
326
326
|
|
|
327
327
|
self.recent_file_acts = []
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
recent_exps = recent_exps.readlines()
|
|
333
|
-
recent_exps = [r.strip() for r in recent_exps]
|
|
328
|
+
recent_path = os.sep.join([self.soft_path, "celldetective", "recent.txt"])
|
|
329
|
+
if os.path.exists(recent_path):
|
|
330
|
+
with open(recent_path, "r") as f:
|
|
331
|
+
recent_exps = [r.strip() for r in f.readlines()]
|
|
334
332
|
recent_exps.reverse()
|
|
335
|
-
recent_exps = list(dict.fromkeys(recent_exps))
|
|
333
|
+
recent_exps = list(dict.fromkeys(recent_exps))[:10]
|
|
334
|
+
|
|
335
|
+
# Auto-clean the file as well
|
|
336
|
+
with open(recent_path, "w") as f:
|
|
337
|
+
for r in reversed(recent_exps):
|
|
338
|
+
f.write(r + "\n")
|
|
339
|
+
|
|
336
340
|
self.recent_file_acts = [QAction(r, self) for r in recent_exps]
|
|
337
341
|
for r in self.recent_file_acts:
|
|
338
342
|
r.triggered.connect(
|
|
@@ -525,10 +529,23 @@ class AppInitWindow(CelldetectiveMainWindow):
|
|
|
525
529
|
logger.info(f"Number of positions per well:")
|
|
526
530
|
pretty_table(number_pos)
|
|
527
531
|
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
)
|
|
531
|
-
|
|
532
|
+
recent_path = os.sep.join(
|
|
533
|
+
[self.soft_path, "celldetective", "recent.txt"]
|
|
534
|
+
)
|
|
535
|
+
recent_exps = []
|
|
536
|
+
if os.path.exists(recent_path):
|
|
537
|
+
with open(recent_path, "r") as f:
|
|
538
|
+
recent_exps = [r.strip() for r in f.readlines()]
|
|
539
|
+
|
|
540
|
+
recent_exps.append(self.exp_dir)
|
|
541
|
+
# Deduplicate (keep latest)
|
|
542
|
+
recent_exps = list(dict.fromkeys(reversed(recent_exps)))
|
|
543
|
+
recent_exps.reverse() # Back to original order (latest at end)
|
|
544
|
+
recent_exps = recent_exps[-10:] # Keep only last 10
|
|
545
|
+
|
|
546
|
+
with open(recent_path, "w") as f:
|
|
547
|
+
for r in recent_exps:
|
|
548
|
+
f.write(r + "\n")
|
|
532
549
|
|
|
533
550
|
threading.Thread(
|
|
534
551
|
target=log_position_stats, args=(wells,), daemon=True
|
|
@@ -120,6 +120,8 @@ class QCheckableComboBox(QComboBox):
|
|
|
120
120
|
actions = self.toolMenu.actions()
|
|
121
121
|
|
|
122
122
|
item = self.model().itemFromIndex(index)
|
|
123
|
+
if item is None:
|
|
124
|
+
return
|
|
123
125
|
if item.checkState() == Qt.Checked:
|
|
124
126
|
item.setCheckState(Qt.Unchecked)
|
|
125
127
|
actions[idx].setChecked(False)
|
|
@@ -305,7 +305,11 @@ class BaseAnnotator(CelldetectiveMainWindow, Styles):
|
|
|
305
305
|
]
|
|
306
306
|
# self.log_btns = [QPushButton() for i in range(self.n_signals)]
|
|
307
307
|
|
|
308
|
-
signals =
|
|
308
|
+
signals = [
|
|
309
|
+
c
|
|
310
|
+
for c in self.df_tracks.columns
|
|
311
|
+
if pd.api.types.is_numeric_dtype(self.df_tracks[c])
|
|
312
|
+
]
|
|
309
313
|
|
|
310
314
|
to_remove = [
|
|
311
315
|
"FRAME",
|
|
@@ -357,7 +361,10 @@ class BaseAnnotator(CelldetectiveMainWindow, Styles):
|
|
|
357
361
|
|
|
358
362
|
for i in range(len(self.signal_choice_cb)):
|
|
359
363
|
self.signal_choice_cb[i].addItems(["--"] + signals)
|
|
360
|
-
self.signal_choice_cb[i].
|
|
364
|
+
if i + 1 < self.signal_choice_cb[i].count():
|
|
365
|
+
self.signal_choice_cb[i].setCurrentIndex(i + 1)
|
|
366
|
+
else:
|
|
367
|
+
self.signal_choice_cb[i].setCurrentIndex(0)
|
|
361
368
|
self.signal_choice_cb[i].currentIndexChanged.connect(self.plot_signals)
|
|
362
369
|
|
|
363
370
|
def on_scatter_pick(self, event):
|
|
@@ -58,14 +58,15 @@ logger = logging.getLogger(__name__)
|
|
|
58
58
|
|
|
59
59
|
|
|
60
60
|
class BackgroundLoader(QThread):
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
61
|
+
def run(self):
|
|
62
|
+
logger.info("Loading background packages...")
|
|
63
|
+
try:
|
|
64
|
+
from celldetective.gui.viewers.base_viewer import StackVisualizer
|
|
65
|
+
|
|
66
|
+
self.StackVisualizer = StackVisualizer
|
|
67
|
+
except Exception:
|
|
68
|
+
logger.error("Background packages not loaded...")
|
|
69
|
+
logger.info("Background packages loaded...")
|
|
69
70
|
|
|
70
71
|
|
|
71
72
|
class ControlPanel(CelldetectiveMainWindow):
|
|
@@ -179,9 +180,11 @@ class ControlPanel(CelldetectiveMainWindow):
|
|
|
179
180
|
|
|
180
181
|
name = self.exp_dir.split(os.sep)[-2]
|
|
181
182
|
experiment_label = QLabel(f"Experiment:")
|
|
182
|
-
experiment_label.setStyleSheet(
|
|
183
|
+
experiment_label.setStyleSheet(
|
|
184
|
+
"""
|
|
183
185
|
font-weight: bold;
|
|
184
|
-
"""
|
|
186
|
+
"""
|
|
187
|
+
)
|
|
185
188
|
|
|
186
189
|
self.folder_exp_btn = QPushButton()
|
|
187
190
|
self.folder_exp_btn.setIcon(icon(MDI6.folder, color="black"))
|
|
@@ -553,16 +556,18 @@ class ControlPanel(CelldetectiveMainWindow):
|
|
|
553
556
|
for p in self.ProcessPopulations:
|
|
554
557
|
p.check_seg_btn.setEnabled(False)
|
|
555
558
|
p.check_tracking_result_btn.setEnabled(False)
|
|
556
|
-
p.view_tab_btn.setEnabled(
|
|
557
|
-
p.signal_analysis_action.setEnabled(
|
|
559
|
+
p.view_tab_btn.setEnabled(self.position_list.isAnySelected())
|
|
560
|
+
p.signal_analysis_action.setEnabled(self.position_list.isAnySelected())
|
|
558
561
|
p.check_seg_btn.setEnabled(False)
|
|
559
562
|
p.check_tracking_result_btn.setEnabled(False)
|
|
560
|
-
p.check_measurements_btn.setEnabled(
|
|
561
|
-
p.check_signals_btn.setEnabled(
|
|
563
|
+
p.check_measurements_btn.setEnabled(self.position_list.isAnySelected())
|
|
564
|
+
p.check_signals_btn.setEnabled(self.position_list.isAnySelected())
|
|
562
565
|
p.delete_tracks_btn.hide()
|
|
563
566
|
|
|
564
|
-
self.NeighPanel.view_tab_btn.setEnabled(
|
|
565
|
-
self.NeighPanel.check_signals_btn.setEnabled(
|
|
567
|
+
self.NeighPanel.view_tab_btn.setEnabled(self.position_list.isAnySelected())
|
|
568
|
+
self.NeighPanel.check_signals_btn.setEnabled(
|
|
569
|
+
self.position_list.isAnySelected()
|
|
570
|
+
)
|
|
566
571
|
self.view_stack_btn.setEnabled(False)
|
|
567
572
|
|
|
568
573
|
elif self.well_list.isMultipleSelection():
|
celldetective/gui/gui_utils.py
CHANGED
|
@@ -822,10 +822,15 @@ def color_from_state(state, recently_modified=False):
|
|
|
822
822
|
color_map = {}
|
|
823
823
|
for value in unique_values:
|
|
824
824
|
|
|
825
|
-
|
|
826
|
-
value
|
|
827
|
-
|
|
828
|
-
|
|
825
|
+
try:
|
|
826
|
+
if np.isnan(value):
|
|
827
|
+
value = "nan"
|
|
828
|
+
color_map[value] = "k"
|
|
829
|
+
continue
|
|
830
|
+
except TypeError:
|
|
831
|
+
pass
|
|
832
|
+
|
|
833
|
+
if value == 0:
|
|
829
834
|
color_map[value] = "tab:blue"
|
|
830
835
|
elif value == 1:
|
|
831
836
|
color_map[value] = "tab:red"
|
|
@@ -834,7 +839,11 @@ def color_from_state(state, recently_modified=False):
|
|
|
834
839
|
else:
|
|
835
840
|
import matplotlib.pyplot as plt
|
|
836
841
|
|
|
837
|
-
|
|
842
|
+
if isinstance(value, (int, float, np.number)):
|
|
843
|
+
idx = value
|
|
844
|
+
else:
|
|
845
|
+
idx = hash(str(value)) % 20
|
|
846
|
+
color_map[value] = plt.cm.tab20(idx / 20.0)
|
|
838
847
|
|
|
839
848
|
return color_map
|
|
840
849
|
|
|
@@ -101,6 +101,7 @@ class MeasureAnnotator(BaseAnnotator):
|
|
|
101
101
|
|
|
102
102
|
def __init__(self, *args, **kwargs):
|
|
103
103
|
|
|
104
|
+
self.status_name = "group"
|
|
104
105
|
super().__init__(read_config=False, *args, **kwargs)
|
|
105
106
|
|
|
106
107
|
self.setWindowTitle("Static annotator")
|
|
@@ -115,17 +116,21 @@ class MeasureAnnotator(BaseAnnotator):
|
|
|
115
116
|
|
|
116
117
|
self.current_frame = 0
|
|
117
118
|
self.show_fliers = False
|
|
118
|
-
self.status_name = "group"
|
|
119
119
|
|
|
120
120
|
if self.proceed:
|
|
121
121
|
|
|
122
122
|
from celldetective.utils.image_loaders import fix_missing_labels
|
|
123
|
+
from celldetective.tracking import write_first_detection_class
|
|
123
124
|
|
|
124
125
|
# Ensure labels match stack length
|
|
125
126
|
if self.len_movie > 0:
|
|
126
127
|
temp_labels = locate_labels(self.pos, population=self.mode)
|
|
127
128
|
if temp_labels is None or len(temp_labels) < self.len_movie:
|
|
128
|
-
fix_missing_labels(
|
|
129
|
+
fix_missing_labels(
|
|
130
|
+
self.pos,
|
|
131
|
+
population=self.mode,
|
|
132
|
+
prefix=self.parent_window.movie_prefix,
|
|
133
|
+
)
|
|
129
134
|
self.labels = locate_labels(self.pos, population=self.mode)
|
|
130
135
|
elif len(temp_labels) > self.len_movie:
|
|
131
136
|
self.labels = temp_labels[: self.len_movie]
|
|
@@ -174,13 +179,62 @@ class MeasureAnnotator(BaseAnnotator):
|
|
|
174
179
|
cols = np.array(self.df_tracks.columns)
|
|
175
180
|
self.class_cols = np.array(
|
|
176
181
|
[
|
|
177
|
-
c.startswith("group")
|
|
182
|
+
c.startswith("group")
|
|
183
|
+
or c.startswith("class")
|
|
184
|
+
or c.startswith("status")
|
|
178
185
|
for c in list(self.df_tracks.columns)
|
|
179
186
|
]
|
|
180
187
|
)
|
|
181
188
|
self.class_cols = list(cols[self.class_cols])
|
|
182
189
|
|
|
183
|
-
to_remove = [
|
|
190
|
+
to_remove = [
|
|
191
|
+
"class_id",
|
|
192
|
+
"group_color",
|
|
193
|
+
"class_color",
|
|
194
|
+
"group_id",
|
|
195
|
+
"status_color",
|
|
196
|
+
"status_id",
|
|
197
|
+
]
|
|
198
|
+
for col in to_remove:
|
|
199
|
+
try:
|
|
200
|
+
self.class_cols.remove(col)
|
|
201
|
+
except:
|
|
202
|
+
pass
|
|
203
|
+
|
|
204
|
+
# Generate missing status columns from class columns
|
|
205
|
+
for c in self.class_cols:
|
|
206
|
+
if c.startswith("class_"):
|
|
207
|
+
status_col = c.replace("class_", "status_")
|
|
208
|
+
if status_col not in self.df_tracks.columns:
|
|
209
|
+
if (
|
|
210
|
+
status_col == "status_firstdetection"
|
|
211
|
+
or c == "class_firstdetection"
|
|
212
|
+
):
|
|
213
|
+
try:
|
|
214
|
+
from celldetective.tracking import (
|
|
215
|
+
write_first_detection_class,
|
|
216
|
+
)
|
|
217
|
+
|
|
218
|
+
self.df_tracks = write_first_detection_class(
|
|
219
|
+
self.df_tracks
|
|
220
|
+
)
|
|
221
|
+
except Exception as e:
|
|
222
|
+
logger.error(
|
|
223
|
+
f"Could not generate status_firstdetection: {e}"
|
|
224
|
+
)
|
|
225
|
+
self.df_tracks[status_col] = self.df_tracks[c]
|
|
226
|
+
else:
|
|
227
|
+
self.df_tracks[status_col] = self.df_tracks[c]
|
|
228
|
+
|
|
229
|
+
# Re-evaluate class_cols after generation
|
|
230
|
+
cols = np.array(self.df_tracks.columns)
|
|
231
|
+
self.class_cols = np.array(
|
|
232
|
+
[
|
|
233
|
+
c.startswith("group") or c.startswith("status")
|
|
234
|
+
for c in list(self.df_tracks.columns)
|
|
235
|
+
]
|
|
236
|
+
)
|
|
237
|
+
self.class_cols = list(cols[self.class_cols])
|
|
184
238
|
for col in to_remove:
|
|
185
239
|
try:
|
|
186
240
|
self.class_cols.remove(col)
|
|
@@ -188,7 +242,8 @@ class MeasureAnnotator(BaseAnnotator):
|
|
|
188
242
|
pass
|
|
189
243
|
|
|
190
244
|
if len(self.class_cols) > 0:
|
|
191
|
-
self.status_name
|
|
245
|
+
if self.status_name not in self.class_cols:
|
|
246
|
+
self.status_name = self.class_cols[0]
|
|
192
247
|
else:
|
|
193
248
|
self.status_name = "group"
|
|
194
249
|
|
|
@@ -335,7 +390,13 @@ class MeasureAnnotator(BaseAnnotator):
|
|
|
335
390
|
cols = np.array(self.df_tracks.columns)
|
|
336
391
|
self.class_cols = np.array(
|
|
337
392
|
[
|
|
338
|
-
c.startswith("group")
|
|
393
|
+
c.startswith("group")
|
|
394
|
+
or c.startswith("status")
|
|
395
|
+
or (
|
|
396
|
+
c.startswith("class")
|
|
397
|
+
and not c.endswith("_id")
|
|
398
|
+
and not c.endswith("_color")
|
|
399
|
+
)
|
|
339
400
|
for c in list(self.df_tracks.columns)
|
|
340
401
|
]
|
|
341
402
|
)
|
|
@@ -347,14 +408,23 @@ class MeasureAnnotator(BaseAnnotator):
|
|
|
347
408
|
"class_id",
|
|
348
409
|
"class_color",
|
|
349
410
|
"status_color",
|
|
411
|
+
"status_id",
|
|
350
412
|
]
|
|
351
413
|
for col in to_remove:
|
|
352
|
-
|
|
414
|
+
while col in self.class_cols:
|
|
353
415
|
self.class_cols.remove(col)
|
|
354
|
-
|
|
355
|
-
|
|
416
|
+
|
|
417
|
+
# Filter to keep only group_* and status_* as requested by user, but allow 'group' if it exists
|
|
418
|
+
final_cols = []
|
|
419
|
+
for c in self.class_cols:
|
|
420
|
+
if c == "group" or c.startswith("group_") or c.startswith("status_"):
|
|
421
|
+
final_cols.append(c)
|
|
422
|
+
|
|
423
|
+
self.class_cols = final_cols
|
|
356
424
|
|
|
357
425
|
self.class_choice_cb.addItems(self.class_cols)
|
|
426
|
+
if self.status_name in self.class_cols:
|
|
427
|
+
self.class_choice_cb.setCurrentText(self.status_name)
|
|
358
428
|
self.class_choice_cb.currentIndexChanged.connect(self.changed_class)
|
|
359
429
|
|
|
360
430
|
def populate_window(self):
|
|
@@ -678,13 +748,30 @@ class MeasureAnnotator(BaseAnnotator):
|
|
|
678
748
|
|
|
679
749
|
try:
|
|
680
750
|
cell_selected = f"cell: {self.track_of_interest}\n"
|
|
681
|
-
if
|
|
682
|
-
|
|
751
|
+
if self.status_name in self.df_tracks.columns:
|
|
752
|
+
if "TRACK_ID" in self.df_tracks.columns:
|
|
753
|
+
val = self.df_tracks.loc[
|
|
754
|
+
(self.df_tracks["FRAME"] == self.current_frame)
|
|
755
|
+
& (self.df_tracks["TRACK_ID"] == self.track_of_interest),
|
|
756
|
+
self.status_name,
|
|
757
|
+
].to_numpy()
|
|
758
|
+
if len(val) > 0:
|
|
759
|
+
cell_status = f"phenotype: {val[0]}\n"
|
|
760
|
+
else:
|
|
761
|
+
cell_status = "phenotype: N/A\n"
|
|
762
|
+
else:
|
|
763
|
+
val = self.df_tracks.loc[
|
|
764
|
+
self.df_tracks["ID"] == self.track_of_interest, self.status_name
|
|
765
|
+
].to_numpy()
|
|
766
|
+
if len(val) > 0:
|
|
767
|
+
cell_status = f"phenotype: {val[0]}\n"
|
|
768
|
+
else:
|
|
769
|
+
cell_status = "phenotype: N/A\n"
|
|
683
770
|
else:
|
|
684
|
-
cell_status = f"phenotype: {self.
|
|
771
|
+
cell_status = f"phenotype: N/A (col '{self.status_name}' missing)\n"
|
|
685
772
|
self.cell_info.setText(cell_selected + cell_status)
|
|
686
773
|
except Exception as e:
|
|
687
|
-
logger.error(e)
|
|
774
|
+
logger.error(f"Error in give_cell_information: {e}")
|
|
688
775
|
|
|
689
776
|
def create_new_event_class(self):
|
|
690
777
|
|
|
@@ -772,8 +859,11 @@ class MeasureAnnotator(BaseAnnotator):
|
|
|
772
859
|
|
|
773
860
|
def assign_color_state(self, state):
|
|
774
861
|
|
|
775
|
-
|
|
776
|
-
state
|
|
862
|
+
try:
|
|
863
|
+
if np.isnan(state):
|
|
864
|
+
state = "nan"
|
|
865
|
+
except TypeError:
|
|
866
|
+
pass
|
|
777
867
|
return self.state_color_map[state]
|
|
778
868
|
|
|
779
869
|
def on_scatter_pick(self, event):
|
|
@@ -860,9 +950,9 @@ class MeasureAnnotator(BaseAnnotator):
|
|
|
860
950
|
].to_numpy()
|
|
861
951
|
)
|
|
862
952
|
self.colors.append(
|
|
863
|
-
self.df_tracks.loc[
|
|
864
|
-
|
|
865
|
-
|
|
953
|
+
self.df_tracks.loc[self.df_tracks["FRAME"] == t, ["group_color"]]
|
|
954
|
+
.to_numpy()
|
|
955
|
+
.copy()
|
|
866
956
|
)
|
|
867
957
|
if "TRACK_ID" in self.df_tracks.columns:
|
|
868
958
|
self.tracks.append(
|
|
@@ -945,6 +1035,12 @@ class MeasureAnnotator(BaseAnnotator):
|
|
|
945
1035
|
self.changed_class()
|
|
946
1036
|
|
|
947
1037
|
def modify(self):
|
|
1038
|
+
if self.status_name not in self.df_tracks.columns:
|
|
1039
|
+
logger.warning(
|
|
1040
|
+
f"Column '{self.status_name}' not found in df_tracks. Skipping modify."
|
|
1041
|
+
)
|
|
1042
|
+
return
|
|
1043
|
+
|
|
948
1044
|
all_states = self.df_tracks.loc[:, self.status_name].tolist()
|
|
949
1045
|
all_states = np.array(all_states)
|
|
950
1046
|
self.state_color_map = color_from_state(all_states, recently_modified=False)
|
|
@@ -263,8 +263,7 @@ class ConfigMeasurementsPlot(CelldetectiveWidget):
|
|
|
263
263
|
def ask_for_feature(self):
|
|
264
264
|
|
|
265
265
|
cols = np.array(list(self.df.columns))
|
|
266
|
-
|
|
267
|
-
feats = cols[is_number(self.df.dtypes)]
|
|
266
|
+
feats = [c for c in cols if pd.api.types.is_numeric_dtype(self.df[c])]
|
|
268
267
|
|
|
269
268
|
self.feature_choice_widget = CelldetectiveWidget()
|
|
270
269
|
self.feature_choice_widget.setWindowTitle("Select numeric feature")
|
|
@@ -286,8 +285,7 @@ class ConfigMeasurementsPlot(CelldetectiveWidget):
|
|
|
286
285
|
def ask_for_features(self):
|
|
287
286
|
|
|
288
287
|
cols = np.array(list(self.df.columns))
|
|
289
|
-
|
|
290
|
-
feats = cols[is_number(self.df.dtypes)]
|
|
288
|
+
feats = [c for c in cols if pd.api.types.is_numeric_dtype(self.df[c])]
|
|
291
289
|
|
|
292
290
|
self.feature_choice_widget = CelldetectiveWidget()
|
|
293
291
|
self.feature_choice_widget.setWindowTitle("Select numeric feature")
|
|
@@ -21,6 +21,7 @@ from celldetective.utils.data_cleaning import extract_cols_from_table_list
|
|
|
21
21
|
from celldetective.utils.parsing import _extract_labels_from_config
|
|
22
22
|
from celldetective.utils.data_loaders import load_experiment_tables
|
|
23
23
|
from celldetective.signals import mean_signal
|
|
24
|
+
import pandas as pd
|
|
24
25
|
import numpy as np
|
|
25
26
|
import os
|
|
26
27
|
import matplotlib.pyplot as plt
|
|
@@ -377,8 +378,7 @@ class ConfigSignalPlot(CelldetectiveWidget):
|
|
|
377
378
|
def ask_for_feature(self):
|
|
378
379
|
|
|
379
380
|
cols = np.array(list(self.df.columns))
|
|
380
|
-
|
|
381
|
-
feats = cols[is_number(self.df.dtypes)]
|
|
381
|
+
feats = [c for c in cols if pd.api.types.is_numeric_dtype(self.df[c])]
|
|
382
382
|
|
|
383
383
|
self.feature_choice_widget = CelldetectiveWidget()
|
|
384
384
|
self.feature_choice_widget.setWindowTitle("Select numeric feature")
|
|
@@ -400,8 +400,7 @@ class ConfigSignalPlot(CelldetectiveWidget):
|
|
|
400
400
|
def ask_for_features(self):
|
|
401
401
|
|
|
402
402
|
cols = np.array(list(self.df.columns))
|
|
403
|
-
|
|
404
|
-
feats = cols[is_number(self.df.dtypes)]
|
|
403
|
+
feats = [c for c in cols if pd.api.types.is_numeric_dtype(self.df[c])]
|
|
405
404
|
|
|
406
405
|
self.feature_choice_widget = CelldetectiveWidget()
|
|
407
406
|
self.feature_choice_widget.setWindowTitle("Select numeric feature")
|