celldetective 1.1.1.post1__tar.gz → 1.1.1.post3__tar.gz

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.
Files changed (90) hide show
  1. {celldetective-1.1.1.post1 → celldetective-1.1.1.post3}/PKG-INFO +1 -1
  2. {celldetective-1.1.1.post1 → celldetective-1.1.1.post3}/celldetective/gui/layouts.py +244 -1
  3. {celldetective-1.1.1.post1 → celldetective-1.1.1.post3}/celldetective/gui/retrain_segmentation_model_options.py +66 -164
  4. {celldetective-1.1.1.post1 → celldetective-1.1.1.post3}/celldetective/gui/retrain_signal_model_options.py +18 -164
  5. {celldetective-1.1.1.post1 → celldetective-1.1.1.post3}/celldetective/gui/tableUI.py +160 -60
  6. {celldetective-1.1.1.post1 → celldetective-1.1.1.post3}/celldetective/gui/viewers.py +1 -1
  7. {celldetective-1.1.1.post1 → celldetective-1.1.1.post3}/celldetective/preprocessing.py +23 -11
  8. {celldetective-1.1.1.post1 → celldetective-1.1.1.post3}/celldetective/scripts/segment_cells.py +1 -0
  9. {celldetective-1.1.1.post1 → celldetective-1.1.1.post3}/celldetective/scripts/train_segmentation_model.py +11 -22
  10. {celldetective-1.1.1.post1 → celldetective-1.1.1.post3}/celldetective/utils.py +3 -2
  11. {celldetective-1.1.1.post1 → celldetective-1.1.1.post3}/celldetective.egg-info/PKG-INFO +1 -1
  12. {celldetective-1.1.1.post1 → celldetective-1.1.1.post3}/setup.py +1 -1
  13. {celldetective-1.1.1.post1 → celldetective-1.1.1.post3}/LICENSE +0 -0
  14. {celldetective-1.1.1.post1 → celldetective-1.1.1.post3}/README.md +0 -0
  15. {celldetective-1.1.1.post1 → celldetective-1.1.1.post3}/celldetective/__init__.py +0 -0
  16. {celldetective-1.1.1.post1 → celldetective-1.1.1.post3}/celldetective/__main__.py +0 -0
  17. {celldetective-1.1.1.post1 → celldetective-1.1.1.post3}/celldetective/datasets/segmentation_annotations/blank +0 -0
  18. {celldetective-1.1.1.post1 → celldetective-1.1.1.post3}/celldetective/datasets/signal_annotations/blank +0 -0
  19. {celldetective-1.1.1.post1 → celldetective-1.1.1.post3}/celldetective/events.py +0 -0
  20. {celldetective-1.1.1.post1 → celldetective-1.1.1.post3}/celldetective/extra_properties.py +0 -0
  21. {celldetective-1.1.1.post1 → celldetective-1.1.1.post3}/celldetective/filters.py +0 -0
  22. {celldetective-1.1.1.post1 → celldetective-1.1.1.post3}/celldetective/gui/__init__.py +0 -0
  23. {celldetective-1.1.1.post1 → celldetective-1.1.1.post3}/celldetective/gui/about.py +0 -0
  24. {celldetective-1.1.1.post1 → celldetective-1.1.1.post3}/celldetective/gui/analyze_block.py +0 -0
  25. {celldetective-1.1.1.post1 → celldetective-1.1.1.post3}/celldetective/gui/btrack_options.py +0 -0
  26. {celldetective-1.1.1.post1 → celldetective-1.1.1.post3}/celldetective/gui/classifier_widget.py +0 -0
  27. {celldetective-1.1.1.post1 → celldetective-1.1.1.post3}/celldetective/gui/configure_new_exp.py +0 -0
  28. {celldetective-1.1.1.post1 → celldetective-1.1.1.post3}/celldetective/gui/control_panel.py +0 -0
  29. {celldetective-1.1.1.post1 → celldetective-1.1.1.post3}/celldetective/gui/gui_utils.py +0 -0
  30. {celldetective-1.1.1.post1 → celldetective-1.1.1.post3}/celldetective/gui/json_readers.py +0 -0
  31. {celldetective-1.1.1.post1 → celldetective-1.1.1.post3}/celldetective/gui/measurement_options.py +0 -0
  32. {celldetective-1.1.1.post1 → celldetective-1.1.1.post3}/celldetective/gui/neighborhood_options.py +0 -0
  33. {celldetective-1.1.1.post1 → celldetective-1.1.1.post3}/celldetective/gui/plot_measurements.py +0 -0
  34. {celldetective-1.1.1.post1 → celldetective-1.1.1.post3}/celldetective/gui/plot_signals_ui.py +0 -0
  35. {celldetective-1.1.1.post1 → celldetective-1.1.1.post3}/celldetective/gui/process_block.py +0 -0
  36. {celldetective-1.1.1.post1 → celldetective-1.1.1.post3}/celldetective/gui/seg_model_loader.py +0 -0
  37. {celldetective-1.1.1.post1 → celldetective-1.1.1.post3}/celldetective/gui/signal_annotator.py +0 -0
  38. {celldetective-1.1.1.post1 → celldetective-1.1.1.post3}/celldetective/gui/signal_annotator_options.py +0 -0
  39. {celldetective-1.1.1.post1 → celldetective-1.1.1.post3}/celldetective/gui/styles.py +0 -0
  40. {celldetective-1.1.1.post1 → celldetective-1.1.1.post3}/celldetective/gui/survival_ui.py +0 -0
  41. {celldetective-1.1.1.post1 → celldetective-1.1.1.post3}/celldetective/gui/thresholds_gui.py +0 -0
  42. {celldetective-1.1.1.post1 → celldetective-1.1.1.post3}/celldetective/icons/logo-large.png +0 -0
  43. {celldetective-1.1.1.post1 → celldetective-1.1.1.post3}/celldetective/icons/logo.png +0 -0
  44. {celldetective-1.1.1.post1 → celldetective-1.1.1.post3}/celldetective/icons/signals_icon.png +0 -0
  45. {celldetective-1.1.1.post1 → celldetective-1.1.1.post3}/celldetective/icons/splash-test.png +0 -0
  46. {celldetective-1.1.1.post1 → celldetective-1.1.1.post3}/celldetective/icons/splash.png +0 -0
  47. {celldetective-1.1.1.post1 → celldetective-1.1.1.post3}/celldetective/icons/splash0.png +0 -0
  48. {celldetective-1.1.1.post1 → celldetective-1.1.1.post3}/celldetective/icons/survival2.png +0 -0
  49. {celldetective-1.1.1.post1 → celldetective-1.1.1.post3}/celldetective/icons/vignette_signals2.png +0 -0
  50. {celldetective-1.1.1.post1 → celldetective-1.1.1.post3}/celldetective/icons/vignette_signals2.svg +0 -0
  51. {celldetective-1.1.1.post1 → celldetective-1.1.1.post3}/celldetective/io.py +0 -0
  52. {celldetective-1.1.1.post1 → celldetective-1.1.1.post3}/celldetective/links/zenodo.json +0 -0
  53. {celldetective-1.1.1.post1 → celldetective-1.1.1.post3}/celldetective/measure.py +0 -0
  54. {celldetective-1.1.1.post1 → celldetective-1.1.1.post3}/celldetective/models/segmentation_effectors/blank +0 -0
  55. {celldetective-1.1.1.post1 → celldetective-1.1.1.post3}/celldetective/models/segmentation_effectors/primNK_cfse/config_input.json +0 -0
  56. {celldetective-1.1.1.post1 → celldetective-1.1.1.post3}/celldetective/models/segmentation_effectors/primNK_cfse/cp-cfse-transfer +0 -0
  57. {celldetective-1.1.1.post1 → celldetective-1.1.1.post3}/celldetective/models/segmentation_effectors/primNK_cfse/training_instructions.json +0 -0
  58. {celldetective-1.1.1.post1 → celldetective-1.1.1.post3}/celldetective/models/segmentation_generic/blank +0 -0
  59. {celldetective-1.1.1.post1 → celldetective-1.1.1.post3}/celldetective/models/segmentation_targets/blank +0 -0
  60. {celldetective-1.1.1.post1 → celldetective-1.1.1.post3}/celldetective/models/signal_detection/blank +0 -0
  61. {celldetective-1.1.1.post1 → celldetective-1.1.1.post3}/celldetective/models/tracking_configs/mcf7.json +0 -0
  62. {celldetective-1.1.1.post1 → celldetective-1.1.1.post3}/celldetective/models/tracking_configs/ricm.json +0 -0
  63. {celldetective-1.1.1.post1 → celldetective-1.1.1.post3}/celldetective/models/tracking_configs/ricm2.json +0 -0
  64. {celldetective-1.1.1.post1 → celldetective-1.1.1.post3}/celldetective/neighborhood.py +0 -0
  65. {celldetective-1.1.1.post1 → celldetective-1.1.1.post3}/celldetective/scripts/analyze_signals.py +0 -0
  66. {celldetective-1.1.1.post1 → celldetective-1.1.1.post3}/celldetective/scripts/measure_cells.py +0 -0
  67. {celldetective-1.1.1.post1 → celldetective-1.1.1.post3}/celldetective/scripts/segment_cells_thresholds.py +0 -0
  68. {celldetective-1.1.1.post1 → celldetective-1.1.1.post3}/celldetective/scripts/track_cells.py +0 -0
  69. {celldetective-1.1.1.post1 → celldetective-1.1.1.post3}/celldetective/scripts/train_signal_model.py +0 -0
  70. {celldetective-1.1.1.post1 → celldetective-1.1.1.post3}/celldetective/segmentation.py +0 -0
  71. {celldetective-1.1.1.post1 → celldetective-1.1.1.post3}/celldetective/signals.py +0 -0
  72. {celldetective-1.1.1.post1 → celldetective-1.1.1.post3}/celldetective/tracking.py +0 -0
  73. {celldetective-1.1.1.post1 → celldetective-1.1.1.post3}/celldetective.egg-info/SOURCES.txt +0 -0
  74. {celldetective-1.1.1.post1 → celldetective-1.1.1.post3}/celldetective.egg-info/dependency_links.txt +0 -0
  75. {celldetective-1.1.1.post1 → celldetective-1.1.1.post3}/celldetective.egg-info/entry_points.txt +0 -0
  76. {celldetective-1.1.1.post1 → celldetective-1.1.1.post3}/celldetective.egg-info/not-zip-safe +0 -0
  77. {celldetective-1.1.1.post1 → celldetective-1.1.1.post3}/celldetective.egg-info/requires.txt +0 -0
  78. {celldetective-1.1.1.post1 → celldetective-1.1.1.post3}/celldetective.egg-info/top_level.txt +0 -0
  79. {celldetective-1.1.1.post1 → celldetective-1.1.1.post3}/setup.cfg +0 -0
  80. {celldetective-1.1.1.post1 → celldetective-1.1.1.post3}/tests/__init__.py +0 -0
  81. {celldetective-1.1.1.post1 → celldetective-1.1.1.post3}/tests/test_events.py +0 -0
  82. {celldetective-1.1.1.post1 → celldetective-1.1.1.post3}/tests/test_filters.py +0 -0
  83. {celldetective-1.1.1.post1 → celldetective-1.1.1.post3}/tests/test_io.py +0 -0
  84. {celldetective-1.1.1.post1 → celldetective-1.1.1.post3}/tests/test_measure.py +0 -0
  85. {celldetective-1.1.1.post1 → celldetective-1.1.1.post3}/tests/test_neighborhood.py +0 -0
  86. {celldetective-1.1.1.post1 → celldetective-1.1.1.post3}/tests/test_preprocessing.py +0 -0
  87. {celldetective-1.1.1.post1 → celldetective-1.1.1.post3}/tests/test_segmentation.py +0 -0
  88. {celldetective-1.1.1.post1 → celldetective-1.1.1.post3}/tests/test_signals.py +0 -0
  89. {celldetective-1.1.1.post1 → celldetective-1.1.1.post3}/tests/test_tracking.py +0 -0
  90. {celldetective-1.1.1.post1 → celldetective-1.1.1.post3}/tests/test_utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: celldetective
