celldetective 1.3.6.post1__py3-none-any.whl → 1.3.7__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/events.py +4 -0
- celldetective/filters.py +11 -2
- celldetective/gui/InitWindow.py +23 -9
- celldetective/gui/control_panel.py +19 -11
- celldetective/gui/generic_signal_plot.py +5 -0
- celldetective/gui/gui_utils.py +2 -2
- celldetective/gui/help/DL-segmentation-strategy.json +17 -17
- celldetective/gui/help/Threshold-vs-DL.json +11 -11
- celldetective/gui/help/cell-populations.json +5 -5
- celldetective/gui/help/exp-structure.json +15 -15
- celldetective/gui/help/feature-btrack.json +5 -5
- celldetective/gui/help/neighborhood.json +7 -7
- celldetective/gui/help/prefilter-for-segmentation.json +7 -7
- celldetective/gui/help/preprocessing.json +19 -19
- celldetective/gui/help/propagate-classification.json +7 -7
- celldetective/gui/neighborhood_options.py +1 -1
- celldetective/gui/plot_signals_ui.py +13 -9
- celldetective/gui/process_block.py +63 -14
- celldetective/gui/retrain_segmentation_model_options.py +21 -8
- celldetective/gui/retrain_signal_model_options.py +12 -2
- celldetective/gui/signal_annotator.py +9 -0
- celldetective/gui/signal_annotator2.py +25 -17
- celldetective/gui/styles.py +1 -0
- celldetective/gui/tableUI.py +1 -1
- celldetective/gui/workers.py +136 -0
- celldetective/io.py +54 -28
- celldetective/measure.py +112 -14
- celldetective/scripts/measure_cells.py +36 -46
- celldetective/scripts/segment_cells.py +35 -78
- celldetective/scripts/segment_cells_thresholds.py +21 -22
- celldetective/scripts/track_cells.py +43 -32
- celldetective/segmentation.py +16 -62
- celldetective/signals.py +11 -7
- celldetective/utils.py +587 -67
- {celldetective-1.3.6.post1.dist-info → celldetective-1.3.7.dist-info}/METADATA +1 -1
- {celldetective-1.3.6.post1.dist-info → celldetective-1.3.7.dist-info}/RECORD +41 -40
- {celldetective-1.3.6.post1.dist-info → celldetective-1.3.7.dist-info}/LICENSE +0 -0
- {celldetective-1.3.6.post1.dist-info → celldetective-1.3.7.dist-info}/WHEEL +0 -0
- {celldetective-1.3.6.post1.dist-info → celldetective-1.3.7.dist-info}/entry_points.txt +0 -0
- {celldetective-1.3.6.post1.dist-info → celldetective-1.3.7.dist-info}/top_level.txt +0 -0
|
@@ -6,7 +6,7 @@ from PyQt5.QtGui import QIcon, QDoubleValidator
|
|
|
6
6
|
from celldetective.gui.gui_utils import center_window
|
|
7
7
|
from celldetective.gui.generic_signal_plot import GenericSignalPlotWidget
|
|
8
8
|
from superqt import QLabeledSlider, QColormapComboBox, QSearchableComboBox
|
|
9
|
-
from celldetective.utils import get_software_location, _extract_labels_from_config
|
|
9
|
+
from celldetective.utils import get_software_location, _extract_labels_from_config, extract_cols_from_table_list
|
|
10
10
|
from celldetective.io import load_experiment_tables
|
|
11
11
|
from celldetective.signals import mean_signal
|
|
12
12
|
import numpy as np
|
|
@@ -15,7 +15,6 @@ import matplotlib.pyplot as plt
|
|
|
15
15
|
plt.rcParams['svg.fonttype'] = 'none'
|
|
16
16
|
from glob import glob
|
|
17
17
|
from natsort import natsorted
|
|
18
|
-
import pandas as pd
|
|
19
18
|
import math
|
|
20
19
|
from celldetective.gui import Styles
|
|
21
20
|
from matplotlib import colormaps
|
|
@@ -92,8 +91,14 @@ class ConfigSignalPlot(QWidget, Styles):
|
|
|
92
91
|
""")
|
|
93
92
|
main_layout.addWidget(panel_title, alignment=Qt.AlignCenter)
|
|
94
93
|
|
|
94
|
+
pops = []
|
|
95
|
+
for population in ['effectors','targets','pairs']:
|
|
96
|
+
tables = glob(self.exp_dir+os.sep.join(['W*','*','output','tables',f'trajectories_{population}.csv']))
|
|
97
|
+
if len(tables)>0:
|
|
98
|
+
pops.append(population)
|
|
99
|
+
|
|
95
100
|
labels = [QLabel('population: '), QLabel('class: '), QLabel('time of\ninterest: '), QLabel('cmap: ')]
|
|
96
|
-
self.cb_options = [
|
|
101
|
+
self.cb_options = [pops,[], [], []]
|
|
97
102
|
self.cbs = [QComboBox() for i in range(len(labels))]
|
|
98
103
|
self.cbs[-1] = QColormapComboBox()
|
|
99
104
|
|
|
@@ -161,12 +166,11 @@ class ConfigSignalPlot(QWidget, Styles):
|
|
|
161
166
|
def set_classes_and_times(self):
|
|
162
167
|
|
|
163
168
|
# Look for all classes and times
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
self.all_columns = np.unique(self.all_columns)
|
|
169
|
+
population = self.cbs[0].currentText()
|
|
170
|
+
tables = natsorted(glob(self.exp_dir+os.sep.join(['W*','*','output','tables',f'trajectories_{population}.csv'])))
|
|
171
|
+
|
|
172
|
+
self.all_columns = extract_cols_from_table_list(tables)
|
|
173
|
+
|
|
170
174
|
class_idx = np.array([s.startswith('class_') for s in self.all_columns])
|
|
171
175
|
time_idx = np.array([s.startswith('t_') for s in self.all_columns])
|
|
172
176
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from PyQt5.QtWidgets import QFrame, QGridLayout, QComboBox, QListWidget, QLabel, QPushButton, QVBoxLayout, QHBoxLayout, QCheckBox, \
|
|
1
|
+
from PyQt5.QtWidgets import QDialog, QFrame, QGridLayout, QComboBox, QListWidget, QLabel, QPushButton, QVBoxLayout, QHBoxLayout, QCheckBox, \
|
|
2
2
|
QMessageBox, QWidget
|
|
3
3
|
from PyQt5.QtCore import Qt, QSize
|
|
4
4
|
from superqt.fonticon import icon
|
|
@@ -10,7 +10,7 @@ from celldetective.gui.signal_annotator import MeasureAnnotator
|
|
|
10
10
|
from celldetective.gui.signal_annotator2 import SignalAnnotator2
|
|
11
11
|
from celldetective.io import get_segmentation_models_list, control_segmentation_napari, get_signal_models_list, \
|
|
12
12
|
control_tracks, load_experiment_tables, get_pair_signal_models_list
|
|
13
|
-
from celldetective.io import locate_segmentation_model, fix_missing_labels, auto_load_number_of_frames, load_frames, locate_signal_model
|
|
13
|
+
from celldetective.io import locate_segmentation_model, extract_position_name, fix_missing_labels, auto_load_number_of_frames, load_frames, locate_signal_model
|
|
14
14
|
from celldetective.gui import SegmentationModelLoader, ClassifierWidget, ConfigNeighborhoods, ConfigSegmentationModelTraining, ConfigTracking, SignalAnnotator, ConfigSignalModelTraining, ConfigMeasurements, ConfigSignalAnnotator, TableUI
|
|
15
15
|
from celldetective.gui.gui_utils import QHSeperationLine
|
|
16
16
|
from celldetective.relative_measurements import rel_measure_at_position
|
|
@@ -37,6 +37,14 @@ from celldetective.gui.layouts import CellposeParamsWidget, StarDistParamsWidget
|
|
|
37
37
|
from celldetective.gui import Styles
|
|
38
38
|
from celldetective.utils import get_software_location
|
|
39
39
|
|
|
40
|
+
from celldetective.gui.workers import ProgressWindow
|
|
41
|
+
from celldetective.gui.processes.segment_cells import SegmentCellThresholdProcess, SegmentCellDLProcess
|
|
42
|
+
from celldetective.gui.processes.track_cells import TrackingProcess
|
|
43
|
+
from celldetective.gui.processes.measure_cells import MeasurementProcess
|
|
44
|
+
|
|
45
|
+
import time
|
|
46
|
+
import asyncio
|
|
47
|
+
|
|
40
48
|
class ProcessPanel(QFrame, Styles):
|
|
41
49
|
def __init__(self, parent_window, mode):
|
|
42
50
|
|
|
@@ -52,6 +60,8 @@ class ProcessPanel(QFrame, Styles):
|
|
|
52
60
|
self.wells = np.array(self.parent_window.wells,dtype=str)
|
|
53
61
|
self.cellpose_calibrated = False
|
|
54
62
|
self.stardist_calibrated = False
|
|
63
|
+
self.use_gpu = self.parent_window.parent_window.use_gpu
|
|
64
|
+
self.n_threads = self.parent_window.parent_window.n_threads
|
|
55
65
|
|
|
56
66
|
self.setFrameStyle(QFrame.StyledPanel | QFrame.Raised)
|
|
57
67
|
self.grid = QGridLayout(self)
|
|
@@ -264,7 +274,7 @@ class ProcessPanel(QFrame, Styles):
|
|
|
264
274
|
#self.to_disable.append(self.cell_models_list)
|
|
265
275
|
|
|
266
276
|
self.train_signal_model_btn = QPushButton("TRAIN")
|
|
267
|
-
self.train_signal_model_btn.setToolTip("
|
|
277
|
+
self.train_signal_model_btn.setToolTip("Train or retrain an event detection model\non newly annotated data.")
|
|
268
278
|
self.train_signal_model_btn.setIcon(icon(MDI6.redo_variant,color='black'))
|
|
269
279
|
self.train_signal_model_btn.setIconSize(QSize(20, 20))
|
|
270
280
|
self.train_signal_model_btn.setStyleSheet(self.button_style_sheet_3)
|
|
@@ -284,7 +294,7 @@ class ProcessPanel(QFrame, Styles):
|
|
|
284
294
|
self.signal_models_list.addItems(signal_models)
|
|
285
295
|
|
|
286
296
|
def generate_tracking_options(self):
|
|
287
|
-
|
|
297
|
+
|
|
288
298
|
grid_track = QHBoxLayout()
|
|
289
299
|
|
|
290
300
|
self.track_action = QCheckBox("TRACK")
|
|
@@ -363,7 +373,7 @@ class ProcessPanel(QFrame, Styles):
|
|
|
363
373
|
self.segment_action = QCheckBox("SEGMENT")
|
|
364
374
|
self.segment_action.setStyleSheet(self.menu_check_style)
|
|
365
375
|
self.segment_action.setIcon(icon(MDI6.bacteria, color='black'))
|
|
366
|
-
self.segment_action.setToolTip(f"Segment the {self.mode} cells on the images.")
|
|
376
|
+
self.segment_action.setToolTip(f"Segment the {self.mode[:-1]} cells on the images.")
|
|
367
377
|
self.segment_action.toggled.connect(self.enable_segmentation_model_list)
|
|
368
378
|
#self.to_disable.append(self.segment_action)
|
|
369
379
|
grid_segment.addWidget(self.segment_action, 90)
|
|
@@ -390,6 +400,7 @@ class ProcessPanel(QFrame, Styles):
|
|
|
390
400
|
model_zoo_layout = QHBoxLayout()
|
|
391
401
|
model_zoo_layout.addWidget(QLabel("Model zoo:"),90)
|
|
392
402
|
self.seg_model_list = QComboBox()
|
|
403
|
+
self.seg_model_list.currentIndexChanged.connect(self.reset_generalist_setup)
|
|
393
404
|
#self.to_disable.append(self.tc_seg_model_list)
|
|
394
405
|
self.seg_model_list.setGeometry(50, 50, 200, 30)
|
|
395
406
|
self.init_seg_model_list()
|
|
@@ -682,6 +693,10 @@ class ProcessPanel(QFrame, Styles):
|
|
|
682
693
|
self.ConfigSignalAnnotator = ConfigSignalAnnotator(self)
|
|
683
694
|
self.ConfigSignalAnnotator.show()
|
|
684
695
|
|
|
696
|
+
def reset_generalist_setup(self, index):
|
|
697
|
+
self.cellpose_calibrated = False
|
|
698
|
+
self.stardist_calibrated = False
|
|
699
|
+
|
|
685
700
|
def process_population(self):
|
|
686
701
|
|
|
687
702
|
# if self.parent_window.well_list.currentText().startswith('Multiple'):
|
|
@@ -750,18 +765,19 @@ class ProcessPanel(QFrame, Styles):
|
|
|
750
765
|
self.model_name = self.seg_models[self.seg_model_list.currentIndex()]
|
|
751
766
|
print(self.model_name, self.seg_model_list.currentIndex())
|
|
752
767
|
|
|
753
|
-
if self.model_name.startswith('CP') and self.model_name in self.seg_models_generic and not self.cellpose_calibrated:
|
|
768
|
+
if self.segment_action.isChecked() and self.model_name.startswith('CP') and self.model_name in self.seg_models_generic and not self.cellpose_calibrated:
|
|
754
769
|
|
|
755
770
|
self.diamWidget = CellposeParamsWidget(self, model_name=self.model_name)
|
|
756
771
|
self.diamWidget.show()
|
|
757
772
|
return None
|
|
758
773
|
|
|
759
|
-
if self.model_name.startswith('SD') and self.model_name in self.seg_models_generic and not self.stardist_calibrated:
|
|
774
|
+
if self.segment_action.isChecked() and self.model_name.startswith('SD') and self.model_name in self.seg_models_generic and not self.stardist_calibrated:
|
|
760
775
|
|
|
761
776
|
self.diamWidget = StarDistParamsWidget(self, model_name = self.model_name)
|
|
762
777
|
self.diamWidget.show()
|
|
763
778
|
return None
|
|
764
779
|
|
|
780
|
+
self.movie_prefix = self.parent_window.movie_prefix
|
|
765
781
|
|
|
766
782
|
for w_idx in self.well_index:
|
|
767
783
|
|
|
@@ -775,6 +791,7 @@ class ProcessPanel(QFrame, Styles):
|
|
|
775
791
|
|
|
776
792
|
self.pos = natsorted(glob(well+f"{os.path.split(well)[-1].replace('W','').replace(os.sep,'')}*/"))[pos_idx]
|
|
777
793
|
print(f"Position {self.pos}...\nLoading stack movie...")
|
|
794
|
+
self.pos_name = extract_position_name(self.pos)
|
|
778
795
|
|
|
779
796
|
if not os.path.exists(self.pos + 'output/'):
|
|
780
797
|
os.mkdir(self.pos + 'output/')
|
|
@@ -805,9 +822,27 @@ class ProcessPanel(QFrame, Styles):
|
|
|
805
822
|
return None
|
|
806
823
|
else:
|
|
807
824
|
print(f"Segmentation from threshold config: {self.threshold_config}")
|
|
808
|
-
|
|
825
|
+
process_args = {"pos": self.pos, "mode": self.mode, "n_threads": self.n_threads, "threshold_instructions": self.threshold_config, "use_gpu": self.use_gpu}
|
|
826
|
+
self.job = ProgressWindow(SegmentCellThresholdProcess, parent_window=self, title="Segment", process_args = process_args)
|
|
827
|
+
result = self.job.exec_()
|
|
828
|
+
if result == QDialog.Accepted:
|
|
829
|
+
pass
|
|
830
|
+
elif result == QDialog.Rejected:
|
|
831
|
+
return None
|
|
832
|
+
#segment_from_threshold_at_position(self.pos, self.mode, self.threshold_config, threads=self.parent_window.parent_window.n_threads)
|
|
809
833
|
else:
|
|
810
|
-
|
|
834
|
+
# model = locate_segmentation_model(self.model_name)
|
|
835
|
+
# if model is None:
|
|
836
|
+
# process = {"output_dir": self.output_dir, "file": self.model_name}
|
|
837
|
+
# self.download_model_job = ProgressWindow(DownloadProcess, parent_window=self, title="Download", process_args = args)
|
|
838
|
+
|
|
839
|
+
process_args = {"pos": self.pos, "mode": self.mode, "n_threads": self.n_threads, "model_name": self.model_name, "use_gpu": self.use_gpu}
|
|
840
|
+
self.job = ProgressWindow(SegmentCellDLProcess, parent_window=self, title="Segment", process_args = process_args)
|
|
841
|
+
result = self.job.exec_()
|
|
842
|
+
if result == QDialog.Accepted:
|
|
843
|
+
pass
|
|
844
|
+
elif result == QDialog.Rejected:
|
|
845
|
+
return None
|
|
811
846
|
|
|
812
847
|
if self.track_action.isChecked():
|
|
813
848
|
if os.path.exists(os.sep.join([self.pos, 'output', 'tables', f'trajectories_{self.mode}.csv'])) and not self.parent_window.position_list.isMultipleSelection():
|
|
@@ -819,10 +854,25 @@ class ProcessPanel(QFrame, Styles):
|
|
|
819
854
|
returnValue = msgBox.exec()
|
|
820
855
|
if returnValue == QMessageBox.No:
|
|
821
856
|
return None
|
|
822
|
-
|
|
857
|
+
|
|
858
|
+
process_args = {"pos": self.pos, "mode": self.mode, "n_threads": self.n_threads}
|
|
859
|
+
self.job = ProgressWindow(TrackingProcess, parent_window=self, title="Tracking", process_args=process_args)
|
|
860
|
+
result = self.job.exec_()
|
|
861
|
+
if result == QDialog.Accepted:
|
|
862
|
+
pass
|
|
863
|
+
elif result == QDialog.Rejected:
|
|
864
|
+
return None
|
|
865
|
+
#track_at_position(self.pos, self.mode, threads=self.parent_window.parent_window.n_threads)
|
|
823
866
|
|
|
824
867
|
if self.measure_action.isChecked():
|
|
825
|
-
|
|
868
|
+
process_args = {"pos": self.pos, "mode": self.mode, "n_threads": self.n_threads}
|
|
869
|
+
self.job = ProgressWindow(MeasurementProcess, parent_window=self, title="Measurement", process_args=process_args)
|
|
870
|
+
result = self.job.exec_()
|
|
871
|
+
if result == QDialog.Accepted:
|
|
872
|
+
pass
|
|
873
|
+
elif result == QDialog.Rejected:
|
|
874
|
+
return None
|
|
875
|
+
#measure_at_position(self.pos, self.mode, threads=self.parent_window.parent_window.n_threads)
|
|
826
876
|
|
|
827
877
|
table = os.sep.join([self.pos, 'output', 'tables', f'trajectories_{self.mode}.csv'])
|
|
828
878
|
if self.signal_analysis_action.isChecked() and os.path.exists(table):
|
|
@@ -845,12 +895,11 @@ class ProcessPanel(QFrame, Styles):
|
|
|
845
895
|
|
|
846
896
|
# self.stack = None
|
|
847
897
|
self.parent_window.update_position_options()
|
|
848
|
-
|
|
849
898
|
for action in [self.segment_action, self.track_action, self.measure_action, self.signal_analysis_action]:
|
|
850
899
|
if action.isChecked():
|
|
851
900
|
action.setChecked(False)
|
|
852
901
|
|
|
853
|
-
self.
|
|
902
|
+
self.reset_generalist_setup(0)
|
|
854
903
|
|
|
855
904
|
def open_napari_tracking(self):
|
|
856
905
|
print(f'View the tracks before post-processing for position {self.parent_window.pos} in napari...')
|
|
@@ -1207,7 +1256,7 @@ class NeighPanel(QFrame, Styles):
|
|
|
1207
1256
|
self.neigh_action.setChecked(False)
|
|
1208
1257
|
|
|
1209
1258
|
def open_classifier_ui_pairs(self):
|
|
1210
|
-
|
|
1259
|
+
|
|
1211
1260
|
self.mode = "pairs"
|
|
1212
1261
|
self.load_available_tables()
|
|
1213
1262
|
if self.df is None:
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from PyQt5.QtWidgets import QMainWindow, QApplication,QRadioButton, QMessageBox, QScrollArea, QComboBox, QFrame, QFileDialog, QGridLayout, QLineEdit, QVBoxLayout, QWidget, QLabel, QHBoxLayout, QPushButton
|
|
1
|
+
from PyQt5.QtWidgets import QDialog, QMainWindow, QApplication,QRadioButton, QMessageBox, QScrollArea, QComboBox, QFrame, QFileDialog, QGridLayout, QLineEdit, QVBoxLayout, QWidget, QLabel, QHBoxLayout, QPushButton
|
|
2
2
|
from PyQt5.QtCore import Qt, QSize
|
|
3
3
|
from PyQt5.QtGui import QDoubleValidator, QIntValidator, QIcon
|
|
4
4
|
from celldetective.gui.gui_utils import center_window
|
|
@@ -17,6 +17,8 @@ import os
|
|
|
17
17
|
from glob import glob
|
|
18
18
|
from datetime import datetime
|
|
19
19
|
from celldetective.gui import Styles
|
|
20
|
+
from celldetective.gui.processes.train_segmentation_model import TrainSegModelProcess
|
|
21
|
+
from celldetective.gui.workers import ProgressWindow
|
|
20
22
|
|
|
21
23
|
class ConfigSegmentationModelTraining(QMainWindow, Styles):
|
|
22
24
|
|
|
@@ -29,6 +31,7 @@ class ConfigSegmentationModelTraining(QMainWindow, Styles):
|
|
|
29
31
|
|
|
30
32
|
super().__init__()
|
|
31
33
|
self.parent_window = parent_window
|
|
34
|
+
self.use_gpu = self.parent_window.use_gpu
|
|
32
35
|
self.setWindowTitle("Train segmentation model")
|
|
33
36
|
self.setWindowIcon(QIcon(os.sep.join(['celldetective','icons','mexican-hat.png'])))
|
|
34
37
|
self.mode = self.parent_window.mode
|
|
@@ -239,7 +242,7 @@ class ConfigSegmentationModelTraining(QMainWindow, Styles):
|
|
|
239
242
|
self.augmentation_slider.setSingleStep(0.01)
|
|
240
243
|
self.augmentation_slider.setTickInterval(0.01)
|
|
241
244
|
self.augmentation_slider.setOrientation(1)
|
|
242
|
-
self.augmentation_slider.setRange(
|
|
245
|
+
self.augmentation_slider.setRange(0.01, 3)
|
|
243
246
|
self.augmentation_slider.setValue(2.0)
|
|
244
247
|
|
|
245
248
|
augmentation_hbox.addWidget(self.augmentation_slider, 70)
|
|
@@ -597,24 +600,34 @@ class ConfigSegmentationModelTraining(QMainWindow, Styles):
|
|
|
597
600
|
epochs = self.epochs_slider.value()
|
|
598
601
|
spatial_calib = float(self.spatial_calib_le.text().replace(',','.'))
|
|
599
602
|
|
|
600
|
-
training_instructions = {'model_name': model_name,'model_type': model_type, 'pretrained': pretrained_model, 'spatial_calibration': spatial_calib, 'channel_option': channels, 'normalization_percentile': normalization_mode,
|
|
603
|
+
self.training_instructions = {'model_name': model_name,'model_type': model_type, 'pretrained': pretrained_model, 'spatial_calibration': spatial_calib, 'channel_option': channels, 'normalization_percentile': normalization_mode,
|
|
601
604
|
'normalization_clip': clip_values,'normalization_values': norm_values, 'ds': data_folders, 'augmentation_factor': aug_factor, 'validation_split': val_split,
|
|
602
605
|
'learning_rate': lr, 'batch_size': bs, 'epochs': epochs}
|
|
603
606
|
|
|
604
|
-
print(training_instructions)
|
|
605
607
|
|
|
606
608
|
model_folder = os.sep.join([self.software_models_dir,model_name, ''])
|
|
607
609
|
print(model_folder)
|
|
608
610
|
if not os.path.exists(model_folder):
|
|
609
611
|
os.mkdir(model_folder)
|
|
610
612
|
|
|
611
|
-
training_instructions.update({'target_directory': self.software_models_dir})
|
|
613
|
+
self.training_instructions.update({'target_directory': self.software_models_dir})
|
|
614
|
+
|
|
615
|
+
print(f"Set of instructions: {self.training_instructions}")
|
|
616
|
+
|
|
617
|
+
self.instructions = model_folder+"training_instructions.json"
|
|
612
618
|
|
|
613
|
-
print(f"Set of instructions: {training_instructions}")
|
|
614
619
|
with open(model_folder+"training_instructions.json", 'w') as f:
|
|
615
|
-
json.dump(training_instructions, f, indent=4)
|
|
620
|
+
json.dump(self.training_instructions, f, indent=4)
|
|
616
621
|
|
|
617
|
-
|
|
622
|
+
# process_args = {"instructions": self.instructions, "use_gpu": self.use_gpu}
|
|
623
|
+
# self.job = ProgressWindow(TrainSegModelProcess, parent_window=self, title="Training", position_info=False, process_args=process_args)
|
|
624
|
+
# result = self.job.exec_()
|
|
625
|
+
# if result == QDialog.Accepted:
|
|
626
|
+
# pass
|
|
627
|
+
# elif result == QDialog.Rejected:
|
|
628
|
+
# return None
|
|
629
|
+
|
|
630
|
+
train_segmentation_model(self.instructions, use_gpu=self.parent_window.parent_window.parent_window.use_gpu)
|
|
618
631
|
|
|
619
632
|
self.parent_window.init_seg_model_list()
|
|
620
633
|
idx = self.parent_window.seg_model_list.findText(model_name)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from PyQt5.QtWidgets import QMainWindow, QApplication, QMessageBox, QScrollArea, QComboBox, QFrame, QCheckBox, QFileDialog, QGridLayout, QLineEdit, QVBoxLayout, QWidget, QLabel, QHBoxLayout, QPushButton
|
|
1
|
+
from PyQt5.QtWidgets import QMainWindow, QApplication, QDialog, QMessageBox, QScrollArea, QComboBox, QFrame, QCheckBox, QFileDialog, QGridLayout, QLineEdit, QVBoxLayout, QWidget, QLabel, QHBoxLayout, QPushButton
|
|
2
2
|
from PyQt5.QtCore import Qt, QSize
|
|
3
3
|
from PyQt5.QtGui import QDoubleValidator, QIntValidator, QIcon
|
|
4
4
|
from celldetective.gui.gui_utils import center_window
|
|
@@ -16,6 +16,8 @@ from glob import glob
|
|
|
16
16
|
from datetime import datetime
|
|
17
17
|
from celldetective.gui import Styles
|
|
18
18
|
from pandas.api.types import is_numeric_dtype
|
|
19
|
+
from celldetective.gui.processes.train_signal_model import TrainSignalModelProcess
|
|
20
|
+
from celldetective.gui.workers import ProgressWindow
|
|
19
21
|
|
|
20
22
|
class ConfigSignalModelTraining(QMainWindow, Styles):
|
|
21
23
|
|
|
@@ -584,6 +586,14 @@ class ConfigSignalModelTraining(QMainWindow, Styles):
|
|
|
584
586
|
with open(model_folder+"training_instructions.json", 'w') as f:
|
|
585
587
|
json.dump(training_instructions, f, indent=4)
|
|
586
588
|
|
|
587
|
-
|
|
589
|
+
# self.instructions = model_folder+"training_instructions.json"
|
|
590
|
+
# process_args = {"instructions": self.instructions} # "use_gpu": self.use_gpu
|
|
591
|
+
# self.job = ProgressWindow(TrainSignalModelProcess, parent_window=self, title="Training", position_info=False, process_args=process_args)
|
|
592
|
+
# result = self.job.exec_()
|
|
593
|
+
# if result == QDialog.Accepted:
|
|
594
|
+
# pass
|
|
595
|
+
# elif result == QDialog.Rejected:
|
|
596
|
+
# return None
|
|
588
597
|
|
|
598
|
+
train_signal_model(model_folder+"training_instructions.json")
|
|
589
599
|
self.parent_window.refresh_signal_models()
|
|
@@ -83,6 +83,15 @@ class SignalAnnotator(QMainWindow, Styles):
|
|
|
83
83
|
|
|
84
84
|
self.populate_widget()
|
|
85
85
|
|
|
86
|
+
def resizeEvent(self, event):
|
|
87
|
+
|
|
88
|
+
super().resizeEvent(event)
|
|
89
|
+
|
|
90
|
+
try:
|
|
91
|
+
self.cell_fig.tight_layout()
|
|
92
|
+
except:
|
|
93
|
+
pass
|
|
94
|
+
|
|
86
95
|
def populate_widget(self):
|
|
87
96
|
|
|
88
97
|
"""
|
|
@@ -134,6 +134,14 @@ class SignalAnnotator2(QMainWindow,Styles):
|
|
|
134
134
|
|
|
135
135
|
self.setAttribute(Qt.WA_DeleteOnClose)
|
|
136
136
|
|
|
137
|
+
def resizeEvent(self, event):
|
|
138
|
+
|
|
139
|
+
super().resizeEvent(event)
|
|
140
|
+
try:
|
|
141
|
+
self.cell_fig.tight_layout()
|
|
142
|
+
except:
|
|
143
|
+
pass
|
|
144
|
+
|
|
137
145
|
def populate_widget(self):
|
|
138
146
|
|
|
139
147
|
"""
|
|
@@ -205,14 +213,14 @@ class SignalAnnotator2(QMainWindow,Styles):
|
|
|
205
213
|
|
|
206
214
|
self.cell_events_hbox = QHBoxLayout()
|
|
207
215
|
self.cell_events_hbox.setContentsMargins(0,0,0,0)
|
|
208
|
-
self.cell_events_hbox.addWidget(QLabel('
|
|
216
|
+
self.cell_events_hbox.addWidget(QLabel('Event: '), 25)
|
|
209
217
|
self.reference_event_choice_cb = QComboBox()
|
|
210
218
|
self.cell_events_hbox.addWidget(self.reference_event_choice_cb, 75)
|
|
211
219
|
|
|
212
220
|
#if 'self' not in self.neighborhood_choice_cb.currentText():
|
|
213
221
|
self.neigh_cell_events_hbox = QHBoxLayout()
|
|
214
222
|
self.neigh_cell_events_hbox.setContentsMargins(0,0,0,0)
|
|
215
|
-
self.neigh_lab=QLabel('
|
|
223
|
+
self.neigh_lab=QLabel('Event: ')
|
|
216
224
|
self.neigh_cell_events_hbox.addWidget(self.neigh_lab, 25)
|
|
217
225
|
self.neighbor_event_choice_cb = QComboBox()
|
|
218
226
|
self.neigh_cell_events_hbox.addWidget(self.neighbor_event_choice_cb, 75)
|
|
@@ -233,7 +241,7 @@ class SignalAnnotator2(QMainWindow,Styles):
|
|
|
233
241
|
neighbor_layout.addLayout(self.neigh_cell_events_hbox)
|
|
234
242
|
|
|
235
243
|
self.cell_info_hbox.addLayout(reference_layout, 33)
|
|
236
|
-
self.cell_info_hbox.addWidget(self.pair_info, 33
|
|
244
|
+
self.cell_info_hbox.addWidget(self.pair_info, 33)
|
|
237
245
|
self.cell_info_hbox.addLayout(neighbor_layout, 33)
|
|
238
246
|
|
|
239
247
|
self.left_panel.addLayout(self.cell_info_hbox)
|
|
@@ -2378,41 +2386,41 @@ class SignalAnnotator2(QMainWindow,Styles):
|
|
|
2378
2386
|
|
|
2379
2387
|
df_reference = self.dataframes[self.reference_population]
|
|
2380
2388
|
if self.reference_track_of_interest is not None:
|
|
2381
|
-
reference_cell_selected = f"
|
|
2382
|
-
reference_cell_population = f"
|
|
2389
|
+
reference_cell_selected = f"Ref #{self.reference_track_of_interest}\n"
|
|
2390
|
+
reference_cell_population = f"Pop: {self.reference_population}\n"
|
|
2383
2391
|
#reference_cell_class = f"class: {df_reference[df_reference['TRACK_ID']==self.reference_track_of_interest, self.reference_event_choice_cb.currentText()].values[0]}\n"
|
|
2384
2392
|
#reference_cell_time = f"time of interest: {df_reference[df_reference['TRACK_ID']==self.reference_track_of_interest, ''].values[0]}\n"
|
|
2385
2393
|
self.reference_cell_info.setText(reference_cell_selected+reference_cell_population)
|
|
2386
2394
|
else:
|
|
2387
|
-
reference_cell_selected = f"
|
|
2388
|
-
reference_cell_population = f"
|
|
2395
|
+
reference_cell_selected = f"Ref: None\n"
|
|
2396
|
+
reference_cell_population = f"Pop: {self.reference_population}\n"
|
|
2389
2397
|
self.reference_cell_info.setText(reference_cell_selected+reference_cell_population)
|
|
2390
2398
|
|
|
2391
2399
|
def give_neighbor_cell_information(self):
|
|
2392
2400
|
|
|
2393
2401
|
if self.neighbor_track_of_interest is not None:
|
|
2394
|
-
neighbor_cell_selected = f"
|
|
2395
|
-
neighbor_cell_population = f"
|
|
2402
|
+
neighbor_cell_selected = f"Neigh #{self.neighbor_track_of_interest}\n"
|
|
2403
|
+
neighbor_cell_population = f"Pop: {self.neighbor_population}\n"
|
|
2396
2404
|
#neighbor_cell_time = f"time of interest: {self.df_relative.loc[(self.df_relative['REFERENCE_ID']==self.reference_track_of_interest)&(self.df_relative['NEIGHBOR_ID']==self.neighbor_track_of_interest), self.pair_time_name].to_numpy()[0]}\n"
|
|
2397
2405
|
#neighbor_cell_class = f"class: {self.df_relative.loc[(self.df_relative['REFERENCE_ID']==self.reference_track_of_interest)&(self.df_relative['NEIGHBOR_ID']==self.neighbor_track_of_interest), self.pair_class_name].to_numpy()[0]}\n"
|
|
2398
2406
|
self.neighbor_cell_info.setText(neighbor_cell_selected+neighbor_cell_population) #neighbor_cell_class+neighbor_cell_time
|
|
2399
2407
|
else:
|
|
2400
|
-
neighbor_cell_selected = f"
|
|
2401
|
-
neighbor_cell_population = f"
|
|
2408
|
+
neighbor_cell_selected = f"Neigh: None\n"
|
|
2409
|
+
neighbor_cell_population = f"Pop: {self.neighbor_population}\n"
|
|
2402
2410
|
self.neighbor_cell_info.setText(neighbor_cell_selected+neighbor_cell_population)
|
|
2403
2411
|
|
|
2404
2412
|
def give_pair_information(self):
|
|
2405
2413
|
|
|
2406
2414
|
if self.neighbor_track_of_interest is not None and self.reference_track_of_interest is not None:
|
|
2407
|
-
pair_selected = f"
|
|
2408
|
-
pair_populations = f"populations: ({self.reference_population}, {self.neighbor_population})\n"
|
|
2415
|
+
pair_selected = f"Pair: ({self.reference_track_of_interest},{self.neighbor_track_of_interest})\n"
|
|
2416
|
+
pair_populations = "" #f"populations: ({self.reference_population}, {self.neighbor_population})\n"
|
|
2409
2417
|
current_class = self.relative_class_choice_cb.currentText()
|
|
2410
|
-
pair_class = f"
|
|
2411
|
-
pair_time = f"
|
|
2418
|
+
pair_class = f"Event class: {self.df_relative.loc[(self.df_relative['REFERENCE_ID']==self.reference_track_of_interest)&(self.df_relative['NEIGHBOR_ID']==self.neighbor_track_of_interest)&(self.df_relative['reference_population']==self.reference_population)&(self.df_relative['neighbor_population']==self.neighbor_population)&(~self.df_relative['status_'+self.current_neighborhood].isnull()), current_class].values[0]}\n"
|
|
2419
|
+
pair_time = f"Time: {self.df_relative.loc[(self.df_relative['REFERENCE_ID']==self.reference_track_of_interest)&(self.df_relative['NEIGHBOR_ID']==self.neighbor_track_of_interest)&(self.df_relative['reference_population']==self.reference_population)&(self.df_relative['neighbor_population']==self.neighbor_population)&(~self.df_relative['status_'+self.current_neighborhood].isnull()), self.pair_time_name].values[0]}\n"
|
|
2412
2420
|
self.pair_info.setText(pair_selected+pair_populations+pair_class+pair_time)
|
|
2413
2421
|
else:
|
|
2414
|
-
pair_selected = f"
|
|
2415
|
-
pair_populations = f"populations: ({self.reference_population}, {self.neighbor_population})\n"
|
|
2422
|
+
pair_selected = f"Pair: None\n"
|
|
2423
|
+
pair_populations = "" #f"populations: ({self.reference_population}, {self.neighbor_population})\n"
|
|
2416
2424
|
self.pair_info.setText(pair_selected+pair_populations)
|
|
2417
2425
|
|
|
2418
2426
|
|
celldetective/gui/styles.py
CHANGED
celldetective/gui/tableUI.py
CHANGED
|
@@ -1337,7 +1337,7 @@ class TableUI(QMainWindow, Styles):
|
|
|
1337
1337
|
file_name += ".csv"
|
|
1338
1338
|
invalid_cols = [c for c in list(self.data.columns) if c.startswith('Unnamed')]
|
|
1339
1339
|
if len(invalid_cols)>0:
|
|
1340
|
-
self.data = self.data.drop(invalid_cols, axis=1)
|
|
1340
|
+
self.data = self.data.drop(invalid_cols, axis=1)
|
|
1341
1341
|
self.data.to_csv(file_name, index=False)
|
|
1342
1342
|
|
|
1343
1343
|
def test_bool(self, array):
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
from multiprocessing import Queue
|
|
2
|
+
from PyQt5.QtWidgets import QDialog, QPushButton, QVBoxLayout, QHBoxLayout, QWidget, QLabel, QProgressBar
|
|
3
|
+
from PyQt5.QtCore import QRunnable, QObject, pyqtSignal, QThreadPool, QSize, Qt
|
|
4
|
+
from celldetective.gui.gui_utils import center_window
|
|
5
|
+
import time
|
|
6
|
+
import math
|
|
7
|
+
|
|
8
|
+
class ProgressWindow(QDialog):
|
|
9
|
+
|
|
10
|
+
def __init__(self, process=None, parent_window=None, title="", position_info=True, process_args=None):
|
|
11
|
+
QDialog.__init__(self)
|
|
12
|
+
|
|
13
|
+
self.setWindowTitle(f'{title} Progress')
|
|
14
|
+
self.__process = process
|
|
15
|
+
self.parent_window = parent_window
|
|
16
|
+
self.position_info = position_info
|
|
17
|
+
if self.position_info:
|
|
18
|
+
self.pos_name = self.parent_window.pos_name
|
|
19
|
+
|
|
20
|
+
#self.__btn_run = QPushButton("Start")
|
|
21
|
+
self.__btn_stp = QPushButton("Cancel")
|
|
22
|
+
if self.position_info:
|
|
23
|
+
self.position_label = QLabel(f'Processing position {self.pos_name}...')
|
|
24
|
+
self.__label = QLabel("Idle")
|
|
25
|
+
self.time_left_lbl = QLabel('')
|
|
26
|
+
|
|
27
|
+
self.progress_bar = QProgressBar()
|
|
28
|
+
self.progress_bar.setValue(0)
|
|
29
|
+
|
|
30
|
+
self.__runner = Runner(process=self.__process, progress_bar=self.progress_bar, process_args=process_args, remaining_time_label=self.time_left_lbl)
|
|
31
|
+
self.pool = QThreadPool.globalInstance()
|
|
32
|
+
#print("Multithreading with maximum %d threads" % self.pool.maxThreadCount())
|
|
33
|
+
|
|
34
|
+
#self.__btn_run.clicked.connect(self.__run_net)
|
|
35
|
+
self.__btn_stp.clicked.connect(self.__stp_net)
|
|
36
|
+
self.__runner.signals.finished.connect(self.__on_finished)
|
|
37
|
+
self.__runner.signals.finished.connect(self.__on_error)
|
|
38
|
+
self.__runner.signals.update.connect(self.progress_bar.setValue)
|
|
39
|
+
self.__runner.signals.update_time.connect(self.time_left_lbl.setText)
|
|
40
|
+
|
|
41
|
+
self.__btn_stp.setDisabled(True)
|
|
42
|
+
|
|
43
|
+
self.layout = QVBoxLayout()
|
|
44
|
+
if self.position_info:
|
|
45
|
+
self.layout.addWidget(self.position_label)
|
|
46
|
+
self.layout.addWidget(self.time_left_lbl)
|
|
47
|
+
self.layout.addWidget(self.progress_bar)
|
|
48
|
+
self.btn_layout = QHBoxLayout()
|
|
49
|
+
self.btn_layout.addWidget(self.__btn_stp)
|
|
50
|
+
self.btn_layout.addWidget(self.__label)
|
|
51
|
+
self.layout.addLayout(self.btn_layout)
|
|
52
|
+
|
|
53
|
+
self.setLayout(self.layout)
|
|
54
|
+
self.setFixedSize(QSize(250, 130))
|
|
55
|
+
self.__run_net()
|
|
56
|
+
self.setModal(True)
|
|
57
|
+
center_window(self)
|
|
58
|
+
|
|
59
|
+
def closeEvent(self, evnt):
|
|
60
|
+
# if self._want_to_close:
|
|
61
|
+
# super(MyDialog, self).closeEvent(evnt)
|
|
62
|
+
# else:
|
|
63
|
+
evnt.ignore()
|
|
64
|
+
self.setWindowState(Qt.WindowMinimized)
|
|
65
|
+
|
|
66
|
+
def __run_net(self):
|
|
67
|
+
#self.__btn_run.setDisabled(True)
|
|
68
|
+
self.__btn_stp.setEnabled(True)
|
|
69
|
+
self.__label.setText("Running...")
|
|
70
|
+
self.pool.start(self.__runner)
|
|
71
|
+
|
|
72
|
+
def __stp_net(self):
|
|
73
|
+
self.__runner.close()
|
|
74
|
+
print('\n Job cancelled... Abort.')
|
|
75
|
+
self.reject()
|
|
76
|
+
|
|
77
|
+
def __on_finished(self):
|
|
78
|
+
self.__btn_stp.setDisabled(True)
|
|
79
|
+
self.__label.setText("\nFinished!")
|
|
80
|
+
self.__runner.close()
|
|
81
|
+
self.accept()
|
|
82
|
+
|
|
83
|
+
def __on_error(self):
|
|
84
|
+
self.__btn_stp.setDisabled(True)
|
|
85
|
+
self.__label.setText("\nError")
|
|
86
|
+
self.__runner.close()
|
|
87
|
+
self.accept()
|
|
88
|
+
|
|
89
|
+
class Runner(QRunnable):
|
|
90
|
+
|
|
91
|
+
def __init__(self, process=None, progress_bar=None, remaining_time_label=None, process_args=None):
|
|
92
|
+
QRunnable.__init__(self)
|
|
93
|
+
|
|
94
|
+
print(f"{process_args=}")
|
|
95
|
+
self.progress_bar = progress_bar
|
|
96
|
+
#self.parent_window = parent_window
|
|
97
|
+
self.remaining_time_label = remaining_time_label
|
|
98
|
+
self.__queue = Queue()
|
|
99
|
+
self.__process = process(self.__queue, process_args=process_args)
|
|
100
|
+
self.signals = RunnerSignal()
|
|
101
|
+
|
|
102
|
+
def run(self):
|
|
103
|
+
self.__process.start()
|
|
104
|
+
while True:
|
|
105
|
+
try:
|
|
106
|
+
data = self.__queue.get()
|
|
107
|
+
if len(data)==2:
|
|
108
|
+
progress, time = data
|
|
109
|
+
time = int(time)
|
|
110
|
+
remaining_minutes = time // 60
|
|
111
|
+
remaining_seconds = int(time % 60)
|
|
112
|
+
time_left = "About "+str(remaining_minutes)+" min and "+str(remaining_seconds)+" s remaining"
|
|
113
|
+
if remaining_minutes == 0:
|
|
114
|
+
time_left = "About "+str(remaining_seconds)+" s remaining"
|
|
115
|
+
self.signals.update_time.emit(time_left)
|
|
116
|
+
if isinstance(progress, (float,int)):
|
|
117
|
+
self.signals.update.emit(math.ceil(progress))
|
|
118
|
+
if data == "finished":
|
|
119
|
+
self.signals.finished.emit()
|
|
120
|
+
break
|
|
121
|
+
elif data == "error":
|
|
122
|
+
self.signals.error.emit()
|
|
123
|
+
except Exception as e:
|
|
124
|
+
print(e)
|
|
125
|
+
pass
|
|
126
|
+
|
|
127
|
+
def close(self):
|
|
128
|
+
self.__process.end_process()
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
class RunnerSignal(QObject):
|
|
132
|
+
|
|
133
|
+
update = pyqtSignal(int)
|
|
134
|
+
update_time = pyqtSignal(str)
|
|
135
|
+
finished = pyqtSignal()
|
|
136
|
+
error = pyqtSignal()
|