celldetective 1.3.9.post5__py3-none-any.whl → 1.4.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- celldetective/__init__.py +0 -3
- celldetective/_version.py +1 -1
- celldetective/events.py +2 -4
- celldetective/exceptions.py +11 -0
- celldetective/extra_properties.py +132 -0
- celldetective/filters.py +7 -1
- celldetective/gui/InitWindow.py +37 -46
- celldetective/gui/__init__.py +3 -9
- celldetective/gui/about.py +19 -15
- celldetective/gui/analyze_block.py +34 -19
- celldetective/gui/base_annotator.py +786 -0
- celldetective/gui/base_components.py +23 -0
- celldetective/gui/classifier_widget.py +86 -94
- celldetective/gui/configure_new_exp.py +163 -46
- celldetective/gui/control_panel.py +76 -146
- celldetective/gui/{signal_annotator.py → event_annotator.py} +533 -1438
- celldetective/gui/generic_signal_plot.py +11 -13
- celldetective/gui/gui_utils.py +54 -23
- celldetective/gui/help/neighborhood.json +2 -2
- celldetective/gui/json_readers.py +5 -4
- celldetective/gui/layouts.py +265 -31
- celldetective/gui/{signal_annotator2.py → pair_event_annotator.py} +433 -635
- celldetective/gui/plot_measurements.py +21 -17
- celldetective/gui/plot_signals_ui.py +125 -72
- celldetective/gui/process_block.py +283 -188
- celldetective/gui/processes/compute_neighborhood.py +594 -0
- celldetective/gui/processes/downloader.py +37 -34
- celldetective/gui/processes/measure_cells.py +19 -8
- celldetective/gui/processes/segment_cells.py +47 -11
- celldetective/gui/processes/track_cells.py +18 -13
- celldetective/gui/seg_model_loader.py +21 -62
- celldetective/gui/settings/__init__.py +7 -0
- celldetective/gui/settings/_settings_base.py +70 -0
- celldetective/gui/{retrain_signal_model_options.py → settings/_settings_event_model_training.py} +54 -109
- celldetective/gui/{measurement_options.py → settings/_settings_measurements.py} +54 -92
- celldetective/gui/{neighborhood_options.py → settings/_settings_neighborhood.py} +10 -13
- celldetective/gui/settings/_settings_segmentation.py +49 -0
- celldetective/gui/{retrain_segmentation_model_options.py → settings/_settings_segmentation_model_training.py} +38 -92
- celldetective/gui/{signal_annotator_options.py → settings/_settings_signal_annotator.py} +78 -103
- celldetective/gui/{btrack_options.py → settings/_settings_tracking.py} +85 -116
- celldetective/gui/styles.py +2 -1
- celldetective/gui/survival_ui.py +49 -95
- celldetective/gui/tableUI.py +53 -25
- celldetective/gui/table_ops/__init__.py +0 -0
- celldetective/gui/table_ops/merge_groups.py +118 -0
- celldetective/gui/thresholds_gui.py +617 -1221
- celldetective/gui/viewers.py +107 -42
- celldetective/gui/workers.py +8 -4
- celldetective/io.py +137 -57
- celldetective/links/zenodo.json +145 -144
- celldetective/measure.py +94 -53
- celldetective/neighborhood.py +342 -268
- celldetective/preprocessing.py +56 -35
- celldetective/regionprops/_regionprops.py +16 -5
- celldetective/relative_measurements.py +50 -29
- celldetective/scripts/analyze_signals.py +4 -1
- celldetective/scripts/measure_cells.py +5 -5
- celldetective/scripts/measure_relative.py +20 -12
- celldetective/scripts/segment_cells.py +4 -10
- celldetective/scripts/segment_cells_thresholds.py +3 -3
- celldetective/scripts/track_cells.py +10 -8
- celldetective/scripts/train_segmentation_model.py +18 -6
- celldetective/signals.py +29 -14
- celldetective/tracking.py +14 -3
- celldetective/utils.py +91 -62
- {celldetective-1.3.9.post5.dist-info → celldetective-1.4.1.dist-info}/METADATA +24 -16
- celldetective-1.4.1.dist-info/RECORD +123 -0
- {celldetective-1.3.9.post5.dist-info → celldetective-1.4.1.dist-info}/WHEEL +1 -1
- tests/gui/__init__.py +0 -0
- tests/gui/test_new_project.py +228 -0
- tests/gui/test_project.py +99 -0
- tests/test_preprocessing.py +2 -2
- celldetective/models/segmentation_effectors/ricm_bf_all_last/config_input.json +0 -79
- 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 +0 -37
- celldetective/models/segmentation_effectors/test-transfer/config_input.json +0 -39
- celldetective/models/segmentation_effectors/test-transfer/test-transfer +0 -0
- celldetective/models/signal_detection/NucCond/classification_loss.png +0 -0
- celldetective/models/signal_detection/NucCond/classifier.h5 +0 -0
- celldetective/models/signal_detection/NucCond/config_input.json +0 -1
- celldetective/models/signal_detection/NucCond/log_classifier.csv +0 -126
- celldetective/models/signal_detection/NucCond/log_regressor.csv +0 -282
- celldetective/models/signal_detection/NucCond/regression_loss.png +0 -0
- celldetective/models/signal_detection/NucCond/regressor.h5 +0 -0
- celldetective/models/signal_detection/NucCond/scores.npy +0 -0
- celldetective/models/signal_detection/NucCond/test_confusion_matrix.png +0 -0
- celldetective/models/signal_detection/NucCond/test_regression.png +0 -0
- celldetective/models/signal_detection/NucCond/validation_confusion_matrix.png +0 -0
- celldetective/models/signal_detection/NucCond/validation_regression.png +0 -0
- celldetective-1.3.9.post5.dist-info/RECORD +0 -129
- tests/test_qt.py +0 -103
- {celldetective-1.3.9.post5.dist-info → celldetective-1.4.1.dist-info}/entry_points.txt +0 -0
- {celldetective-1.3.9.post5.dist-info → celldetective-1.4.1.dist-info/licenses}/LICENSE +0 -0
- {celldetective-1.3.9.post5.dist-info → celldetective-1.4.1.dist-info}/top_level.txt +0 -0
celldetective/gui/{retrain_signal_model_options.py → settings/_settings_event_model_training.py}
RENAMED
|
@@ -1,12 +1,9 @@
|
|
|
1
|
-
from PyQt5.QtWidgets import
|
|
1
|
+
from PyQt5.QtWidgets import QMessageBox, QComboBox, QFrame, QCheckBox, QFileDialog, QGridLayout, QLineEdit, QVBoxLayout, QLabel, QHBoxLayout, QPushButton
|
|
2
2
|
from PyQt5.QtCore import Qt, QSize
|
|
3
|
-
from PyQt5.QtGui import QDoubleValidator, QIntValidator, QIcon
|
|
4
|
-
from celldetective.gui.gui_utils import center_window
|
|
5
3
|
from celldetective.gui.layouts import ChannelNormGenerator
|
|
6
4
|
from superqt import QLabeledDoubleSlider, QLabeledSlider, QSearchableComboBox
|
|
7
5
|
from superqt.fonticon import icon
|
|
8
6
|
from fonticon_mdi6 import MDI6
|
|
9
|
-
from celldetective.utils import get_software_location
|
|
10
7
|
from celldetective.io import locate_signal_dataset, get_signal_datasets_list, load_experiment_tables
|
|
11
8
|
from celldetective.signals import train_signal_model
|
|
12
9
|
import numpy as np
|
|
@@ -14,12 +11,12 @@ import json
|
|
|
14
11
|
import os
|
|
15
12
|
from glob import glob
|
|
16
13
|
from datetime import datetime
|
|
17
|
-
from celldetective.gui import Styles
|
|
18
14
|
from pandas.api.types import is_numeric_dtype
|
|
19
15
|
from celldetective.gui.processes.train_signal_model import TrainSignalModelProcess
|
|
20
16
|
from celldetective.gui.workers import ProgressWindow
|
|
17
|
+
from celldetective.gui.settings._settings_base import CelldetectiveSettingsPanel
|
|
21
18
|
|
|
22
|
-
class
|
|
19
|
+
class SettingsEventDetectionModelTraining(CelldetectiveSettingsPanel):
|
|
23
20
|
|
|
24
21
|
"""
|
|
25
22
|
UI to set measurement instructions.
|
|
@@ -28,88 +25,62 @@ class ConfigSignalModelTraining(QMainWindow, Styles):
|
|
|
28
25
|
|
|
29
26
|
def __init__(self, parent_window=None, signal_mode='single-cells'):
|
|
30
27
|
|
|
31
|
-
super().__init__()
|
|
32
28
|
self.parent_window = parent_window
|
|
33
|
-
self.setWindowTitle("Train signal model")
|
|
34
|
-
self.setWindowIcon(QIcon(os.sep.join(['celldetective','icons','mexican-hat.png'])))
|
|
35
29
|
self.mode = self.parent_window.mode
|
|
36
30
|
self.exp_dir = self.parent_window.exp_dir
|
|
37
|
-
self.
|
|
38
|
-
self.pretrained_model = None
|
|
31
|
+
self.pretrained_model = None
|
|
39
32
|
self.dataset_folder = None
|
|
40
33
|
self.current_neighborhood = None
|
|
41
34
|
self.reference_population = None
|
|
42
35
|
self.neighbor_population = None
|
|
43
36
|
self.signal_mode = signal_mode
|
|
37
|
+
|
|
38
|
+
super().__init__(title="Train event detection model")
|
|
44
39
|
|
|
45
40
|
if self.signal_mode=='single-cells':
|
|
46
|
-
self.signal_models_dir = self.
|
|
41
|
+
self.signal_models_dir = self._software_path+os.sep+os.sep.join(['celldetective','models','signal_detection'])
|
|
47
42
|
elif self.signal_mode=='pairs':
|
|
48
|
-
self.signal_models_dir = self.
|
|
43
|
+
self.signal_models_dir = self._software_path+os.sep+os.sep.join(['celldetective','models','pair_signal_detection'])
|
|
49
44
|
self.mode = 'pairs'
|
|
45
|
+
|
|
46
|
+
self._add_to_layout()
|
|
47
|
+
self._load_previous_instructions()
|
|
48
|
+
|
|
49
|
+
self._adjustSize()
|
|
50
|
+
new_width = int(self.width()*1.2)
|
|
51
|
+
self.resize(new_width, int(self._screen_height * 0.8))
|
|
52
|
+
self.setMinimumWidth(new_width)
|
|
53
|
+
|
|
54
|
+
def _add_to_layout(self):
|
|
55
|
+
self._layout.addWidget(self.model_frame)
|
|
56
|
+
self._layout.addWidget(self.data_frame)
|
|
57
|
+
self._layout.addWidget(self.hyper_frame)
|
|
58
|
+
self._layout.addWidget(self.submit_btn)
|
|
50
59
|
|
|
51
|
-
|
|
52
|
-
self.onlyInt = QIntValidator()
|
|
53
|
-
|
|
54
|
-
self.screen_height = self.parent_window.parent_window.parent_window.screen_height
|
|
55
|
-
center_window(self)
|
|
56
|
-
|
|
57
|
-
self.setMinimumWidth(500)
|
|
58
|
-
self.setMinimumHeight(int(0.3*self.screen_height))
|
|
59
|
-
self.setMaximumHeight(int(0.8*self.screen_height))
|
|
60
|
-
self.populate_widget()
|
|
61
|
-
#self.load_previous_measurement_instructions()
|
|
62
|
-
|
|
63
|
-
def populate_widget(self):
|
|
60
|
+
def _create_widgets(self):
|
|
64
61
|
|
|
65
62
|
"""
|
|
66
63
|
Create the multibox design.
|
|
67
64
|
|
|
68
65
|
"""
|
|
66
|
+
super()._create_widgets()
|
|
69
67
|
|
|
70
|
-
# Create button widget and layout
|
|
71
|
-
self.scroll_area = QScrollArea(self)
|
|
72
|
-
self.button_widget = QWidget()
|
|
73
|
-
self.main_layout = QVBoxLayout()
|
|
74
|
-
self.button_widget.setLayout(self.main_layout)
|
|
75
|
-
self.main_layout.setContentsMargins(30,30,30,30)
|
|
76
|
-
|
|
77
68
|
# first frame for FEATURES
|
|
78
69
|
self.model_frame = QFrame()
|
|
79
70
|
self.model_frame.setFrameStyle(QFrame.StyledPanel | QFrame.Raised)
|
|
80
71
|
self.populate_model_frame()
|
|
81
|
-
self.main_layout.addWidget(self.model_frame)
|
|
82
72
|
|
|
83
73
|
self.data_frame = QFrame()
|
|
84
74
|
self.data_frame.setFrameStyle(QFrame.StyledPanel | QFrame.Raised)
|
|
85
75
|
self.populate_data_frame()
|
|
86
|
-
self.main_layout.addWidget(self.data_frame)
|
|
87
76
|
|
|
88
77
|
self.hyper_frame = QFrame()
|
|
89
78
|
self.hyper_frame.setFrameStyle(QFrame.StyledPanel | QFrame.Raised)
|
|
90
79
|
self.populate_hyper_frame()
|
|
91
|
-
self.main_layout.addWidget(self.hyper_frame)
|
|
92
80
|
|
|
93
|
-
self.submit_btn = QPushButton('Train')
|
|
94
|
-
self.submit_btn.setStyleSheet(self.button_style_sheet)
|
|
95
|
-
self.submit_btn.clicked.connect(self.prep_model)
|
|
96
|
-
self.main_layout.addWidget(self.submit_btn)
|
|
97
81
|
self.submit_btn.setEnabled(False)
|
|
82
|
+
self.submit_btn.setText("Train")
|
|
98
83
|
|
|
99
|
-
#self.populate_left_panel()
|
|
100
|
-
#grid.addLayout(self.left_side, 0, 0, 1, 1)
|
|
101
|
-
self.button_widget.adjustSize()
|
|
102
|
-
|
|
103
|
-
self.scroll_area.setAlignment(Qt.AlignCenter)
|
|
104
|
-
self.scroll_area.setWidget(self.button_widget)
|
|
105
|
-
self.scroll_area.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
|
|
106
|
-
self.scroll_area.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded)
|
|
107
|
-
self.scroll_area.setWidgetResizable(True)
|
|
108
|
-
self.setCentralWidget(self.scroll_area)
|
|
109
|
-
self.show()
|
|
110
|
-
|
|
111
|
-
QApplication.processEvents()
|
|
112
|
-
self.adjustScrollArea()
|
|
113
84
|
|
|
114
85
|
def populate_hyper_frame(self):
|
|
115
86
|
|
|
@@ -139,14 +110,14 @@ class ConfigSignalModelTraining(QMainWindow, Styles):
|
|
|
139
110
|
lr_layout = QHBoxLayout()
|
|
140
111
|
lr_layout.addWidget(QLabel('learning rate: '),30)
|
|
141
112
|
self.lr_le = QLineEdit('0,01')
|
|
142
|
-
self.lr_le.setValidator(self.
|
|
113
|
+
self.lr_le.setValidator(self._floatValidator)
|
|
143
114
|
lr_layout.addWidget(self.lr_le, 70)
|
|
144
115
|
layout.addLayout(lr_layout)
|
|
145
116
|
|
|
146
117
|
bs_layout = QHBoxLayout()
|
|
147
118
|
bs_layout.addWidget(QLabel('batch size: '),30)
|
|
148
119
|
self.bs_le = QLineEdit('64')
|
|
149
|
-
self.bs_le.setValidator(self.
|
|
120
|
+
self.bs_le.setValidator(self._intValidator)
|
|
150
121
|
bs_layout.addWidget(self.bs_le, 70)
|
|
151
122
|
layout.addLayout(bs_layout)
|
|
152
123
|
|
|
@@ -156,7 +127,7 @@ class ConfigSignalModelTraining(QMainWindow, Styles):
|
|
|
156
127
|
self.epochs_slider.setRange(1,3000)
|
|
157
128
|
self.epochs_slider.setSingleStep(1)
|
|
158
129
|
self.epochs_slider.setTickInterval(1)
|
|
159
|
-
self.epochs_slider.setOrientation(
|
|
130
|
+
self.epochs_slider.setOrientation(Qt.Horizontal)
|
|
160
131
|
self.epochs_slider.setValue(300)
|
|
161
132
|
epochs_layout.addWidget(self.epochs_slider, 70)
|
|
162
133
|
layout.addLayout(epochs_layout)
|
|
@@ -243,7 +214,7 @@ class ConfigSignalModelTraining(QMainWindow, Styles):
|
|
|
243
214
|
self.augmentation_slider = QLabeledDoubleSlider()
|
|
244
215
|
self.augmentation_slider.setSingleStep(0.01)
|
|
245
216
|
self.augmentation_slider.setTickInterval(0.01)
|
|
246
|
-
self.augmentation_slider.setOrientation(
|
|
217
|
+
self.augmentation_slider.setOrientation(Qt.Horizontal)
|
|
247
218
|
self.augmentation_slider.setRange(1, 5)
|
|
248
219
|
self.augmentation_slider.setValue(2)
|
|
249
220
|
|
|
@@ -255,7 +226,7 @@ class ConfigSignalModelTraining(QMainWindow, Styles):
|
|
|
255
226
|
self.validation_slider = QLabeledDoubleSlider()
|
|
256
227
|
self.validation_slider.setSingleStep(0.01)
|
|
257
228
|
self.validation_slider.setTickInterval(0.01)
|
|
258
|
-
self.validation_slider.setOrientation(
|
|
229
|
+
self.validation_slider.setOrientation(Qt.Horizontal)
|
|
259
230
|
self.validation_slider.setRange(0,0.9)
|
|
260
231
|
self.validation_slider.setValue(0.25)
|
|
261
232
|
validation_split_layout.addWidget(self.validation_slider, 70)
|
|
@@ -332,7 +303,7 @@ class ConfigSignalModelTraining(QMainWindow, Styles):
|
|
|
332
303
|
self.model_length_slider.setSingleStep(1)
|
|
333
304
|
self.model_length_slider.setTickInterval(1)
|
|
334
305
|
self.model_length_slider.setSingleStep(1)
|
|
335
|
-
self.model_length_slider.setOrientation(
|
|
306
|
+
self.model_length_slider.setOrientation(Qt.Horizontal)
|
|
336
307
|
self.model_length_slider.setRange(0,1024)
|
|
337
308
|
self.model_length_slider.setValue(128)
|
|
338
309
|
model_length_layout.addWidget(self.model_length_slider, 70)
|
|
@@ -341,25 +312,22 @@ class ConfigSignalModelTraining(QMainWindow, Styles):
|
|
|
341
312
|
def neighborhood_changed(self):
|
|
342
313
|
|
|
343
314
|
neigh = self.neighborhood_choice_cb.currentText()
|
|
344
|
-
self.current_neighborhood = neigh
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
315
|
+
self.current_neighborhood = neigh
|
|
316
|
+
for pop in self.dataframes.keys():
|
|
317
|
+
self.current_neighborhood = self.current_neighborhood.replace(f'{pop}_ref_', '')
|
|
318
|
+
|
|
319
|
+
self.reference_population = self.neighborhood_choice_cb.currentText().split('_')[0]
|
|
320
|
+
if '_(' in self.current_neighborhood and ')_' in self.current_neighborhood:
|
|
321
|
+
self.neighbor_population = self.current_neighborhood.split('_(')[-1].split(')_')[0].split('-')[-1]
|
|
322
|
+
self.reference_population = self.current_neighborhood.split('_(')[-1].split(')_')[0].split('-')[0]
|
|
351
323
|
else:
|
|
352
|
-
if 'self' in
|
|
353
|
-
self.neighbor_population =
|
|
354
|
-
|
|
355
|
-
self.neighbor_population = 'targets'
|
|
356
|
-
|
|
324
|
+
if 'self' in self.current_neighborhood:
|
|
325
|
+
self.neighbor_population = self.reference_population
|
|
326
|
+
|
|
357
327
|
print(f'Current neighborhood: {self.current_neighborhood}')
|
|
358
328
|
print(f'New reference population: {self.reference_population}')
|
|
359
329
|
print(f'New neighbor population: {self.neighbor_population}')
|
|
360
330
|
|
|
361
|
-
# reload reference signals / neighbor signals / pair signals
|
|
362
|
-
# fill the channel cbs
|
|
363
331
|
self.df_reference = self.dataframes[self.reference_population]
|
|
364
332
|
self.df_neighbor = self.dataframes[self.neighbor_population]
|
|
365
333
|
self.df_pairs = load_experiment_tables(self.parent_window.exp_dir, population='pairs', load_pickle=False)
|
|
@@ -374,45 +342,19 @@ class ConfigSignalModelTraining(QMainWindow, Styles):
|
|
|
374
342
|
self.signals = ['--'] + num_cols_pairs + num_cols_reference + num_cols_neighbor
|
|
375
343
|
|
|
376
344
|
for cb in self.ch_norm.channel_cbs:
|
|
377
|
-
# try:
|
|
378
|
-
# cb.disconnect()
|
|
379
|
-
# except:
|
|
380
|
-
# pass
|
|
381
345
|
cb.clear()
|
|
382
346
|
cb.addItems(self.signals)
|
|
383
347
|
|
|
384
348
|
def fill_available_neighborhoods(self):
|
|
385
|
-
|
|
386
|
-
df_targets = load_experiment_tables(self.parent_window.exp_dir, population='targets', load_pickle=True)
|
|
387
|
-
df_effectors = load_experiment_tables(self.parent_window.exp_dir, population='effectors', load_pickle=True)
|
|
388
|
-
|
|
389
|
-
self.dataframes = {
|
|
390
|
-
'targets': df_targets,
|
|
391
|
-
'effectors': df_effectors,
|
|
392
|
-
}
|
|
393
349
|
|
|
350
|
+
self.dataframes = {}
|
|
394
351
|
self.neighborhood_cols = []
|
|
395
|
-
self.
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
if c.startswith('neighborhood') and '_2_' in c:
|
|
402
|
-
self.neighbor_populations.append('effectors')
|
|
403
|
-
elif c.startswith('neighborhood') and 'self' in c:
|
|
404
|
-
self.neighbor_populations.append('targets')
|
|
405
|
-
|
|
406
|
-
if df_effectors is not None:
|
|
407
|
-
self.neighborhood_cols.extend(['effector_ref_'+c for c in list(df_effectors.columns) if c.startswith('neighborhood')])
|
|
408
|
-
self.reference_populations.extend(['effectors' for c in list(df_effectors.columns) if c.startswith('neighborhood')])
|
|
409
|
-
for c in list(df_effectors.columns):
|
|
410
|
-
if c.startswith('neighborhood') and '_2_' in c:
|
|
411
|
-
self.neighbor_populations.append('targets')
|
|
412
|
-
elif c.startswith('neighborhood') and 'self' in c:
|
|
413
|
-
self.neighbor_populations.append('effectors')
|
|
414
|
-
|
|
415
|
-
print(f"The following neighborhoods were detected: {self.neighborhood_cols=} {self.reference_populations=} {self.neighbor_populations=}")
|
|
352
|
+
for population in self.parent_window.parent_window.populations:
|
|
353
|
+
df_pop = load_experiment_tables(self.parent_window.exp_dir, population=population, load_pickle=True)
|
|
354
|
+
self.dataframes.update({population: df_pop})
|
|
355
|
+
if df_pop is not None:
|
|
356
|
+
self.neighborhood_cols.extend(
|
|
357
|
+
[f'{population}_ref_' + c for c in list(df_pop.columns) if c.startswith('neighborhood')])
|
|
416
358
|
|
|
417
359
|
self.neighborhood_choice_cb.addItems(self.neighborhood_cols)
|
|
418
360
|
|
|
@@ -518,7 +460,7 @@ class ConfigSignalModelTraining(QMainWindow, Styles):
|
|
|
518
460
|
while self.scroll_area.verticalScrollBar().isVisible() and self.height() < self.maximumHeight():
|
|
519
461
|
self.resize(self.width(), self.height() + step)
|
|
520
462
|
|
|
521
|
-
def
|
|
463
|
+
def _write_instructions(self):
|
|
522
464
|
|
|
523
465
|
model_name = self.modelname_le.text()
|
|
524
466
|
pretrained_model = self.pretrained_model
|
|
@@ -596,4 +538,7 @@ class ConfigSignalModelTraining(QMainWindow, Styles):
|
|
|
596
538
|
# return None
|
|
597
539
|
|
|
598
540
|
train_signal_model(model_folder+"training_instructions.json")
|
|
599
|
-
self.parent_window.refresh_signal_models()
|
|
541
|
+
self.parent_window.refresh_signal_models()
|
|
542
|
+
|
|
543
|
+
def _load_previous_instructions(self):
|
|
544
|
+
pass
|
|
@@ -1,21 +1,19 @@
|
|
|
1
|
+
from subprocess import Popen
|
|
1
2
|
|
|
2
|
-
from PyQt5.QtWidgets import
|
|
3
|
-
QGridLayout, QLineEdit, QVBoxLayout,
|
|
3
|
+
from PyQt5.QtWidgets import QMessageBox, QComboBox, QFrame, QCheckBox, \
|
|
4
|
+
QGridLayout, QLineEdit, QVBoxLayout, QLabel, QHBoxLayout, QPushButton
|
|
4
5
|
from PyQt5.QtCore import Qt, QSize
|
|
5
|
-
from PyQt5.QtGui import QIcon, QDoubleValidator, QIntValidator
|
|
6
6
|
|
|
7
|
-
from celldetective.gui.gui_utils import
|
|
7
|
+
from celldetective.gui.gui_utils import FeatureChoice, ListWidget, QHSeperationLine, FigureCanvas, \
|
|
8
8
|
GeometryChoice, OperationChoice
|
|
9
9
|
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
|
|
14
13
|
from celldetective.utils import extract_experiment_channels, get_software_location
|
|
15
14
|
from celldetective.io import load_frames, auto_load_number_of_frames
|
|
16
15
|
from celldetective.measure import compute_haralick_features
|
|
17
16
|
import numpy as np
|
|
18
|
-
from tifffile import imread
|
|
19
17
|
import json
|
|
20
18
|
import os
|
|
21
19
|
import matplotlib.pyplot as plt
|
|
@@ -27,11 +25,11 @@ from pathlib import Path
|
|
|
27
25
|
|
|
28
26
|
from celldetective.gui.viewers import CellEdgeVisualizer, SpotDetectionVisualizer
|
|
29
27
|
from celldetective.gui.layouts import ProtocolDesignerLayout, BackgroundFitCorrectionLayout, LocalCorrectionLayout
|
|
30
|
-
from celldetective.gui.gui_utils import
|
|
31
|
-
from celldetective.gui import
|
|
28
|
+
from celldetective.gui.gui_utils import PreprocessingLayout2
|
|
29
|
+
from celldetective.gui.settings._settings_base import CelldetectiveSettingsPanel
|
|
32
30
|
|
|
33
31
|
|
|
34
|
-
class
|
|
32
|
+
class SettingsMeasurements(CelldetectiveSettingsPanel):
|
|
35
33
|
"""
|
|
36
34
|
UI to set measurement instructions.
|
|
37
35
|
|
|
@@ -39,54 +37,33 @@ class ConfigMeasurements(QMainWindow, Styles):
|
|
|
39
37
|
|
|
40
38
|
def __init__(self, parent_window=None):
|
|
41
39
|
|
|
42
|
-
super().__init__()
|
|
43
|
-
|
|
44
40
|
self.parent_window = parent_window
|
|
45
|
-
self.setWindowTitle("Configure measurements")
|
|
46
|
-
self.setWindowIcon(QIcon(os.sep.join(['celldetective', 'icons', 'mexican-hat.png'])))
|
|
47
41
|
self.mode = self.parent_window.mode
|
|
48
42
|
self.exp_dir = self.parent_window.exp_dir
|
|
49
43
|
self.background_correction = []
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
self.measure_instructions_path = self.parent_window.exp_dir + "configs/measurement_instructions_targets.json"
|
|
53
|
-
elif self.mode == "effectors":
|
|
54
|
-
self.config_name = "btrack_config_effectors.json"
|
|
55
|
-
self.measure_instructions_path = self.parent_window.exp_dir + "configs/measurement_instructions_effectors.json"
|
|
56
|
-
self.soft_path = get_software_location()
|
|
44
|
+
self.config_name = f"btrack_config_{self.mode}.json"
|
|
45
|
+
self.measure_instructions_path = self.parent_window.exp_dir + f"configs/measurement_instructions_{self.mode}.json"
|
|
57
46
|
self.clear_previous = False
|
|
58
|
-
|
|
59
|
-
exp_config = self.exp_dir + "config.ini"
|
|
60
47
|
self.config_path = self.exp_dir + self.config_name
|
|
61
48
|
self.channel_names, self.channels = extract_experiment_channels(self.exp_dir)
|
|
62
49
|
self.channel_names = np.array(self.channel_names)
|
|
63
50
|
self.channels = np.array(self.channels)
|
|
51
|
+
|
|
52
|
+
super().__init__("Configure measurements")
|
|
64
53
|
|
|
65
|
-
self.
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
self.
|
|
69
|
-
self.
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
self.setMinimumHeight(int(0.3 * self.screen_height))
|
|
73
|
-
self.setMaximumHeight(int(0.8 * self.screen_height))
|
|
74
|
-
self.populate_widget()
|
|
75
|
-
self.load_previous_measurement_instructions()
|
|
76
|
-
|
|
77
|
-
def populate_widget(self):
|
|
54
|
+
self._add_to_layout()
|
|
55
|
+
self._load_previous_instructions()
|
|
56
|
+
|
|
57
|
+
self._adjustSize()
|
|
58
|
+
self.resize(int(self.width()), int(self._screen_height * 0.8))
|
|
59
|
+
|
|
60
|
+
def _create_widgets(self):
|
|
78
61
|
|
|
79
62
|
"""
|
|
80
63
|
Create the multibox design.
|
|
81
64
|
|
|
82
65
|
"""
|
|
83
|
-
|
|
84
|
-
# Create button widget and layout
|
|
85
|
-
self.scroll_area = QScrollArea(self)
|
|
86
|
-
self.button_widget = QWidget()
|
|
87
|
-
main_layout = QVBoxLayout()
|
|
88
|
-
self.button_widget.setLayout(main_layout)
|
|
89
|
-
main_layout.setContentsMargins(30, 30, 30, 30)
|
|
66
|
+
super()._create_widgets()
|
|
90
67
|
|
|
91
68
|
self.normalisation_frame = QFrame()
|
|
92
69
|
self.normalisation_frame.setFrameStyle(QFrame.StyledPanel | QFrame.Raised)
|
|
@@ -104,48 +81,31 @@ class ConfigMeasurements(QMainWindow, Styles):
|
|
|
104
81
|
self.normalisation_frame.setLayout(self.protocol_layout)
|
|
105
82
|
|
|
106
83
|
#self.populate_normalisation_tabs()
|
|
107
|
-
main_layout.addWidget(self.normalisation_frame)
|
|
108
84
|
|
|
109
85
|
# first frame for FEATURES
|
|
110
86
|
self.features_frame = QFrame()
|
|
111
87
|
self.features_frame.setFrameStyle(QFrame.StyledPanel | QFrame.Raised)
|
|
112
88
|
self.populate_features_frame()
|
|
113
|
-
main_layout.addWidget(self.features_frame)
|
|
114
89
|
|
|
115
90
|
# second frame for ISOTROPIC MEASUREMENTS
|
|
116
91
|
self.iso_frame = QFrame()
|
|
117
92
|
self.iso_frame.setFrameStyle(QFrame.StyledPanel | QFrame.Raised)
|
|
118
93
|
self.populate_iso_frame()
|
|
119
|
-
main_layout.addWidget(self.iso_frame)
|
|
120
94
|
|
|
121
95
|
self.spot_detection_frame = QFrame()
|
|
122
96
|
self.spot_detection_frame.setFrameStyle(QFrame.StyledPanel | QFrame.Raised)
|
|
123
97
|
self.populate_spot_detection()
|
|
124
|
-
main_layout.addWidget(self.spot_detection_frame)
|
|
125
98
|
|
|
126
99
|
self.clear_previous_btn = QCheckBox('clear previous measurements')
|
|
127
|
-
main_layout.addWidget(self.clear_previous_btn)
|
|
128
|
-
|
|
129
|
-
self.submit_btn = QPushButton('Save')
|
|
130
|
-
self.submit_btn.setStyleSheet(self.button_style_sheet)
|
|
131
|
-
self.submit_btn.clicked.connect(self.write_instructions)
|
|
132
|
-
main_layout.addWidget(self.submit_btn)
|
|
133
|
-
|
|
134
|
-
# self.populate_left_panel()
|
|
135
|
-
# grid.addLayout(self.left_side, 0, 0, 1, 1)
|
|
136
|
-
self.button_widget.adjustSize()
|
|
137
|
-
|
|
138
|
-
self.scroll_area.setAlignment(Qt.AlignCenter)
|
|
139
|
-
self.scroll_area.setWidget(self.button_widget)
|
|
140
|
-
self.scroll_area.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
|
|
141
|
-
self.scroll_area.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded)
|
|
142
|
-
self.scroll_area.setWidgetResizable(True)
|
|
143
|
-
self.setCentralWidget(self.scroll_area)
|
|
144
|
-
self.show()
|
|
145
|
-
|
|
146
|
-
QApplication.processEvents()
|
|
147
|
-
self.adjustScrollArea()
|
|
148
100
|
|
|
101
|
+
def _add_to_layout(self):
|
|
102
|
+
self._layout.addWidget(self.normalisation_frame)
|
|
103
|
+
self._layout.addWidget(self.features_frame)
|
|
104
|
+
self._layout.addWidget(self.iso_frame)
|
|
105
|
+
self._layout.addWidget(self.spot_detection_frame)
|
|
106
|
+
self._layout.addWidget(self.clear_previous_btn)
|
|
107
|
+
self._layout.addWidget(self.submit_btn)
|
|
108
|
+
|
|
149
109
|
def populate_iso_frame(self):
|
|
150
110
|
|
|
151
111
|
"""
|
|
@@ -264,12 +224,21 @@ class ConfigMeasurements(QMainWindow, Styles):
|
|
|
264
224
|
|
|
265
225
|
self.features_list = ListWidget(FeatureChoice, initial_features=['area', 'intensity_mean', ])
|
|
266
226
|
|
|
227
|
+
self.create_feature_btn = QPushButton("")
|
|
228
|
+
self.create_feature_btn.setStyleSheet(self.button_select_all)
|
|
229
|
+
self.create_feature_btn.setIcon(icon(MDI6.file_cog, color="black"))
|
|
230
|
+
self.create_feature_btn.setToolTip("Create new feature")
|
|
231
|
+
self.create_feature_btn.setIconSize(QSize(20, 20))
|
|
232
|
+
|
|
267
233
|
self.del_feature_btn.clicked.connect(self.features_list.removeSel)
|
|
268
234
|
self.add_feature_btn.clicked.connect(self.features_list.addItem)
|
|
235
|
+
self.create_feature_btn.clicked.connect(self.go_to_extraprops)
|
|
269
236
|
|
|
270
237
|
feature_layout.addWidget(self.feature_lbl, 90)
|
|
271
238
|
feature_layout.addWidget(self.del_feature_btn, 5)
|
|
272
239
|
feature_layout.addWidget(self.add_feature_btn, 5)
|
|
240
|
+
feature_layout.addWidget(self.create_feature_btn, 5)
|
|
241
|
+
|
|
273
242
|
layout.addLayout(feature_layout)
|
|
274
243
|
layout.addWidget(self.features_list)
|
|
275
244
|
|
|
@@ -334,7 +303,7 @@ class ConfigMeasurements(QMainWindow, Styles):
|
|
|
334
303
|
self.haralick_scale_slider.setSingleStep(0.05)
|
|
335
304
|
self.haralick_scale_slider.setTickInterval(0.05)
|
|
336
305
|
self.haralick_scale_slider.setSingleStep(1)
|
|
337
|
-
self.haralick_scale_slider.setOrientation(
|
|
306
|
+
self.haralick_scale_slider.setOrientation(Qt.Horizontal)
|
|
338
307
|
self.haralick_scale_slider.setRange(0, 1)
|
|
339
308
|
self.haralick_scale_slider.setValue(0.5)
|
|
340
309
|
self.haralick_scale_lbl = QLabel('Scale: ')
|
|
@@ -426,6 +395,18 @@ class ConfigMeasurements(QMainWindow, Styles):
|
|
|
426
395
|
self.haralick_normalization_mode_btn.clicked.connect(self.switch_to_absolute_normalization_mode)
|
|
427
396
|
layout.addLayout(self.haralick_layout)
|
|
428
397
|
|
|
398
|
+
def go_to_extraprops(self):
|
|
399
|
+
|
|
400
|
+
path = os.sep.join([self._software_path,'celldetective',os.sep,'extra_properties.py'])
|
|
401
|
+
try:
|
|
402
|
+
Popen(f'explorer {os.path.realpath(path)}')
|
|
403
|
+
except:
|
|
404
|
+
|
|
405
|
+
try:
|
|
406
|
+
os.system('xdg-open "%s"' % path)
|
|
407
|
+
except:
|
|
408
|
+
return None
|
|
409
|
+
|
|
429
410
|
def switch_to_absolute_normalization_mode(self):
|
|
430
411
|
|
|
431
412
|
if self.percentile_mode:
|
|
@@ -472,7 +453,7 @@ class ConfigMeasurements(QMainWindow, Styles):
|
|
|
472
453
|
while self.scroll_area.verticalScrollBar().isVisible() and self.height() < self.maximumHeight():
|
|
473
454
|
self.resize(self.width(), self.height() + step)
|
|
474
455
|
|
|
475
|
-
def
|
|
456
|
+
def _write_instructions(self):
|
|
476
457
|
|
|
477
458
|
"""
|
|
478
459
|
Write the selected options in a json file for later reading by the software.
|
|
@@ -551,7 +532,7 @@ class ConfigMeasurements(QMainWindow, Styles):
|
|
|
551
532
|
else:
|
|
552
533
|
self.haralick_options = None
|
|
553
534
|
|
|
554
|
-
def
|
|
535
|
+
def _load_previous_instructions(self):
|
|
555
536
|
|
|
556
537
|
"""
|
|
557
538
|
Read the measurmeent options from a previously written json file and format properly for the UI.
|
|
@@ -670,18 +651,6 @@ class ConfigMeasurements(QMainWindow, Styles):
|
|
|
670
651
|
else:
|
|
671
652
|
self.operations_list.list_widget.clear()
|
|
672
653
|
|
|
673
|
-
# if 'radial_intensity' in measurement_instructions:
|
|
674
|
-
# radial_intensity = measurement_instructions['radial_intensity']
|
|
675
|
-
# if radial_intensity is not None:
|
|
676
|
-
# self.radial_intensity_btn.setChecked(True)
|
|
677
|
-
# self.step_size.setText(str(radial_intensity['radial_step']))
|
|
678
|
-
# self.step_size.setEnabled(True)
|
|
679
|
-
# self.step_lbl.setEnabled(True)
|
|
680
|
-
# for checkbox in self.channel_chechkboxes:
|
|
681
|
-
# checkbox.setEnabled(True)
|
|
682
|
-
# if checkbox.text() in radial_intensity['radial_channels']:
|
|
683
|
-
# checkbox.setChecked(True)
|
|
684
|
-
|
|
685
654
|
if 'clear_previous' in measurement_instructions:
|
|
686
655
|
self.clear_previous = measurement_instructions['clear_previous']
|
|
687
656
|
self.clear_previous_btn.setChecked(self.clear_previous)
|
|
@@ -703,6 +672,7 @@ class ConfigMeasurements(QMainWindow, Styles):
|
|
|
703
672
|
returnValue = msgBox.exec()
|
|
704
673
|
if returnValue == QMessageBox.Ok:
|
|
705
674
|
self.current_stack = None
|
|
675
|
+
self.test_frame = None
|
|
706
676
|
return None
|
|
707
677
|
else:
|
|
708
678
|
self.current_stack = movies[0]
|
|
@@ -931,7 +901,7 @@ class ConfigMeasurements(QMainWindow, Styles):
|
|
|
931
901
|
diam_hbox = QHBoxLayout()
|
|
932
902
|
self.diameter_lbl = QLabel('Spot diameter: ')
|
|
933
903
|
self.diameter_value = QLineEdit()
|
|
934
|
-
self.diameter_value.setValidator(self.
|
|
904
|
+
self.diameter_value.setValidator(self._floatValidator)
|
|
935
905
|
self.diameter_value.setText('7')
|
|
936
906
|
self.diameter_value.textChanged.connect(self.enable_spot_preview)
|
|
937
907
|
|
|
@@ -942,7 +912,7 @@ class ConfigMeasurements(QMainWindow, Styles):
|
|
|
942
912
|
thresh_hbox = QHBoxLayout()
|
|
943
913
|
self.threshold_lbl = QLabel('Spot threshold: ')
|
|
944
914
|
self.threshold_value = QLineEdit()
|
|
945
|
-
self.threshold_value.setValidator(self.
|
|
915
|
+
self.threshold_value.setValidator(self._floatValidator)
|
|
946
916
|
self.threshold_value.setText('0')
|
|
947
917
|
self.threshold_value.textChanged.connect(self.enable_spot_preview)
|
|
948
918
|
|
|
@@ -950,14 +920,6 @@ class ConfigMeasurements(QMainWindow, Styles):
|
|
|
950
920
|
thresh_hbox.addWidget(self.threshold_value, 70)
|
|
951
921
|
layout.addLayout(thresh_hbox)
|
|
952
922
|
|
|
953
|
-
# #invert_layout = QHBoxLayout()
|
|
954
|
-
# self.invert_check = QCheckBox('invert')
|
|
955
|
-
# self.invert_value_le = QLineEdit('65535')
|
|
956
|
-
# self.invert_value_le.setValidator(self.onlyFloat)
|
|
957
|
-
# layout.addWidget(self.invert_check, 6, 0)
|
|
958
|
-
# layout.addWidget(self.invert_value_le, 6, 1)
|
|
959
|
-
# #layout.addLayout(invert_layout, 5, 1, 1, 1)
|
|
960
|
-
|
|
961
923
|
self.spot_detection_widgets = [self.spot_channel,
|
|
962
924
|
self.spot_channel_lbl,
|
|
963
925
|
self.diameter_value,
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
from PyQt5.QtWidgets import QApplication, QComboBox, QFrame, QCheckBox, QVBoxLayout,
|
|
1
|
+
from PyQt5.QtWidgets import QApplication, QComboBox, QFrame, QCheckBox, QVBoxLayout, QLabel, QHBoxLayout, QPushButton
|
|
2
2
|
from PyQt5.QtCore import Qt, QSize
|
|
3
|
-
from PyQt5.QtGui import QIcon
|
|
4
3
|
from celldetective.gui.gui_utils import center_window, ListWidget, DistanceChoice
|
|
5
4
|
from superqt.fonticon import icon
|
|
6
5
|
from fonticon_mdi6 import MDI6
|
|
@@ -10,9 +9,10 @@ import os
|
|
|
10
9
|
from glob import glob
|
|
11
10
|
import pandas as pd
|
|
12
11
|
from celldetective.gui.viewers import CellSizeViewer, CellEdgeVisualizer
|
|
13
|
-
from celldetective.gui import
|
|
12
|
+
from celldetective.gui import CelldetectiveWidget
|
|
14
13
|
|
|
15
|
-
|
|
14
|
+
|
|
15
|
+
class SettingsNeighborhood(CelldetectiveWidget):
|
|
16
16
|
|
|
17
17
|
"""
|
|
18
18
|
Widget to configure neighborhood measurements.
|
|
@@ -24,7 +24,6 @@ class ConfigNeighborhoods(QWidget, Styles):
|
|
|
24
24
|
super().__init__(*args, **kwargs)
|
|
25
25
|
self.parent_window = parent_window
|
|
26
26
|
self.attr_parent = self.parent_window.parent_window
|
|
27
|
-
self.setWindowIcon(QIcon(os.sep.join(['celldetective','icons','logo.png'])))
|
|
28
27
|
|
|
29
28
|
self.neighborhood_type = neighborhood_type
|
|
30
29
|
self.neighborhood_parameter_name = neighborhood_parameter_name
|
|
@@ -43,7 +42,6 @@ class ConfigNeighborhoods(QWidget, Styles):
|
|
|
43
42
|
self.generate_main_layout()
|
|
44
43
|
self.load_previous_neighborhood_instructions()
|
|
45
44
|
center_window(self)
|
|
46
|
-
self.setAttribute(Qt.WA_DeleteOnClose)
|
|
47
45
|
|
|
48
46
|
def generate_main_layout(self):
|
|
49
47
|
|
|
@@ -140,7 +138,7 @@ class ConfigNeighborhoods(QWidget, Styles):
|
|
|
140
138
|
|
|
141
139
|
layout.addLayout(list_header_layout)
|
|
142
140
|
|
|
143
|
-
self.measurements_list = ListWidget(DistanceChoice, initial_features=[
|
|
141
|
+
self.measurements_list = ListWidget(DistanceChoice, initial_features=[], dtype=int)
|
|
144
142
|
self.measurements_list.setToolTip('Neighborhoods to compute.')
|
|
145
143
|
layout.addWidget(self.measurements_list)
|
|
146
144
|
|
|
@@ -211,7 +209,7 @@ class ConfigNeighborhoods(QWidget, Styles):
|
|
|
211
209
|
population_layout = QHBoxLayout()
|
|
212
210
|
population_layout.addWidget(QLabel('population: '),30)
|
|
213
211
|
self.reference_population_cb = QComboBox()
|
|
214
|
-
self.reference_population_cb.addItems(
|
|
212
|
+
self.reference_population_cb.addItems(self.parent_window.parent_window.populations)
|
|
215
213
|
self.reference_population_cb.setToolTip('Select a reference population.')
|
|
216
214
|
population_layout.addWidget(self.reference_population_cb,70)
|
|
217
215
|
layout.addLayout(population_layout)
|
|
@@ -271,7 +269,7 @@ class ConfigNeighborhoods(QWidget, Styles):
|
|
|
271
269
|
population_layout = QHBoxLayout()
|
|
272
270
|
population_layout.addWidget(QLabel('population: '),30)
|
|
273
271
|
self.neighbor_population_cb = QComboBox()
|
|
274
|
-
self.neighbor_population_cb.addItems(
|
|
272
|
+
self.neighbor_population_cb.addItems(self.parent_window.parent_window.populations)
|
|
275
273
|
self.neighbor_population_cb.setToolTip('Select a neighbor population.')
|
|
276
274
|
population_layout.addWidget(self.neighbor_population_cb,70)
|
|
277
275
|
layout.addLayout(population_layout)
|
|
@@ -315,15 +313,14 @@ class ConfigNeighborhoods(QWidget, Styles):
|
|
|
315
313
|
population = self.neighbor_population_cb.currentText()
|
|
316
314
|
class_cols, status_cols, group_cols, time_cols = self.locate_population_specific_columns(population)
|
|
317
315
|
self.neighbor_population_status_cb.clear()
|
|
318
|
-
self.neighbor_population_status_cb.addItems(['--','class', 'status']+class_cols+status_cols+group_cols)
|
|
316
|
+
self.neighbor_population_status_cb.addItems(list(np.unique(['--','class', 'status']+class_cols+status_cols+group_cols)))
|
|
319
317
|
|
|
320
318
|
def fill_cbs_of_reference_population(self):
|
|
321
319
|
|
|
322
320
|
population = self.reference_population_cb.currentText()
|
|
323
321
|
class_cols, status_cols, group_cols, time_cols = self.locate_population_specific_columns(population)
|
|
324
|
-
self.
|
|
325
|
-
self.
|
|
326
|
-
self.event_time_cb.addItems(['--', 't0']+time_cols)
|
|
322
|
+
self.event_time_cb.clear()
|
|
323
|
+
self.event_time_cb.addItems(list(np.unique(['--', 't0']+time_cols)))
|
|
327
324
|
|
|
328
325
|
def switch_not_reference(self):
|
|
329
326
|
|