3
- Version: 1.1.1.post1
3
+ Version: 1.1.1.post3
4
4
  Summary: description
5
5
  Home-page: http://github.com/remyeltorro/celldetective
6
6
  Author: Rémy Torro
@@ -3,7 +3,7 @@ from celldetective.gui.gui_utils import ThresholdLineEdit
3
3
  from PyQt5.QtCore import Qt, QSize
4
4
  from PyQt5.QtGui import QIntValidator
5
5
 
6
- from superqt import QLabeledRangeSlider, QLabeledSlider, QLabeledDoubleRangeSlider
6
+ from superqt import QLabeledRangeSlider, QLabeledSlider, QLabeledDoubleRangeSlider, QSearchableComboBox
7
7
 
8
8
  from superqt.fonticon import icon
9
9
  from fonticon_mdi6 import MDI6
@@ -12,6 +12,249 @@ from celldetective.gui.viewers import ThresholdedStackVisualizer, CellEdgeVisual
12
12
  from celldetective.gui import Styles
13
13
  from celldetective.gui.gui_utils import QuickSliderLayout
14
14
  from celldetective.preprocessing import correct_background_model, correct_background_model_free, estimate_background_per_condition
15
+ from functools import partial
16
+ from glob import glob
17
+ import os
18
+ import pandas as pd
19
+ import numpy as np
20
+
21
+ class ChannelNormGenerator(QVBoxLayout, Styles):
22
+
23
+ """Generator for list of channels"""
24
+
25
+ def __init__(self, parent_window=None, init_n_channels=4, mode='signals', *args):
26
+ super().__init__(*args)
27
+
28
+ self.parent_window = parent_window
29
+ self.mode = mode
30
+ self.init_n_channels = init_n_channels
31
+
32
+ if hasattr(self.parent_window.parent_window, 'locate_image'):
33
+ self.attr_parent = self.parent_window.parent_window
34
+ elif hasattr(self.parent_window.parent_window.parent_window, 'locate_image'):
35
+ self.attr_parent = self.parent_window.parent_window.parent_window
36
+ else:
37
+ self.attr_parent = self.parent_window.parent_window.parent_window.parent_window
38
+
39
+ self.channel_names = self.attr_parent.exp_channels
40
+ self.setContentsMargins(15,15,15,15)
41
+ self.generate_widgets()
42
+ self.add_to_layout()
43
+
44
+ def generate_widgets(self):
45
+
46
+ self.channel_cbs = [QSearchableComboBox() for i in range(self.init_n_channels)]
47
+ self.normalization_mode_btns = [QPushButton('') for i in range(self.init_n_channels)]
48
+ self.normalization_mode = [True for i in range(self.init_n_channels)]
49
+ self.normalization_clip_btns = [QPushButton('') for i in range(self.init_n_channels)]
50
+ self.clip_option = [False for i in range(self.init_n_channels)]
51
+
52
+ for i in range(self.init_n_channels):
53
+ self.normalization_mode_btns[i].setIcon(icon(MDI6.percent_circle,color="#1565c0"))
54
+ self.normalization_mode_btns[i].setIconSize(QSize(20, 20))
55
+ self.normalization_mode_btns[i].setStyleSheet(self.button_select_all)
56
+ self.normalization_mode_btns[i].setToolTip("Switch to absolute normalization values.")
57
+ self.normalization_mode_btns[i].clicked.connect(partial(self.switch_normalization_mode, i))
58
+
59
+ self.normalization_clip_btns[i].setIcon(icon(MDI6.content_cut,color="black"))
60
+ self.normalization_clip_btns[i].setIconSize(QSize(20, 20))
61
+ self.normalization_clip_btns[i].setStyleSheet(self.button_select_all)
62
+ self.normalization_clip_btns[i].clicked.connect(partial(self.switch_clipping_mode, i))
63
+ self.normalization_clip_btns[i].setToolTip('clip')
64
+
65
+ self.normalization_min_value_lbl = [QLabel('Min %: ') for i in range(self.init_n_channels)]
66
+ self.normalization_min_value_le = [QLineEdit('0.1') for i in range(self.init_n_channels)]
67
+ self.normalization_max_value_lbl = [QLabel('Max %: ') for i in range(self.init_n_channels)]
68
+ self.normalization_max_value_le = [QLineEdit('99.99') for i in range(self.init_n_channels)]
69
+
70
+ if self.mode=='signals':
71
+ tables = glob(self.parent_window.exp_dir+os.sep.join(['W*','*','output','tables',f'trajectories_{self.parent_window.mode}.csv']))
72
+ all_measurements = []
73
+ for tab in tables:
74
+ cols = pd.read_csv(tab, nrows=1).columns.tolist()
75
+ all_measurements.extend(cols)
76
+ all_measurements = np.unique(all_measurements)
77
+
78
+ if self.mode=='signals':
79
+ generic_measurements = ['brightfield_channel', 'live_nuclei_channel', 'dead_nuclei_channel',
80
+ 'effector_fluo_channel', 'adhesion_channel', 'fluo_channel_1', 'fluo_channel_2',
81
+ "area", "area_bbox","area_convex","area_filled","major_axis_length",
82
+ "minor_axis_length",
83
+ "eccentricity",
84
+ "equivalent_diameter_area",
85
+ "euler_number",
86
+ "extent",
87
+ "feret_diameter_max",
88
+ "orientation",
89
+ "perimeter",
90
+ "perimeter_crofton",
91
+ "solidity",
92
+ "angular_second_moment",
93
+ "contrast",
94
+ "correlation",
95
+ "sum_of_square_variance",
96
+ "inverse_difference_moment",
97
+ "sum_average",
98
+ "sum_variance",
99
+ "sum_entropy",
100
+ "entropy",
101
+ "difference_variance",
102
+ "difference_entropy",
103
+ "information_measure_of_correlation_1",
104
+ "information_measure_of_correlation_2",
105
+ "maximal_correlation_coefficient",
106
+ "POSITION_X",
107
+ "POSITION_Y",
108
+ ]
109
+ elif self.mode=='channels':
110
+ generic_measurements = ['brightfield_channel', 'live_nuclei_channel', 'dead_nuclei_channel',
111
+ 'effector_fluo_channel', 'adhesion_channel', 'fluo_channel_1', 'fluo_channel_2', 'None']
112
+
113
+ if self.mode=='channels':
114
+ all_measurements = []
115
+ exp_ch = self.attr_parent.exp_channels
116
+ for c in exp_ch:
117
+ all_measurements.append(c)
118
+
119
+ self.channel_items = np.unique(generic_measurements + list(all_measurements))
120
+ self.channel_items = np.insert(self.channel_items, 0, '--')
121
+
122
+ self.add_col_btn = QPushButton('Add channel')
123
+ self.add_col_btn.clicked.connect(self.add_channel)
124
+ self.add_col_btn.setStyleSheet(self.button_add)
125
+ self.add_col_btn.setIcon(icon(MDI6.plus,color="black"))
126
+
127
+ def add_channel(self):
128
+
129
+ self.channel_cbs.append(QSearchableComboBox())
130
+ self.channel_cbs[-1].addItems(self.channel_items)
131
+ self.channel_cbs[-1].currentIndexChanged.connect(self.check_valid_channels)
132
+
133
+ self.normalization_mode_btns.append(QPushButton(''))
134
+ self.normalization_mode.append(True)
135
+ self.normalization_clip_btns.append(QPushButton(''))
136
+ self.clip_option.append(False)
137
+
138
+ self.normalization_mode_btns[-1].setIcon(icon(MDI6.percent_circle,color="#1565c0"))
139
+ self.normalization_mode_btns[-1].setIconSize(QSize(20, 20))
140
+ self.normalization_mode_btns[-1].setStyleSheet(self.button_select_all)
141
+ self.normalization_mode_btns[-1].setToolTip("Switch to absolute normalization values.")
142
+ self.normalization_mode_btns[-1].clicked.connect(partial(self.switch_normalization_mode, len(self.channel_cbs)-1))
143
+
144
+ self.normalization_clip_btns[-1].setIcon(icon(MDI6.content_cut,color="black"))
145
+ self.normalization_clip_btns[-1].setIconSize(QSize(20, 20))
146
+ self.normalization_clip_btns[-1].setStyleSheet(self.button_select_all)
147
+ self.normalization_clip_btns[-1].clicked.connect(partial(self.switch_clipping_mode, len(self.channel_cbs)-1))
148
+ self.normalization_clip_btns[-1].setToolTip('clip')
149
+
150
+ self.normalization_min_value_lbl.append(QLabel('Min %: '))
151
+ self.normalization_min_value_le.append(QLineEdit('0.1'))
152
+ self.normalization_max_value_lbl.append(QLabel('Max %: '))
153
+ self.normalization_max_value_le.append(QLineEdit('99.99'))
154
+
155
+ ch_layout = QHBoxLayout()
156
+ ch_layout.addWidget(QLabel(f'channel {len(self.channel_cbs)-1}: '), 30)
157
+ ch_layout.addWidget(self.channel_cbs[-1], 70)
158
+ self.channels_vb.addLayout(ch_layout)
159
+
160
+ channel_norm_options_layout = QHBoxLayout()
161
+ channel_norm_options_layout.setContentsMargins(130,0,0,0)
162
+ channel_norm_options_layout.addWidget(self.normalization_min_value_lbl[-1])
163
+ channel_norm_options_layout.addWidget(self.normalization_min_value_le[-1])
164
+ channel_norm_options_layout.addWidget(self.normalization_max_value_lbl[-1])
165
+ channel_norm_options_layout.addWidget(self.normalization_max_value_le[-1])
166
+ channel_norm_options_layout.addWidget(self.normalization_clip_btns[-1])
167
+ channel_norm_options_layout.addWidget(self.normalization_mode_btns[-1])
168
+ self.channels_vb.addLayout(channel_norm_options_layout)
169
+
170
+
171
+ def add_to_layout(self):
172
+
173
+ self.channels_vb = QVBoxLayout()
174
+ self.channel_option_layouts = []
175
+ for i in range(len(self.channel_cbs)):
176
+
177
+ ch_layout = QHBoxLayout()
178
+ ch_layout.addWidget(QLabel(f'channel {i}: '), 30)
179
+ self.channel_cbs[i].addItems(self.channel_items)
180
+ self.channel_cbs[i].currentIndexChanged.connect(self.check_valid_channels)
181
+ ch_layout.addWidget(self.channel_cbs[i], 70)
182
+ self.channels_vb.addLayout(ch_layout)
183
+
184
+ channel_norm_options_layout = QHBoxLayout()
185
+ channel_norm_options_layout.setContentsMargins(130,0,0,0)
186
+ channel_norm_options_layout.addWidget(self.normalization_min_value_lbl[i])
187
+ channel_norm_options_layout.addWidget(self.normalization_min_value_le[i])
188
+ channel_norm_options_layout.addWidget(self.normalization_max_value_lbl[i])
189
+ channel_norm_options_layout.addWidget(self.normalization_max_value_le[i])
190
+ channel_norm_options_layout.addWidget(self.normalization_clip_btns[i])
191
+ channel_norm_options_layout.addWidget(self.normalization_mode_btns[i])
192
+ self.channels_vb.addLayout(channel_norm_options_layout)
193
+
194
+ self.addLayout(self.channels_vb)
195
+
196
+ add_hbox = QHBoxLayout()
197
+ add_hbox.addWidget(QLabel(''), 66)
198
+ add_hbox.addWidget(self.add_col_btn, 33, alignment=Qt.AlignRight)
199
+ self.addLayout(add_hbox)
200
+
201
+ def switch_normalization_mode(self, index):
202
+
203
+ """
204
+ Use absolute or percentile values for the normalization of each individual channel.
205
+
206
+ """
207
+
208
+ currentNormMode = self.normalization_mode[index]
209
+ self.normalization_mode[index] = not currentNormMode
210
+
211
+ if self.normalization_mode[index]:
212
+ self.normalization_mode_btns[index].setIcon(icon(MDI6.percent_circle,color="#1565c0"))
213
+ self.normalization_mode_btns[index].setIconSize(QSize(20, 20))
214
+ self.normalization_mode_btns[index].setStyleSheet(self.button_select_all)
215
+ self.normalization_mode_btns[index].setToolTip("Switch to absolute normalization values.")
216
+ self.normalization_min_value_lbl[index].setText('Min %: ')
217
+ self.normalization_max_value_lbl[index].setText('Max %: ')
218
+ self.normalization_min_value_le[index].setText('0.1')
219
+ self.normalization_max_value_le[index].setText('99.99')
220
+
221
+ else:
222
+ self.normalization_mode_btns[index].setIcon(icon(MDI6.percent_circle_outline,color="black"))
223
+ self.normalization_mode_btns[index].setIconSize(QSize(20, 20))
224
+ self.normalization_mode_btns[index].setStyleSheet(self.button_select_all)
225
+ self.normalization_mode_btns[index].setToolTip("Switch to percentile normalization values.")
226
+ self.normalization_min_value_lbl[index].setText('Min: ')
227
+ self.normalization_min_value_le[index].setText('0')
228
+ self.normalization_max_value_lbl[index].setText('Max: ')
229
+ self.normalization_max_value_le[index].setText('1000')
230
+
231
+ def switch_clipping_mode(self, index):
232
+
233
+ currentClipMode = self.clip_option[index]
234
+ self.clip_option[index] = not currentClipMode
235
+
236
+ if self.clip_option[index]:
237
+ self.normalization_clip_btns[index].setIcon(icon(MDI6.content_cut,color="#1565c0"))
238
+ self.normalization_clip_btns[index].setIconSize(QSize(20, 20))
239
+ self.normalization_clip_btns[index].setStyleSheet(self.button_select_all)
240
+
241
+ else:
242
+ self.normalization_clip_btns[index].setIcon(icon(MDI6.content_cut,color="black"))
243
+ self.normalization_clip_btns[index].setIconSize(QSize(20, 20))
244
+ self.normalization_clip_btns[index].setStyleSheet(self.button_select_all)
245
+
246
+ def check_valid_channels(self):
247
+
248
+ if np.all([cb.currentText()=='--' for cb in self.channel_cbs]):
249
+ self.parent_window.submit_btn.setEnabled(False)
250
+
251
+ if hasattr(self.parent_window, "spatial_calib_le"):
252
+ if self.parent_window.spatial_calib_le.text()!='--':
253
+ self.parent_window.submit_btn.setEnabled(True)
254
+ else:
255
+ self.parent_window.submit_btn.setEnabled(True)
256
+
257
+
15
258
 
