celldetective 1.5.0b7__py3-none-any.whl → 1.5.0b9__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/event_detection_models.py +2463 -0
- celldetective/gui/base/channel_norm_generator.py +19 -3
- celldetective/gui/base/figure_canvas.py +1 -1
- celldetective/gui/base/list_widget.py +1 -1
- celldetective/gui/base_annotator.py +2 -5
- celldetective/gui/event_annotator.py +248 -138
- celldetective/gui/generic_signal_plot.py +14 -14
- celldetective/gui/gui_utils.py +27 -6
- celldetective/gui/pair_event_annotator.py +146 -20
- celldetective/gui/plot_signals_ui.py +32 -15
- celldetective/gui/process_block.py +2 -2
- celldetective/gui/seg_model_loader.py +4 -4
- celldetective/gui/settings/_settings_event_model_training.py +32 -14
- celldetective/gui/settings/_settings_segmentation_model_training.py +5 -5
- celldetective/gui/settings/_settings_signal_annotator.py +0 -19
- celldetective/gui/survival_ui.py +39 -11
- celldetective/gui/tableUI.py +69 -148
- celldetective/gui/thresholds_gui.py +45 -5
- celldetective/gui/viewers/base_viewer.py +17 -20
- celldetective/gui/viewers/spot_detection_viewer.py +136 -27
- celldetective/processes/train_signal_model.py +1 -1
- celldetective/scripts/train_signal_model.py +1 -1
- celldetective/signals.py +4 -2426
- celldetective/utils/event_detection/__init__.py +1 -1
- {celldetective-1.5.0b7.dist-info → celldetective-1.5.0b9.dist-info}/METADATA +1 -1
- {celldetective-1.5.0b7.dist-info → celldetective-1.5.0b9.dist-info}/RECORD +33 -31
- tests/gui/test_spot_detection_viewer.py +187 -0
- tests/test_signals.py +135 -116
- {celldetective-1.5.0b7.dist-info → celldetective-1.5.0b9.dist-info}/WHEEL +0 -0
- {celldetective-1.5.0b7.dist-info → celldetective-1.5.0b9.dist-info}/entry_points.txt +0 -0
- {celldetective-1.5.0b7.dist-info → celldetective-1.5.0b9.dist-info}/licenses/LICENSE +0 -0
- {celldetective-1.5.0b7.dist-info → celldetective-1.5.0b9.dist-info}/top_level.txt +0 -0
|
@@ -417,8 +417,7 @@ class SettingsEventDetectionModelTraining(CelldetectiveSettingsPanel):
|
|
|
417
417
|
self.signals = ["--"] + num_cols_pairs + num_cols_reference + num_cols_neighbor
|
|
418
418
|
|
|
419
419
|
for cb in self.ch_norm.channel_cbs:
|
|
420
|
-
cb.
|
|
421
|
-
cb.addItems(self.signals)
|
|
420
|
+
self.ch_norm.add_items_truncated(cb, self.signals)
|
|
422
421
|
|
|
423
422
|
def fill_available_neighborhoods(self):
|
|
424
423
|
|
|
@@ -541,15 +540,36 @@ class SettingsEventDetectionModelTraining(CelldetectiveSettingsPanel):
|
|
|
541
540
|
self.model_length_slider.setValue(int(signal_length))
|
|
542
541
|
self.model_length_slider.setEnabled(False)
|
|
543
542
|
|
|
544
|
-
|
|
545
|
-
|
|
543
|
+
try:
|
|
544
|
+
norm_perc = data["normalization_percentile"]
|
|
545
|
+
if isinstance(norm_perc, bool):
|
|
546
|
+
norm_perc = [norm_perc] * len(channels)
|
|
547
|
+
norm_val = data["normalization_values"]
|
|
548
|
+
if len(norm_val) == 2 and isinstance(norm_val[0], float):
|
|
549
|
+
norm_val = [norm_val] * len(channels)
|
|
550
|
+
norm_clip = data["normalization_clip"]
|
|
551
|
+
if isinstance(norm_clip, bool):
|
|
552
|
+
norm_clip = [norm_clip] * len(channels)
|
|
553
|
+
except Exception:
|
|
554
|
+
norm_perc = [True] * len(channels)
|
|
555
|
+
norm_val = [[0.1, 99.99]] * len(channels)
|
|
556
|
+
norm_clip = [False] * len(channels)
|
|
557
|
+
|
|
558
|
+
for k, (c, cb) in enumerate(zip(channels, self.ch_norm.channel_cbs)):
|
|
559
|
+
index = cb.findData(c)
|
|
546
560
|
cb.setCurrentIndex(index)
|
|
547
561
|
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
self.ch_norm.
|
|
551
|
-
|
|
552
|
-
|
|
562
|
+
# Set normalization mode
|
|
563
|
+
if self.ch_norm.normalization_mode[k] != norm_perc[k]:
|
|
564
|
+
self.ch_norm.switch_normalization_mode(k)
|
|
565
|
+
|
|
566
|
+
# Set clipping mode
|
|
567
|
+
if self.ch_norm.clip_option[k] != norm_clip[k]:
|
|
568
|
+
self.ch_norm.switch_clipping_mode(k)
|
|
569
|
+
|
|
570
|
+
# Set normalization values
|
|
571
|
+
self.ch_norm.normalization_min_value_le[k].setText(str(norm_val[k][0]))
|
|
572
|
+
self.ch_norm.normalization_max_value_le[k].setText(str(norm_val[k][1]))
|
|
553
573
|
|
|
554
574
|
def adjust_scroll_area(self):
|
|
555
575
|
"""
|
|
@@ -581,7 +601,7 @@ class SettingsEventDetectionModelTraining(CelldetectiveSettingsPanel):
|
|
|
581
601
|
|
|
582
602
|
channels = []
|
|
583
603
|
for i in range(len(self.ch_norm.channel_cbs)):
|
|
584
|
-
channels.append(self.ch_norm.channel_cbs[i].
|
|
604
|
+
channels.append(self.ch_norm.channel_cbs[i].currentData())
|
|
585
605
|
|
|
586
606
|
slots_to_keep = np.where(np.array(channels) != "--")[0]
|
|
587
607
|
while "--" in channels:
|
|
@@ -750,10 +770,8 @@ class SettingsEventDetectionModelTraining(CelldetectiveSettingsPanel):
|
|
|
750
770
|
|
|
751
771
|
# Assuming signal/event models directory. Verifying path would be better but this fits pattern.
|
|
752
772
|
# If exact attribute unknown, use os.path.dirname logic or config methods.
|
|
753
|
-
# Safe bet: self.
|
|
754
|
-
model_path = os.path.join(
|
|
755
|
-
self.parent_window.signal_models_dir, self.modelname_le.text()
|
|
756
|
-
)
|
|
773
|
+
# Safe bet: self.signal_models_dir based on init.
|
|
774
|
+
model_path = os.path.join(self.signal_models_dir, self.modelname_le.text())
|
|
757
775
|
if os.path.exists(model_path):
|
|
758
776
|
time.sleep(0.5)
|
|
759
777
|
shutil.rmtree(model_path)
|
|
@@ -355,7 +355,7 @@ class SettingsSegmentationModelTraining(CelldetectiveSettingsPanel):
|
|
|
355
355
|
not current_name in models
|
|
356
356
|
and not self.spatial_calib_le.text() == ""
|
|
357
357
|
and not np.all(
|
|
358
|
-
[cb.
|
|
358
|
+
[cb.currentData() == "--" for cb in self.ch_norm.channel_cbs]
|
|
359
359
|
)
|
|
360
360
|
):
|
|
361
361
|
self.submit_btn.setEnabled(True)
|
|
@@ -370,7 +370,7 @@ class SettingsSegmentationModelTraining(CelldetectiveSettingsPanel):
|
|
|
370
370
|
self.submit_warning.setText(
|
|
371
371
|
"Please provide a valid spatial calibration..."
|
|
372
372
|
)
|
|
373
|
-
elif np.all([cb.
|
|
373
|
+
elif np.all([cb.currentData() == "--" for cb in self.ch_norm.channel_cbs]):
|
|
374
374
|
self.submit_warning.setText("Please provide valid channels...")
|
|
375
375
|
|
|
376
376
|
def rescale_slider(self):
|
|
@@ -459,7 +459,7 @@ class SettingsSegmentationModelTraining(CelldetectiveSettingsPanel):
|
|
|
459
459
|
|
|
460
460
|
for k in range(len(self.diamWidget.cellpose_channel_cb)):
|
|
461
461
|
ch = self.diamWidget.cellpose_channel_cb[k].currentText()
|
|
462
|
-
idx = self.ch_norm.channel_cbs[k].
|
|
462
|
+
idx = self.ch_norm.channel_cbs[k].findData(ch)
|
|
463
463
|
self.ch_norm.channel_cbs[k].setCurrentIndex(idx)
|
|
464
464
|
|
|
465
465
|
self.diamWidget.close()
|
|
@@ -561,7 +561,7 @@ class SettingsSegmentationModelTraining(CelldetectiveSettingsPanel):
|
|
|
561
561
|
self.cellpose_model.setChecked(True)
|
|
562
562
|
|
|
563
563
|
for c, cb in zip(channels, self.ch_norm.channel_cbs):
|
|
564
|
-
index = cb.
|
|
564
|
+
index = cb.findData(c)
|
|
565
565
|
cb.setCurrentIndex(index)
|
|
566
566
|
|
|
567
567
|
for i in range(len(channels)):
|
|
@@ -622,7 +622,7 @@ class SettingsSegmentationModelTraining(CelldetectiveSettingsPanel):
|
|
|
622
622
|
|
|
623
623
|
channels = []
|
|
624
624
|
for i in range(len(self.ch_norm.channel_cbs)):
|
|
625
|
-
channels.append(self.ch_norm.channel_cbs[i].
|
|
625
|
+
channels.append(self.ch_norm.channel_cbs[i].currentData())
|
|
626
626
|
|
|
627
627
|
slots_to_keep = np.where(np.array(channels) != "--")[0]
|
|
628
628
|
while "--" in channels:
|
|
@@ -100,11 +100,6 @@ class SettingsSignalAnnotator(CelldetectiveSettingsPanel):
|
|
|
100
100
|
hbox_frac.addWidget(self.fraction_slider, 80)
|
|
101
101
|
sub_layout.addLayout(hbox_frac)
|
|
102
102
|
|
|
103
|
-
hbox_interval = QHBoxLayout()
|
|
104
|
-
hbox_interval.addWidget(self._interval_lbl, 20)
|
|
105
|
-
hbox_interval.addWidget(self.interval_slider, 80)
|
|
106
|
-
sub_layout.addLayout(hbox_interval)
|
|
107
|
-
|
|
108
103
|
self._layout.addLayout(sub_layout)
|
|
109
104
|
|
|
110
105
|
self._layout.addWidget(self.submit_btn)
|
|
@@ -118,7 +113,6 @@ class SettingsSignalAnnotator(CelldetectiveSettingsPanel):
|
|
|
118
113
|
|
|
119
114
|
self._modality_lbl = QLabel("Modality: ")
|
|
120
115
|
self._fraction_lbl = QLabel("fraction: ")
|
|
121
|
-
self._interval_lbl = QLabel("interval [ms]: ")
|
|
122
116
|
|
|
123
117
|
self.gs_btn = QRadioButton("grayscale")
|
|
124
118
|
self.gs_btn.setChecked(True)
|
|
@@ -173,14 +167,6 @@ class SettingsSignalAnnotator(CelldetectiveSettingsPanel):
|
|
|
173
167
|
self.fraction_slider.setRange(0.1, 1)
|
|
174
168
|
self.fraction_slider.setValue(0.25)
|
|
175
169
|
|
|
176
|
-
self.interval_slider = QLabeledSlider()
|
|
177
|
-
self.interval_slider.setSingleStep(1)
|
|
178
|
-
self.interval_slider.setTickInterval(1)
|
|
179
|
-
self.interval_slider.setSingleStep(1)
|
|
180
|
-
self.interval_slider.setOrientation(Qt.Horizontal)
|
|
181
|
-
self.interval_slider.setRange(1, 1000)
|
|
182
|
-
self.interval_slider.setValue(1)
|
|
183
|
-
|
|
184
170
|
def enable_channels(self):
|
|
185
171
|
"""
|
|
186
172
|
Enable three channels when RGB mode is checked.
|
|
@@ -255,7 +241,6 @@ class SettingsSignalAnnotator(CelldetectiveSettingsPanel):
|
|
|
255
241
|
"rgb_mode": self.rgb_btn.isChecked(),
|
|
256
242
|
"percentile_mode": self.percentile_mode,
|
|
257
243
|
"fraction": float(self.fraction_slider.value()),
|
|
258
|
-
"interval": int(self.interval_slider.value()),
|
|
259
244
|
"log": self.log_option,
|
|
260
245
|
}
|
|
261
246
|
max_i = 3 if self.rgb_btn.isChecked() else 1
|
|
@@ -322,10 +307,6 @@ class SettingsSignalAnnotator(CelldetectiveSettingsPanel):
|
|
|
322
307
|
fraction = instructions["fraction"]
|
|
323
308
|
self.fraction_slider.setValue(fraction)
|
|
324
309
|
|
|
325
|
-
if "interval" in instructions:
|
|
326
|
-
interval = instructions["interval"]
|
|
327
|
-
self.interval_slider.setValue(interval)
|
|
328
|
-
|
|
329
310
|
if "log" in instructions:
|
|
330
311
|
self.log_option = not instructions["log"]
|
|
331
312
|
self.switch_to_log()
|
celldetective/gui/survival_ui.py
CHANGED
|
@@ -19,11 +19,13 @@ from celldetective.utils.data_cleaning import extract_cols_from_table_list
|
|
|
19
19
|
from celldetective.utils.parsing import _extract_labels_from_config
|
|
20
20
|
from celldetective.utils.data_loaders import load_experiment_tables
|
|
21
21
|
import numpy as np
|
|
22
|
+
import pandas as pd
|
|
22
23
|
import os
|
|
23
24
|
import matplotlib.pyplot as plt
|
|
24
25
|
|
|
25
26
|
plt.rcParams["svg.fonttype"] = "none"
|
|
26
27
|
from glob import glob
|
|
28
|
+
from celldetective import get_logger
|
|
27
29
|
from celldetective.gui.base.styles import Styles
|
|
28
30
|
from celldetective.gui.base.components import CelldetectiveWidget
|
|
29
31
|
from matplotlib import colormaps
|
|
@@ -32,6 +34,8 @@ from celldetective.relative_measurements import expand_pair_table
|
|
|
32
34
|
import matplotlib.cm
|
|
33
35
|
from celldetective.neighborhood import extract_neighborhood_in_pair_table
|
|
34
36
|
|
|
37
|
+
logger = get_logger(__name__)
|
|
38
|
+
|
|
35
39
|
|
|
36
40
|
class ConfigSurvival(CelldetectiveWidget):
|
|
37
41
|
"""
|
|
@@ -225,7 +229,9 @@ class ConfigSurvival(CelldetectiveWidget):
|
|
|
225
229
|
)
|
|
226
230
|
)
|
|
227
231
|
if not tables_pairs:
|
|
228
|
-
|
|
232
|
+
logger.warning(
|
|
233
|
+
"No pair table found. Please compute the pair measurements."
|
|
234
|
+
)
|
|
229
235
|
return None
|
|
230
236
|
self.cols_pairs = extract_cols_from_table_list(tables_pairs)
|
|
231
237
|
|
|
@@ -264,7 +270,7 @@ class ConfigSurvival(CelldetectiveWidget):
|
|
|
264
270
|
and str(self.population_neigh) not in c
|
|
265
271
|
]
|
|
266
272
|
|
|
267
|
-
|
|
273
|
+
logger.debug(f"Neighborhood keys: {self.neighborhood_keys}")
|
|
268
274
|
|
|
269
275
|
time_idx = np.array(
|
|
270
276
|
[s.startswith("t_") or s.startswith("t0") for s in self.cols_pairs]
|
|
@@ -281,8 +287,8 @@ class ConfigSurvival(CelldetectiveWidget):
|
|
|
281
287
|
|
|
282
288
|
try:
|
|
283
289
|
time_columns = list(self.all_columns[time_idx])
|
|
284
|
-
except:
|
|
285
|
-
|
|
290
|
+
except (IndexError, KeyError):
|
|
291
|
+
logger.warning("No column starts with 't_' for time reference.")
|
|
286
292
|
self.auto_close = True
|
|
287
293
|
return None
|
|
288
294
|
|
|
@@ -295,8 +301,15 @@ class ConfigSurvival(CelldetectiveWidget):
|
|
|
295
301
|
|
|
296
302
|
def process_survival(self):
|
|
297
303
|
|
|
304
|
+
# Validate that reference time and time of interest are different
|
|
305
|
+
time_of_reference = self.cbs[1].currentText()
|
|
306
|
+
time_of_interest = self.cbs[2].currentText()
|
|
307
|
+
if time_of_reference == time_of_interest:
|
|
308
|
+
generic_message("Reference time and time of interest must be different.")
|
|
309
|
+
return None
|
|
310
|
+
|
|
298
311
|
self.FrameToMin = float(self.time_calibration_le.text().replace(",", "."))
|
|
299
|
-
self.time_of_interest =
|
|
312
|
+
self.time_of_interest = time_of_interest
|
|
300
313
|
if self.time_of_interest == "t0":
|
|
301
314
|
self.class_of_interest = "class"
|
|
302
315
|
elif self.time_of_interest.startswith("t0"):
|
|
@@ -312,8 +325,22 @@ class ConfigSurvival(CelldetectiveWidget):
|
|
|
312
325
|
query_text = self.query_le.text()
|
|
313
326
|
if query_text != "":
|
|
314
327
|
self.df = self.df.query(query_text)
|
|
328
|
+
except pd.errors.UndefinedVariableError as e:
|
|
329
|
+
logger.warning(f"Query failed - undefined variable: {e}")
|
|
330
|
+
generic_message(
|
|
331
|
+
f"Query error: column not found.\n{e}\n\nPlease check your column names."
|
|
332
|
+
)
|
|
333
|
+
return None
|
|
334
|
+
except SyntaxError as e:
|
|
335
|
+
logger.warning(f"Query failed - syntax error: {e}")
|
|
336
|
+
generic_message(
|
|
337
|
+
f"Query syntax error: {e}\n\nCheck your query format (e.g., 'column > 100')."
|
|
338
|
+
)
|
|
339
|
+
return None
|
|
315
340
|
except Exception as e:
|
|
316
|
-
|
|
341
|
+
logger.warning(f"Query not applied: {e}")
|
|
342
|
+
generic_message(f"Query could not be applied: {e}")
|
|
343
|
+
return None
|
|
317
344
|
|
|
318
345
|
self.interpret_pos_location()
|
|
319
346
|
|
|
@@ -391,11 +418,12 @@ class ConfigSurvival(CelldetectiveWidget):
|
|
|
391
418
|
/ self.FrameToMin
|
|
392
419
|
)
|
|
393
420
|
if not 0 < cut_observation_time <= (self.df["FRAME"].max()):
|
|
394
|
-
|
|
421
|
+
logger.warning(
|
|
422
|
+
"Invalid cut time (larger than movie length). Not applied."
|
|
423
|
+
)
|
|
395
424
|
cut_observation_time = None
|
|
396
425
|
except Exception as e:
|
|
397
|
-
|
|
398
|
-
pass
|
|
426
|
+
logger.debug(f"Cut time parsing error: {e}")
|
|
399
427
|
|
|
400
428
|
pairs = False
|
|
401
429
|
if self.neighborhood_keys is not None:
|
|
@@ -403,7 +431,7 @@ class ConfigSurvival(CelldetectiveWidget):
|
|
|
403
431
|
|
|
404
432
|
# Per position survival
|
|
405
433
|
for block, movie_group in self.df.groupby(["well", "position"]):
|
|
406
|
-
|
|
434
|
+
logger.debug(f"Processing block: {block}")
|
|
407
435
|
ks = compute_survival(
|
|
408
436
|
movie_group,
|
|
409
437
|
self.class_of_interest,
|
|
@@ -413,7 +441,7 @@ class ConfigSurvival(CelldetectiveWidget):
|
|
|
413
441
|
cut_observation_time=cut_observation_time,
|
|
414
442
|
pairs=pairs,
|
|
415
443
|
)
|
|
416
|
-
|
|
444
|
+
logger.debug(f"Survival fit result: {ks}")
|
|
417
445
|
if ks is not None:
|
|
418
446
|
self.df_pos_info.loc[
|
|
419
447
|
self.df_pos_info["pos_path"] == block[1], "survival_fit"
|
celldetective/gui/tableUI.py
CHANGED
|
@@ -21,8 +21,13 @@ from celldetective.gui.gui_utils import (
|
|
|
21
21
|
)
|
|
22
22
|
from celldetective.gui.base.figure_canvas import FigureCanvas
|
|
23
23
|
from celldetective.gui.base.utils import center_window
|
|
24
|
-
from celldetective.gui.table_ops._maths import
|
|
25
|
-
|
|
24
|
+
from celldetective.gui.table_ops._maths import (
|
|
25
|
+
DifferentiateColWidget,
|
|
26
|
+
OperationOnColsWidget,
|
|
27
|
+
CalibrateColWidget,
|
|
28
|
+
AbsColWidget,
|
|
29
|
+
LogColWidget,
|
|
30
|
+
)
|
|
26
31
|
from celldetective.gui.table_ops._merge_one_hot import MergeOneHotWidget
|
|
27
32
|
from celldetective.gui.table_ops._query_table import QueryWidget
|
|
28
33
|
from celldetective.gui.table_ops._rename_col import RenameColWidget
|
|
@@ -55,7 +60,7 @@ class PivotTableUI(CelldetectiveWidget):
|
|
|
55
60
|
self.mode = mode
|
|
56
61
|
|
|
57
62
|
self.setWindowTitle(title)
|
|
58
|
-
|
|
63
|
+
logger.debug(f"Pivot table to show: {self.data.shape}")
|
|
59
64
|
|
|
60
65
|
self.table = QTableView(self)
|
|
61
66
|
|
|
@@ -219,9 +224,35 @@ class TableUI(CelldetectiveMainWindow):
|
|
|
219
224
|
|
|
220
225
|
try:
|
|
221
226
|
self.fig.tight_layout()
|
|
222
|
-
except:
|
|
227
|
+
except AttributeError:
|
|
228
|
+
# fig not yet created
|
|
223
229
|
pass
|
|
224
230
|
|
|
231
|
+
def _get_selected_columns(self, max_cols=None):
|
|
232
|
+
"""
|
|
233
|
+
Get selected column names from the table view.
|
|
234
|
+
|
|
235
|
+
Parameters
|
|
236
|
+
----------
|
|
237
|
+
max_cols : int, optional
|
|
238
|
+
Maximum number of columns to return. Returns all if None.
|
|
239
|
+
|
|
240
|
+
Returns
|
|
241
|
+
-------
|
|
242
|
+
list
|
|
243
|
+
List of selected column names.
|
|
244
|
+
"""
|
|
245
|
+
x = self.table_view.selectedIndexes()
|
|
246
|
+
col_idx = np.unique(np.array([l.column() for l in x]))
|
|
247
|
+
cols = np.array(list(self.data.columns))
|
|
248
|
+
result = []
|
|
249
|
+
if len(col_idx) > 0:
|
|
250
|
+
for i in col_idx:
|
|
251
|
+
result.append(str(cols[i]))
|
|
252
|
+
if max_cols is not None:
|
|
253
|
+
return result[:max_cols]
|
|
254
|
+
return result
|
|
255
|
+
|
|
225
256
|
def _create_actions(self):
|
|
226
257
|
|
|
227
258
|
self.save_as = QAction("&Save as...", self)
|
|
@@ -540,8 +571,8 @@ class TableUI(CelldetectiveMainWindow):
|
|
|
540
571
|
self.renameWidget.show()
|
|
541
572
|
|
|
542
573
|
def save_as_csv_inplace_per_pos(self):
|
|
543
|
-
|
|
544
|
-
|
|
574
|
+
"""Save each position's table in its respective folder."""
|
|
575
|
+
logger.info("Saving each table in its respective position folder...")
|
|
545
576
|
for pos, pos_group in self.data.groupby(["position"]):
|
|
546
577
|
invalid_cols = [
|
|
547
578
|
c for c in list(pos_group.columns) if c.startswith("Unnamed")
|
|
@@ -555,26 +586,12 @@ class TableUI(CelldetectiveMainWindow):
|
|
|
555
586
|
),
|
|
556
587
|
index=False,
|
|
557
588
|
)
|
|
558
|
-
|
|
589
|
+
logger.info("Done saving tables.")
|
|
559
590
|
|
|
560
591
|
def divide_signals(self):
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
if isinstance(col_idx, (list, np.ndarray)):
|
|
565
|
-
cols = np.array(list(self.data.columns))
|
|
566
|
-
if len(col_idx) > 0:
|
|
567
|
-
selected_col1 = str(cols[col_idx[0]])
|
|
568
|
-
if len(col_idx) > 1:
|
|
569
|
-
selected_col2 = str(cols[col_idx[1]])
|
|
570
|
-
else:
|
|
571
|
-
selected_col2 = None
|
|
572
|
-
else:
|
|
573
|
-
selected_col1 = None
|
|
574
|
-
selected_col2 = None
|
|
575
|
-
else:
|
|
576
|
-
selected_col1 = None
|
|
577
|
-
selected_col2 = None
|
|
592
|
+
selected = self._get_selected_columns(max_cols=2)
|
|
593
|
+
selected_col1 = selected[0] if len(selected) > 0 else None
|
|
594
|
+
selected_col2 = selected[1] if len(selected) > 1 else None
|
|
578
595
|
|
|
579
596
|
self.divWidget = OperationOnColsWidget(
|
|
580
597
|
self, column1=selected_col1, column2=selected_col2, operation="divide"
|
|
@@ -582,23 +599,9 @@ class TableUI(CelldetectiveMainWindow):
|
|
|
582
599
|
self.divWidget.show()
|
|
583
600
|
|
|
584
601
|
def multiply_signals(self):
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
if isinstance(col_idx, (list, np.ndarray)):
|
|
589
|
-
cols = np.array(list(self.data.columns))
|
|
590
|
-
if len(col_idx) > 0:
|
|
591
|
-
selected_col1 = str(cols[col_idx[0]])
|
|
592
|
-
if len(col_idx) > 1:
|
|
593
|
-
selected_col2 = str(cols[col_idx[1]])
|
|
594
|
-
else:
|
|
595
|
-
selected_col2 = None
|
|
596
|
-
else:
|
|
597
|
-
selected_col1 = None
|
|
598
|
-
selected_col2 = None
|
|
599
|
-
else:
|
|
600
|
-
selected_col1 = None
|
|
601
|
-
selected_col2 = None
|
|
602
|
+
selected = self._get_selected_columns(max_cols=2)
|
|
603
|
+
selected_col1 = selected[0] if len(selected) > 0 else None
|
|
604
|
+
selected_col2 = selected[1] if len(selected) > 1 else None
|
|
602
605
|
|
|
603
606
|
self.mulWidget = OperationOnColsWidget(
|
|
604
607
|
self, column1=selected_col1, column2=selected_col2, operation="multiply"
|
|
@@ -606,23 +609,9 @@ class TableUI(CelldetectiveMainWindow):
|
|
|
606
609
|
self.mulWidget.show()
|
|
607
610
|
|
|
608
611
|
def add_signals(self):
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
if isinstance(col_idx, (list, np.ndarray)):
|
|
613
|
-
cols = np.array(list(self.data.columns))
|
|
614
|
-
if len(col_idx) > 0:
|
|
615
|
-
selected_col1 = str(cols[col_idx[0]])
|
|
616
|
-
if len(col_idx) > 1:
|
|
617
|
-
selected_col2 = str(cols[col_idx[1]])
|
|
618
|
-
else:
|
|
619
|
-
selected_col2 = None
|
|
620
|
-
else:
|
|
621
|
-
selected_col1 = None
|
|
622
|
-
selected_col2 = None
|
|
623
|
-
else:
|
|
624
|
-
selected_col1 = None
|
|
625
|
-
selected_col2 = None
|
|
612
|
+
selected = self._get_selected_columns(max_cols=2)
|
|
613
|
+
selected_col1 = selected[0] if len(selected) > 0 else None
|
|
614
|
+
selected_col2 = selected[1] if len(selected) > 1 else None
|
|
626
615
|
|
|
627
616
|
self.addiWidget = OperationOnColsWidget(
|
|
628
617
|
self, column1=selected_col1, column2=selected_col2, operation="add"
|
|
@@ -630,23 +619,9 @@ class TableUI(CelldetectiveMainWindow):
|
|
|
630
619
|
self.addiWidget.show()
|
|
631
620
|
|
|
632
621
|
def subtract_signals(self):
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
if isinstance(col_idx, (list, np.ndarray)):
|
|
637
|
-
cols = np.array(list(self.data.columns))
|
|
638
|
-
if len(col_idx) > 0:
|
|
639
|
-
selected_col1 = str(cols[col_idx[0]])
|
|
640
|
-
if len(col_idx) > 1:
|
|
641
|
-
selected_col2 = str(cols[col_idx[1]])
|
|
642
|
-
else:
|
|
643
|
-
selected_col2 = None
|
|
644
|
-
else:
|
|
645
|
-
selected_col1 = None
|
|
646
|
-
selected_col2 = None
|
|
647
|
-
else:
|
|
648
|
-
selected_col1 = None
|
|
649
|
-
selected_col2 = None
|
|
622
|
+
selected = self._get_selected_columns(max_cols=2)
|
|
623
|
+
selected_col1 = selected[0] if len(selected) > 0 else None
|
|
624
|
+
selected_col2 = selected[1] if len(selected) > 1 else None
|
|
650
625
|
|
|
651
626
|
self.subWidget = OperationOnColsWidget(
|
|
652
627
|
self, column1=selected_col1, column2=selected_col2, operation="subtract"
|
|
@@ -654,56 +629,22 @@ class TableUI(CelldetectiveMainWindow):
|
|
|
654
629
|
self.subWidget.show()
|
|
655
630
|
|
|
656
631
|
def differenciate_selected_feature(self):
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
# create new col
|
|
661
|
-
|
|
662
|
-
x = self.table_view.selectedIndexes()
|
|
663
|
-
col_idx = np.unique(np.array([l.column() for l in x]))
|
|
664
|
-
if isinstance(col_idx, (list, np.ndarray)):
|
|
665
|
-
cols = np.array(list(self.data.columns))
|
|
666
|
-
if len(col_idx) > 0:
|
|
667
|
-
selected_col = str(cols[col_idx[0]])
|
|
668
|
-
else:
|
|
669
|
-
selected_col = None
|
|
670
|
-
else:
|
|
671
|
-
selected_col = None
|
|
672
|
-
|
|
632
|
+
"""Open widget to differentiate the selected column."""
|
|
633
|
+
selected = self._get_selected_columns(max_cols=1)
|
|
634
|
+
selected_col = selected[0] if selected else None
|
|
673
635
|
self.diffWidget = DifferentiateColWidget(self, selected_col)
|
|
674
636
|
self.diffWidget.show()
|
|
675
637
|
|
|
676
638
|
def take_log_of_selected_feature(self):
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
# create new col
|
|
681
|
-
|
|
682
|
-
x = self.table_view.selectedIndexes()
|
|
683
|
-
col_idx = np.unique(np.array([l.column() for l in x]))
|
|
684
|
-
if isinstance(col_idx, (list, np.ndarray)):
|
|
685
|
-
cols = np.array(list(self.data.columns))
|
|
686
|
-
if len(col_idx) > 0:
|
|
687
|
-
selected_col = str(cols[col_idx[0]])
|
|
688
|
-
else:
|
|
689
|
-
selected_col = None
|
|
690
|
-
else:
|
|
691
|
-
selected_col = None
|
|
692
|
-
|
|
639
|
+
"""Open widget to take log of the selected column."""
|
|
640
|
+
selected = self._get_selected_columns(max_cols=1)
|
|
641
|
+
selected_col = selected[0] if selected else None
|
|
693
642
|
self.LogWidget = LogColWidget(self, selected_col)
|
|
694
643
|
self.LogWidget.show()
|
|
695
644
|
|
|
696
645
|
def merge_classification_features(self):
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
col_idx = np.unique(np.array([l.column() for l in x]))
|
|
700
|
-
|
|
701
|
-
col_selection = []
|
|
702
|
-
if isinstance(col_idx, (list, np.ndarray)):
|
|
703
|
-
cols = np.array(list(self.data.columns))
|
|
704
|
-
if len(col_idx) > 0:
|
|
705
|
-
selected_cols = cols[col_idx]
|
|
706
|
-
col_selection.extend(selected_cols)
|
|
646
|
+
"""Open widget to merge selected classification columns."""
|
|
647
|
+
col_selection = self._get_selected_columns()
|
|
707
648
|
|
|
708
649
|
# Lazy load MergeGroupWidget
|
|
709
650
|
from celldetective.gui.table_ops._merge_groups import MergeGroupWidget
|
|
@@ -712,38 +653,16 @@ class TableUI(CelldetectiveMainWindow):
|
|
|
712
653
|
self.merge_classification_widget.show()
|
|
713
654
|
|
|
714
655
|
def calibrate_selected_feature(self):
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
if isinstance(col_idx, (list, np.ndarray)):
|
|
719
|
-
cols = np.array(list(self.data.columns))
|
|
720
|
-
if len(col_idx) > 0:
|
|
721
|
-
selected_col = str(cols[col_idx[0]])
|
|
722
|
-
else:
|
|
723
|
-
selected_col = None
|
|
724
|
-
else:
|
|
725
|
-
selected_col = None
|
|
726
|
-
|
|
656
|
+
"""Open widget to calibrate the selected column."""
|
|
657
|
+
selected = self._get_selected_columns(max_cols=1)
|
|
658
|
+
selected_col = selected[0] if selected else None
|
|
727
659
|
self.calWidget = CalibrateColWidget(self, selected_col)
|
|
728
660
|
self.calWidget.show()
|
|
729
661
|
|
|
730
662
|
def take_abs_of_selected_feature(self):
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
# create new col
|
|
735
|
-
|
|
736
|
-
x = self.table_view.selectedIndexes()
|
|
737
|
-
col_idx = np.unique(np.array([l.column() for l in x]))
|
|
738
|
-
if isinstance(col_idx, (list, np.ndarray)):
|
|
739
|
-
cols = np.array(list(self.data.columns))
|
|
740
|
-
if len(col_idx) > 0:
|
|
741
|
-
selected_col = str(cols[col_idx[0]])
|
|
742
|
-
else:
|
|
743
|
-
selected_col = None
|
|
744
|
-
else:
|
|
745
|
-
selected_col = None
|
|
746
|
-
|
|
663
|
+
"""Open widget to take absolute value of the selected column."""
|
|
664
|
+
selected = self._get_selected_columns(max_cols=1)
|
|
665
|
+
selected_col = selected[0] if selected else None
|
|
747
666
|
self.absWidget = AbsColWidget(self, selected_col)
|
|
748
667
|
self.absWidget.show()
|
|
749
668
|
|
|
@@ -991,7 +910,8 @@ class TableUI(CelldetectiveMainWindow):
|
|
|
991
910
|
y = column_names[unique_cols]
|
|
992
911
|
idx = self.y_cb.findText(y)
|
|
993
912
|
self.y_cb.setCurrentIndex(idx)
|
|
994
|
-
except:
|
|
913
|
+
except (IndexError, KeyError):
|
|
914
|
+
# No column selected or invalid selection
|
|
995
915
|
pass
|
|
996
916
|
|
|
997
917
|
hbox = QHBoxLayout()
|
|
@@ -1018,7 +938,8 @@ class TableUI(CelldetectiveMainWindow):
|
|
|
1018
938
|
if hasattr(matplotlib.cm, str(cm).lower()):
|
|
1019
939
|
try:
|
|
1020
940
|
self.cmap_cb.addColormap(cm.lower())
|
|
1021
|
-
except:
|
|
941
|
+
except Exception:
|
|
942
|
+
# Some colormaps may fail to add
|
|
1022
943
|
pass
|
|
1023
944
|
|
|
1024
945
|
hbox = QHBoxLayout()
|
|
@@ -1057,7 +978,7 @@ class TableUI(CelldetectiveMainWindow):
|
|
|
1057
978
|
cmap(i / len(self.data[self.hue_variable].unique()))
|
|
1058
979
|
for i in range(len(self.data[self.hue_variable].unique()))
|
|
1059
980
|
]
|
|
1060
|
-
except:
|
|
981
|
+
except (KeyError, ZeroDivisionError):
|
|
1061
982
|
colors = None
|
|
1062
983
|
|
|
1063
984
|
if self.hue_cb.currentText() == "--":
|