16
259
  class BackgroundFitCorrectionLayout(QGridLayout, Styles):
17
260
 
@@ -2,6 +2,8 @@ from PyQt5.QtWidgets import QMainWindow, QApplication,QRadioButton, QMessageBox,
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, FeatureChoice, ListWidget, QHSeperationLine, FigureCanvas, GeometryChoice, OperationChoice
5
+ from celldetective.gui.layouts import ChannelNormGenerator
6
+
5
7
  from superqt import QLabeledDoubleRangeSlider, QLabeledDoubleSlider,QLabeledSlider
6
8
  from superqt.fonticon import icon
7
9
  from fonticon_mdi6 import MDI6
@@ -91,6 +93,8 @@ class ConfigSegmentationModelTraining(QMainWindow, Styles):
91
93
  self.main_layout.addWidget(self.submit_btn)
92
94
  self.submit_btn.setEnabled(False)
93
95
 
96
+ self.spatial_calib_le.textChanged.connect(self.activate_train_btn)
97
+
94
98
  #self.populate_left_panel()
95
99
  #grid.addLayout(self.left_side, 0, 0, 1, 1)
96
100
  self.button_widget.adjustSize()
@@ -308,83 +312,25 @@ class ConfigSegmentationModelTraining(QMainWindow, Styles):
308
312
  # layout.addLayout(recompile_layout)
309
313
 
310
314
  self.max_nbr_channels = 5
311
- self.channel_cbs = [QComboBox() for i in range(self.max_nbr_channels)]
312
- self.normalization_mode_btns = [QPushButton('') for i in range(self.max_nbr_channels)]
313
- self.normalization_mode = [True for i in range(self.max_nbr_channels)]
314
-
315
- self.normalization_clip_btns = [QPushButton('') for i in range(self.max_nbr_channels)]
316
- self.clip_option = [False for i in range(self.max_nbr_channels)]
317
-
318
- for i in range(self.max_nbr_channels):
319
-
320
- self.normalization_mode_btns[i].setIcon(icon(MDI6.percent_circle,color="#1565c0"))
321
- self.normalization_mode_btns[i].setIconSize(QSize(20, 20))
322
- self.normalization_mode_btns[i].setStyleSheet(self.button_select_all)
323
- self.normalization_mode_btns[i].setToolTip("Switch to absolute normalization values.")
324
- self.normalization_mode_btns[i].clicked.connect(partial(self.switch_normalization_mode, i))
325
-
326
- self.normalization_clip_btns[i].setIcon(icon(MDI6.content_cut,color="black"))
327
- self.normalization_clip_btns[i].setIconSize(QSize(20, 20))
328
- self.normalization_clip_btns[i].setStyleSheet(self.button_select_all)
329
- self.normalization_clip_btns[i].clicked.connect(partial(self.switch_clipping_mode, i))
330
- self.normalization_clip_btns[i].setToolTip('clip')
331
-
332
- self.normalization_min_value_lbl = [QLabel('Min %: ') for i in range(self.max_nbr_channels)]
333
- self.normalization_min_value_le = [QLineEdit('0.1') for i in range(self.max_nbr_channels)]
334
-
335
- self.normalization_max_value_lbl = [QLabel('Max %: ') for i in range(self.max_nbr_channels)]
336
- self.normalization_max_value_le = [QLineEdit('99.99') for i in range(self.max_nbr_channels)]
337
-
338
- self.channel_items = ['--', 'brightfield_channel', 'live_nuclei_channel', 'dead_nuclei_channel',
339
- 'effector_fluo_channel', 'adhesion_channel', 'fluo_channel_1', 'fluo_channel_2','None'
340
- ]
341
- exp_ch = self.parent_window.parent_window.exp_channels
342
- for c in exp_ch:
343
- if c not in self.channel_items:
344
- self.channel_items.append(c)
345
-
346
- self.channel_option_layouts = []
347
- for i in range(len(self.channel_cbs)):
348
- ch_layout = QHBoxLayout()
349
- ch_layout.addWidget(QLabel(f'channel {i}: '), 30)
350
- self.channel_cbs[i].addItems(self.channel_items)
351
- self.channel_cbs[i].currentIndexChanged.connect(self.check_valid_channels)
352
- ch_layout.addWidget(self.channel_cbs[i], 70)
353
- layout.addLayout(ch_layout)
354
-
355
- channel_norm_options_layout = QHBoxLayout()
356
- channel_norm_options_layout.setContentsMargins(130,0,0,0)
357
- channel_norm_options_layout.addWidget(self.normalization_min_value_lbl[i])
358
- channel_norm_options_layout.addWidget(self.normalization_min_value_le[i])
359
- channel_norm_options_layout.addWidget(self.normalization_max_value_lbl[i])
360
- channel_norm_options_layout.addWidget(self.normalization_max_value_le[i])
361
- channel_norm_options_layout.addWidget(self.normalization_clip_btns[i])
362
- channel_norm_options_layout.addWidget(self.normalization_mode_btns[i])
363
- layout.addLayout(channel_norm_options_layout)
364
-
365
- # for i in range(self.max_nbr_channels):
366
- # self.channel_cbs[i].currentIndexChanged.connect(partial(self.show_norm_options, i))
315
+ self.ch_norm = ChannelNormGenerator(self, mode='channels')
316
+ layout.addLayout(self.ch_norm)
367
317
 
368
318
  spatial_calib_layout = QHBoxLayout()
369
319
  spatial_calib_layout.addWidget(QLabel('input spatial\ncalibration'), 30)
370
- self.spatial_calib_le = QLineEdit('')
320
+ parent_pxtoum = f"{self.parent_window.parent_window.PxToUm}"
321
+ self.spatial_calib_le = QLineEdit(parent_pxtoum.replace('.',','))
371
322
  self.spatial_calib_le.setPlaceholderText('e.g. 0.1 µm per pixel')
323
+ self.spatial_calib_le.setValidator(self.onlyFloat)
372
324
  spatial_calib_layout.addWidget(self.spatial_calib_le, 70)
373
325
  layout.addLayout(spatial_calib_layout)
374
326
 
375
327
 
376
- # model_length_layout = QHBoxLayout()
377
- # model_length_layout.addWidget(QLabel('Max signal length: '), 30)
378
- # self.model_length_slider = QLabeledSlider()
379
- # self.model_length_slider.setSingleStep(1)
380
- # self.model_length_slider.setTickInterval(1)
381
- # self.model_length_slider.setSingleStep(1)
382
- # self.model_length_slider.setOrientation(1)
383
- # self.model_length_slider.setRange(0,1024)
384
- # self.model_length_slider.setValue(128)
385
- # model_length_layout.addWidget(self.model_length_slider, 70)
386
- # layout.addLayout(model_length_layout)
387
328
 
329
+ def activate_train_btn(self):
330
+ if self.spatial_calib_le.text()=='':
331
+ self.submit_btn.setEnabled(False)
332
+ elif not np.all([cb.currentText()=='--' for cb in self.ch_norm.channel_cbs]):
333
+ self.submit_btn.setEnabled(True)
388
334
 
389
335
  def rescale_slider(self):
390
336
  if self.stardist_model.isChecked():
@@ -400,36 +346,44 @@ class ConfigSegmentationModelTraining(QMainWindow, Styles):
400
346
  except:
401
347
  pass
402
348
 
349
+ self.pretrained_model = None
403
350
  self.pretrained_model = QFileDialog.getExistingDirectory(
404
351
  self, "Open Directory",
405
352
  os.sep.join([self.soft_path, 'celldetective', 'models', f'segmentation_generic','']),
406
353
  QFileDialog.ShowDirsOnly | QFileDialog.DontResolveSymlinks,
407
354
  )
355
+
356
+ if self.pretrained_model=='':
357
+ return None
358
+
359
+ if self.pretrained_model is None:
360
+ return None
408
361
 
409
- if self.pretrained_model is not None:
410
-
362
+ else:
411
363
  self.pretrained_model = self.pretrained_model.replace('\\','/')
412
364
  self.pretrained_model = rf"{self.pretrained_model}"
413
365
 
414
- subfiles = glob('/'.join([self.pretrained_model,"*"]))
366
+ subfiles = glob(os.sep.join([self.pretrained_model,"*"]))
415
367
  subfiles = [s.replace('\\','/') for s in subfiles]
416
368
  subfiles = [rf"{s}" for s in subfiles]
417
369
 
418
- if '/'.join([self.pretrained_model,"config_input.json"]) in subfiles:
370
+ if os.sep.join([self.pretrained_model,"config_input.json"]) in subfiles:
419
371
  self.load_pretrained_config()
420
372
  self.pretrained_lbl.setText(self.pretrained_model.split("/")[-1])
421
373
  self.cancel_pretrained.setVisible(True)
422
374
  #self.recompile_option.setEnabled(True)
423
- self.modelname_le.setText(f"{self.pretrained_model.split('/')[-1]}_{datetime.today().strftime('%Y-%m-%d')}")
375
+ self.modelname_le.setText(f"{self.pretrained_model.split(os.sep)[-1]}_{datetime.today().strftime('%Y-%m-%d')}")
424
376
  else:
425
377
  self.pretrained_model = None
426
378
  self.pretrained_lbl.setText('No folder chosen')
427
379
  #self.recompile_option.setEnabled(False)
428
380
  self.cancel_pretrained.setVisible(False)
381
+ return None
382
+
429
383
  print(self.pretrained_model)
430
384
 
431
- self.seg_folder = self.pretrained_model.split('/')[-2]
432
- self.model_name = self.pretrained_model.split('/')[-1]
385
+ self.seg_folder = self.pretrained_model.split(os.sep)[-2]
386
+ self.model_name = self.pretrained_model.split(os.sep)[-1]
433
387
  if self.model_name.startswith('CP') and self.seg_folder=='segmentation_generic':
434
388
 
435
389
  self.diamWidget = QWidget()
@@ -456,7 +410,7 @@ class ConfigSegmentationModelTraining(QMainWindow, Styles):
456
410
  scale = self.parent_window.parent_window.PxToUm * float(self.diameter_le.text()) / 30.0
457
411
  if self.model_name=="CP_nuclei":
458
412
  scale = self.parent_window.parent_window.PxToUm * float(self.diameter_le.text()) / 17.0
459
- self.spatial_calib_le.setText(str(scale))
413
+ self.spatial_calib_le.setText(str(scale).replace('.',','))
460
414
  self.diamWidget.close()
461
415
 
462
416
 
@@ -485,14 +439,15 @@ class ConfigSegmentationModelTraining(QMainWindow, Styles):
485
439
 
486
440
  self.pretrained_model = None
487
441
  self.pretrained_lbl.setText('No folder chosen')
488
- for i in range(len(self.channel_cbs)):
489
- self.channel_cbs[i].setEnabled(True)
490
- self.normalization_mode_btns[i].setEnabled(True)
491
- self.normalization_max_value_le[i].setEnabled(True)
492
- self.normalization_min_value_le[i].setEnabled(True)
493
- self.normalization_clip_btns[i].setEnabled(True)
494
- self.normalization_min_value_lbl[i].setEnabled(True)
495
- self.normalization_max_value_lbl[i].setEnabled(True)
442
+ for i in range(len(self.ch_norm.channel_cbs)):
443
+ self.ch_norm.channel_cbs[i].setEnabled(True)
444
+ self.ch_norm.normalization_mode_btns[i].setEnabled(True)
445
+ self.ch_norm.normalization_max_value_le[i].setEnabled(True)
446
+ self.ch_norm.normalization_min_value_le[i].setEnabled(True)
447
+ self.ch_norm.normalization_clip_btns[i].setEnabled(True)
448
+ self.ch_norm.normalization_min_value_lbl[i].setEnabled(True)
449
+ self.ch_norm.normalization_max_value_lbl[i].setEnabled(True)
450
+ self.ch_norm.add_col_btn.setEnabled(True)
496
451
 
497
452
  self.cancel_pretrained.setVisible(False)
498
453
  self.modelname_le.setText(f"Untitled_model_{datetime.today().strftime('%Y-%m-%d')}")
@@ -507,7 +462,7 @@ class ConfigSegmentationModelTraining(QMainWindow, Styles):
507
462
 
508
463
  def load_pretrained_config(self):
509
464
 
510
- f = open('/'.join([self.pretrained_model,"config_input.json"]))
465
+ f = open(os.sep.join([self.pretrained_model,"config_input.json"]))
511
466
  data = json.load(f)
512
467
  channels = data["channels"]
513
468
  self.seg_folder = self.pretrained_model.split('/')[-2]
@@ -533,36 +488,37 @@ class ConfigSegmentationModelTraining(QMainWindow, Styles):
533
488
  self.stardist_model.setChecked(False)
534
489
  self.cellpose_model.setChecked(True)
535
490
 
536
- for c,cb in zip(channels, self.channel_cbs):
491
+ for c,cb in zip(channels, self.ch_norm.channel_cbs):
537
492
  index = cb.findText(c)
538
493
  cb.setCurrentIndex(index)
539
494
 
540
495
  for i in range(len(channels)):
541
496
 
542
497
  to_clip = normalization_clip[i]
543
- if self.clip_option[i] != to_clip:
544
- self.normalization_clip_btns[i].click()
498
+ if self.ch_norm.clip_option[i] != to_clip:
499
+ self.ch_norm.normalization_clip_btns[i].click()
545
500
 
546
501
  use_percentile = normalization_percentile[i]
547
- if self.normalization_mode[i] != use_percentile:
548
- self.normalization_mode_btns[i].click()
502
+ if self.ch_norm.normalization_mode[i] != use_percentile:
503
+ self.ch_norm.normalization_mode_btns[i].click()
549
504
 
550
- self.normalization_min_value_le[i].setText(str(normalization_values[i][0]))
551
- self.normalization_max_value_le[i].setText(str(normalization_values[i][1]))
505
+ self.ch_norm.normalization_min_value_le[i].setText(str(normalization_values[i][0]))
506
+ self.ch_norm.normalization_max_value_le[i].setText(str(normalization_values[i][1]))
552
507
 
553
508
 
554
- if len(channels)<len(self.channel_cbs):
555
- for k in range(len(self.channel_cbs)-len(channels)):
556
- self.channel_cbs[len(channels)+k].setCurrentIndex(0)
557
- self.channel_cbs[len(channels)+k].setEnabled(False)
558
- self.normalization_mode_btns[len(channels)+k].setEnabled(False)
559
- self.normalization_max_value_le[len(channels)+k].setEnabled(False)
560
- self.normalization_min_value_le[len(channels)+k].setEnabled(False)
561
- self.normalization_min_value_lbl[len(channels)+k].setEnabled(False)
562
- self.normalization_max_value_lbl[len(channels)+k].setEnabled(False)
563
- self.normalization_clip_btns[len(channels)+k].setEnabled(False)
509
+ if len(channels)<len(self.ch_norm.channel_cbs):
510
+ for k in range(len(self.ch_norm.channel_cbs)-len(channels)):
511
+ self.ch_norm.channel_cbs[len(channels)+k].setCurrentIndex(0)
512
+ self.ch_norm.channel_cbs[len(channels)+k].setEnabled(False)
513
+ self.ch_norm.normalization_mode_btns[len(channels)+k].setEnabled(False)
514
+ self.ch_norm.normalization_max_value_le[len(channels)+k].setEnabled(False)
515
+ self.ch_norm.normalization_min_value_le[len(channels)+k].setEnabled(False)
516
+ self.ch_norm.normalization_min_value_lbl[len(channels)+k].setEnabled(False)
517
+ self.ch_norm.normalization_max_value_lbl[len(channels)+k].setEnabled(False)
518
+ self.ch_norm.normalization_clip_btns[len(channels)+k].setEnabled(False)
519
+ self.ch_norm.add_col_btn.setEnabled(False)
564
520
 
565
- self.spatial_calib_le.setText(str(spatial_calib))
521
+ self.spatial_calib_le.setText(str(spatial_calib).replace('.',','))
566
522
 
567
523
  def adjustScrollArea(self):
568
524
 
@@ -581,23 +537,23 @@ class ConfigSegmentationModelTraining(QMainWindow, Styles):
581
537
  pretrained_model = self.pretrained_model
582
538
 
583
539
  channels = []
584
- for i in range(len(self.channel_cbs)):
585
- channels.append(self.channel_cbs[i].currentText())
540
+ for i in range(len(self.ch_norm.channel_cbs)):
541
+ channels.append(self.ch_norm.channel_cbs[i].currentText())
586
542
 
587
543
  slots_to_keep = np.where(np.array(channels)!='--')[0]
588
544
  while '--' in channels:
589
545
  channels.remove('--')
590
546
 
591
- norm_values = np.array([[float(a.replace(',','.')),float(b.replace(',','.'))] for a,b in zip([l.text() for l in self.normalization_min_value_le],
592
- [l.text() for l in self.normalization_max_value_le])])
547
+ norm_values = np.array([[float(a.replace(',','.')),float(b.replace(',','.'))] for a,b in zip([l.text() for l in self.ch_norm.normalization_min_value_le],
548
+ [l.text() for l in self.ch_norm.normalization_max_value_le])])
593
549
  norm_values = norm_values[slots_to_keep]
594
550
  norm_values = [list(v) for v in norm_values]
595
551
 
596
- clip_values = np.array(self.clip_option)
552
+ clip_values = np.array(self.ch_norm.clip_option)
597
553
  clip_values = list(clip_values[slots_to_keep])
598
554
  clip_values = [bool(c) for c in clip_values]
599
555
 
600
- normalization_mode = np.array(self.normalization_mode)
556
+ normalization_mode = np.array(self.ch_norm.normalization_mode)
601
557
  normalization_mode = list(normalization_mode[slots_to_keep])
602
558
  normalization_mode = [bool(m) for m in normalization_mode]
603
559
 
@@ -650,58 +606,4 @@ class ConfigSegmentationModelTraining(QMainWindow, Styles):
650
606
 
651
607
  train_segmentation_model(model_folder+"training_instructions.json", use_gpu=self.parent_window.parent_window.parent_window.use_gpu)
652
608
 
653
- # self.parent.refresh_signal_models()
654
-
655
-
656
- def check_valid_channels(self):
657
-
658
- if np.all([cb.currentText()=='--' for cb in self.channel_cbs]):
659
- self.submit_btn.setEnabled(False)
660
- else:
661
- self.submit_btn.setEnabled(True)
662
-
663
-
664
- def switch_normalization_mode(self, index):
665
-
666
- """
667
- Use absolute or percentile values for the normalization of each individual channel.
668
-
669
- """
670
-
671
- currentNormMode = self.normalization_mode[index]
672
- self.normalization_mode[index] = not currentNormMode
673
-
674
- if self.normalization_mode[index]:
675
- self.normalization_mode_btns[index].setIcon(icon(MDI6.percent_circle,color="#1565c0"))
676
- self.normalization_mode_btns[index].setIconSize(QSize(20, 20))
677
- self.normalization_mode_btns[index].setStyleSheet(self.button_select_all)
678
- self.normalization_mode_btns[index].setToolTip("Switch to absolute normalization values.")
679
- self.normalization_min_value_lbl[index].setText('Min %: ')
680
- self.normalization_max_value_lbl[index].setText('Max %: ')
681
- self.normalization_min_value_le[index].setText('0.1')
682
- self.normalization_max_value_le[index].setText('99.99')
683
-
684
- else:
685
- self.normalization_mode_btns[index].setIcon(icon(MDI6.percent_circle_outline,color="black"))
686
- self.normalization_mode_btns[index].setIconSize(QSize(20, 20))
687
- self.normalization_mode_btns[index].setStyleSheet(self.button_select_all)
688
- self.normalization_mode_btns[index].setToolTip("Switch to percentile normalization values.")
689
- self.normalization_min_value_lbl[index].setText('Min: ')
690
- self.normalization_min_value_le[index].setText('0')
691
- self.normalization_max_value_lbl[index].setText('Max: ')
692
- self.normalization_max_value_le[index].setText('1000')
693
-
694
- def switch_clipping_mode(self, index):
695
-
696
- currentClipMode = self.clip_option[index]
697
- self.clip_option[index] = not currentClipMode
698
-
699
- if self.clip_option[index]:
700
- self.normalization_clip_btns[index].setIcon(icon(MDI6.content_cut,color="#1565c0"))
701
- self.normalization_clip_btns[index].setIconSize(QSize(20, 20))
702
- self.normalization_clip_btns[index].setStyleSheet(self.button_select_all)
703
-
704
- else:
705
- self.normalization_clip_btns[index].setIcon(icon(MDI6.content_cut,color="black"))
706
- self.normalization_clip_btns[index].setIconSize(QSize(20, 20))
707
- self.normalization_clip_btns[index].setStyleSheet(self.button_select_all)
609
+ # self.parent.refresh_signal_models()