celldetective 1.0.2__py3-none-any.whl → 1.1.0__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.
Files changed (56) hide show
  1. celldetective/__main__.py +2 -2
  2. celldetective/events.py +2 -44
  3. celldetective/filters.py +4 -5
  4. celldetective/gui/__init__.py +1 -1
  5. celldetective/gui/analyze_block.py +37 -10
  6. celldetective/gui/btrack_options.py +24 -23
  7. celldetective/gui/classifier_widget.py +62 -19
  8. celldetective/gui/configure_new_exp.py +32 -35
  9. celldetective/gui/control_panel.py +115 -81
  10. celldetective/gui/gui_utils.py +674 -396
  11. celldetective/gui/json_readers.py +7 -6
  12. celldetective/gui/layouts.py +755 -0
  13. celldetective/gui/measurement_options.py +168 -487
  14. celldetective/gui/neighborhood_options.py +322 -270
  15. celldetective/gui/plot_measurements.py +1114 -0
  16. celldetective/gui/plot_signals_ui.py +20 -20
  17. celldetective/gui/process_block.py +449 -169
  18. celldetective/gui/retrain_segmentation_model_options.py +27 -26
  19. celldetective/gui/retrain_signal_model_options.py +25 -24
  20. celldetective/gui/seg_model_loader.py +31 -27
  21. celldetective/gui/signal_annotator.py +2326 -2295
  22. celldetective/gui/signal_annotator_options.py +18 -16
  23. celldetective/gui/styles.py +16 -1
  24. celldetective/gui/survival_ui.py +61 -39
  25. celldetective/gui/tableUI.py +60 -23
  26. celldetective/gui/thresholds_gui.py +68 -66
  27. celldetective/gui/viewers.py +596 -0
  28. celldetective/io.py +234 -23
  29. celldetective/measure.py +37 -32
  30. celldetective/neighborhood.py +495 -27
  31. celldetective/preprocessing.py +683 -0
  32. celldetective/scripts/analyze_signals.py +7 -0
  33. celldetective/scripts/measure_cells.py +12 -0
  34. celldetective/scripts/segment_cells.py +5 -0
  35. celldetective/scripts/track_cells.py +11 -0
  36. celldetective/signals.py +221 -98
  37. celldetective/tracking.py +0 -1
  38. celldetective/utils.py +178 -36
  39. celldetective-1.1.0.dist-info/METADATA +305 -0
  40. celldetective-1.1.0.dist-info/RECORD +80 -0
  41. {celldetective-1.0.2.dist-info → celldetective-1.1.0.dist-info}/top_level.txt +1 -0
  42. tests/__init__.py +0 -0
  43. tests/test_events.py +28 -0
  44. tests/test_filters.py +24 -0
  45. tests/test_io.py +70 -0
  46. tests/test_measure.py +141 -0
  47. tests/test_neighborhood.py +70 -0
  48. tests/test_segmentation.py +93 -0
  49. tests/test_signals.py +135 -0
  50. tests/test_tracking.py +164 -0
  51. tests/test_utils.py +71 -0
  52. celldetective-1.0.2.dist-info/METADATA +0 -192
  53. celldetective-1.0.2.dist-info/RECORD +0 -66
  54. {celldetective-1.0.2.dist-info → celldetective-1.1.0.dist-info}/LICENSE +0 -0
  55. {celldetective-1.0.2.dist-info → celldetective-1.1.0.dist-info}/WHEEL +0 -0
  56. {celldetective-1.0.2.dist-info → celldetective-1.1.0.dist-info}/entry_points.txt +0 -0
@@ -21,102 +21,188 @@ from tifffile import imread
21
21
  from pathlib import Path, PurePath
22
22
  import gc
23
23
  import pandas as pd
24
+ from celldetective.gui.viewers import CellSizeViewer, CellEdgeVisualizer
25
+ from celldetective.gui import Styles
24
26
 
25
- class ConfigNeighborhoods(QMainWindow):
27
+ class ConfigNeighborhoods(QWidget, Styles):
26
28
 
27
29
  """
28
- UI to set measurement instructions.
30
+ Widget to configure neighborhood measurements.
29
31
 
30
32
  """
31
33
 
32
- def __init__(self, parent=None):
34
+ def __init__(self, neighborhood_type='distance_threshold',neighborhood_parameter_name='threshold distance', parent_window=None, *args, **kwargs):
33
35
 
34
- super().__init__()
35
- self.parent = parent
36
- self.setWindowTitle("Configure neighborhoods")
37
- #self.setWindowIcon(QIcon(os.sep.join(['celldetective','icons','mexican-hat.png'])))
36
+ super().__init__(*args, **kwargs)
37
+ self.parent_window = parent_window
38
+ self.attr_parent = self.parent_window.parent_window
39
+ self.setWindowIcon(QIcon(os.sep.join(['celldetective','icons','logo.png'])))
38
40
 
39
- self.exp_dir = self.parent.exp_dir
40
- self.neigh_instructions = self.parent.exp_dir + os.sep.join(["configs","neighborhood_instructions.json"])
41
+ self.neighborhood_type = neighborhood_type
42
+ self.neighborhood_parameter_name = neighborhood_parameter_name
43
+
44
+ self.setWindowTitle('Configure neighborhoods')
45
+ self.neigh_instructions = self.attr_parent.exp_dir + os.sep.join(["configs","neighborhood_instructions.json"])
41
46
  self.clear_previous = False
42
47
  self.not_status_reference = False
43
48
  self.not_status_neighbor = False
44
49
 
45
- exp_config = self.exp_dir +"config.ini"
46
- self.channel_names, self.channels = extract_experiment_channels(exp_config)
47
- self.channel_names = np.array(self.channel_names)
48
- self.channels = np.array(self.channels)
49
-
50
- self.screen_height = self.parent.parent.parent.screen_height
51
- center_window(self)
52
-
50
+ self.screen_height = self.attr_parent.screen_height
53
51
  self.setMinimumWidth(750)
54
52
  self.setMinimumHeight(int(0.5*self.screen_height))
55
53
  self.setMaximumHeight(int(0.95*self.screen_height))
56
54
 
57
- self.populate_widget()
55
+ self.generate_main_layout()
58
56
  self.load_previous_neighborhood_instructions()
57
+ center_window(self)
58
+ self.setAttribute(Qt.WA_DeleteOnClose)
59
59
 
60
- def populate_widget(self):
60
+ def generate_main_layout(self):
61
61
 
62
- """
63
- Create the multibox design.
64
-
65
- """
66
-
67
- # Create button widget and layout
68
- self.scroll_area = QScrollArea(self)
69
- self.button_widget = QWidget()
70
- main_layout = QVBoxLayout()
71
- self.button_widget.setLayout(main_layout)
62
+ main_layout = QVBoxLayout(self)
72
63
  main_layout.setContentsMargins(30,30,30,30)
73
64
 
74
- # second frame for ISOTROPIC MEASUREMENTS
75
- pop_hbox = QHBoxLayout()
65
+ populations_layout = QHBoxLayout()
76
66
 
67
+ # Reference population
77
68
  self.reference_population_frame = QFrame()
78
69
  self.reference_population_frame.setFrameStyle(QFrame.StyledPanel | QFrame.Raised)
79
70
  self.populate_reference_frame()
80
- pop_hbox.addWidget(self.reference_population_frame, 50)
71
+ populations_layout.addWidget(self.reference_population_frame, 50)
81
72
 
73
+ # Neighbor population
82
74
  self.neigh_population_frame = QFrame()
83
75
  self.neigh_population_frame.setFrameStyle(QFrame.StyledPanel | QFrame.Raised)
84
- self.populate_neigh_frame()
85
- pop_hbox.addWidget(self.neigh_population_frame, 50)
86
- main_layout.addLayout(pop_hbox)
76
+ self.populate_neighbor_frame()
77
+ populations_layout.addWidget(self.neigh_population_frame, 50)
78
+ main_layout.addLayout(populations_layout)
87
79
 
88
- self.radii_frame = QFrame()
89
- self.radii_frame.setFrameStyle(QFrame.StyledPanel | QFrame.Raised)
90
- self.populate_radii_frame()
91
- main_layout.addWidget(self.radii_frame)
80
+ # Measurements
81
+
82
+ self.measurement_frame = QFrame()
83
+ self.measurement_frame.setFrameStyle(QFrame.StyledPanel | QFrame.Raised)
84
+ self.populate_measurement_frame()
85
+ # if self.neighborhood_type=='distance_threshold':
86
+ # self.populate_radii_frame()
87
+ # elif self.neighborhood_type=='mask_contact':
88
+ # self.populate_contact_frame()
89
+ main_layout.addWidget(self.measurement_frame)
92
90
 
93
91
  self.clear_previous_btn = QCheckBox('clear previous neighborhoods')
92
+ self.clear_previous_btn.setToolTip('Clear all previous neighborhood measurements.')
94
93
  main_layout.addWidget(self.clear_previous_btn, alignment=Qt.AlignRight)
95
94
 
96
95
  main_layout.addWidget(QLabel(''))
97
96
  self.submit_btn = QPushButton('Set')
98
- self.submit_btn.setStyleSheet(self.parent.parent.parent.button_style_sheet)
97
+ self.submit_btn.setStyleSheet(self.button_style_sheet)
99
98
  self.submit_btn.clicked.connect(self.write_instructions)
100
99
  main_layout.addWidget(self.submit_btn)
101
100
 
102
- #self.populate_left_panel()
103
- #grid.addLayout(self.left_side, 0, 0, 1, 1)
104
- self.button_widget.adjustSize()
101
+ self.adjustSize()
102
+ QApplication.processEvents()
103
+
104
+ def populate_measurement_frame(self):
105
+
106
+ """
107
+ Add widgets and layout in the radii frame.
108
+ """
105
109
 
106
- self.scroll_area.setAlignment(Qt.AlignCenter)
107
- self.scroll_area.setWidget(self.button_widget)
108
- self.scroll_area.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
109
- self.scroll_area.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded)
110
- self.scroll_area.setWidgetResizable(True)
111
- self.setCentralWidget(self.scroll_area)
112
- self.show()
110
+ grid = QVBoxLayout(self.measurement_frame)
113
111
 
114
- QApplication.processEvents()
115
- #self.adjustScrollArea()
112
+ self.dist_lbl = QLabel(f"NEIGHBORHOOD {self.neighborhood_parameter_name.upper()}")
113
+ self.dist_lbl.setStyleSheet(self.block_title)
114
+ grid.addWidget(self.dist_lbl, alignment=Qt.AlignCenter)
116
115
 
116
+ self.ContentsMeasurements = QFrame()
117
+ layout = QVBoxLayout(self.ContentsMeasurements)
118
+ layout.setContentsMargins(0,0,0,0)
117
119
 
118
- def populate_reference_frame(self):
120
+ list_header_layout = QHBoxLayout()
121
+ meas = self.neighborhood_parameter_name.split(' ')[-1]
122
+ lbl = QLabel(f'{meas} [px]:')
123
+ lbl.setToolTip('')
124
+ list_header_layout.addWidget(lbl, 85)
125
+
126
+ self.delete_measurement_btn = QPushButton("")
127
+ self.delete_measurement_btn.setStyleSheet(self.button_select_all)
128
+ self.delete_measurement_btn.setIcon(icon(MDI6.trash_can,color="black"))
129
+ self.delete_measurement_btn.setToolTip("Remove measurement.")
130
+ self.delete_measurement_btn.setIconSize(QSize(20, 20))
131
+ list_header_layout.addWidget(self.delete_measurement_btn, 5)
132
+
133
+ self.add_measurement_btn = QPushButton("")
134
+ self.add_measurement_btn.setStyleSheet(self.button_select_all)
135
+ self.add_measurement_btn.setIcon(icon(MDI6.plus,color="black"))
136
+ self.add_measurement_btn.setToolTip("Add a neighborhood measurement.")
137
+ self.add_measurement_btn.setIconSize(QSize(20, 20))
138
+ list_header_layout.addWidget(self.add_measurement_btn, 5)
139
+
140
+ self.viewer_btn = QPushButton()
141
+ self.viewer_btn.setStyleSheet(self.button_select_all)
142
+ self.viewer_btn.setIcon(icon(MDI6.image_check, color="black"))
143
+ self.viewer_btn.setToolTip("View stack and set measurement.")
144
+ self.viewer_btn.setIconSize(QSize(20, 20))
145
+ if self.neighborhood_type=='distance_threshold':
146
+ self.viewer_btn.clicked.connect(self.view_current_stack_with_circle)
147
+ elif self.neighborhood_type=='mask_contact':
148
+ self.viewer_btn.clicked.connect(self.view_current_stack_with_edge)
149
+ list_header_layout.addWidget(self.viewer_btn, 5)
150
+
151
+ layout.addLayout(list_header_layout)
152
+
153
+ self.measurements_list = ListWidget(self, DistanceChoice, initial_features=["60"], dtype=int)
154
+ self.measurements_list.setToolTip('Neighborhoods to compute.')
155
+ layout.addWidget(self.measurements_list)
156
+
157
+ self.delete_measurement_btn.clicked.connect(self.measurements_list.removeSel)
158
+ self.add_measurement_btn.clicked.connect(self.measurements_list.addItem)
159
+
160
+ grid.addWidget(self.ContentsMeasurements)
161
+
162
+ def view_current_stack_with_circle(self):
163
+
164
+ self.parent_window.parent_window.locate_image()
165
+ if self.parent_window.parent_window.current_stack is not None:
166
+ self.viewer = CellSizeViewer(
167
+ initial_diameter = 100,
168
+ parent_list_widget = self.measurements_list.list_widget,
169
+ set_radius_in_list = True,
170
+ stack_path=self.parent_window.parent_window.current_stack,
171
+ window_title=f'Position {self.parent_window.parent_window.position_list.currentText()}',
172
+ frame_slider = True,
173
+ contrast_slider = True,
174
+ channel_cb = True,
175
+ diameter_slider_range = (0,300),
176
+ channel_names = self.parent_window.parent_window.exp_channels,
177
+ n_channels = self.parent_window.parent_window.nbr_channels,
178
+ PxToUm = 1,
179
+ )
180
+ self.viewer.show()
181
+
182
+ def view_current_stack_with_edge(self):
183
+
184
+ self.attr_parent.locate_image()
185
+ if self.attr_parent.current_stack is not None:
186
+ self.viewer = CellEdgeVisualizer(
187
+ cell_type='effectors',
188
+ edge_range=(1,30),
189
+ invert=True,
190
+ initial_edge=3,
191
+ parent_list_widget = self.measurements_list.list_widget,
192
+ stack_path=self.attr_parent.current_stack,
193
+ window_title=f'Position {self.attr_parent.position_list.currentText()}',
194
+ frame_slider = True,
195
+ contrast_slider = True,
196
+ channel_cb = True,
197
+ channel_names = self.attr_parent.exp_channels,
198
+ n_channels = self.attr_parent.nbr_channels,
199
+ PxToUm = 1,
200
+ )
201
+ self.viewer.show()
119
202
 
203
+
204
+ def populate_reference_frame(self):
205
+
120
206
  """
121
207
  Add widgets and layout in the reference population frame.
122
208
  """
@@ -124,199 +210,152 @@ class ConfigNeighborhoods(QMainWindow):
124
210
  grid = QVBoxLayout(self.reference_population_frame)
125
211
  grid.setSpacing(15)
126
212
  self.ref_lbl = QLabel("REFERENCE")
127
- self.ref_lbl.setStyleSheet("""
128
- font-weight: bold;
129
- padding: 0px;
130
- """)
213
+ self.ref_lbl.setStyleSheet(self.block_title)
214
+ self.ref_lbl.setToolTip('Reference population settings.')
131
215
  grid.addWidget(self.ref_lbl, 30, alignment=Qt.AlignCenter)
132
- self.generate_reference_contents()
133
- grid.addWidget(self.ContentsReference, 70)
134
-
135
- def populate_neigh_frame(self):
136
-
137
- """
138
- Add widgets and layout in the neighbor population frame.
139
- """
140
-
141
- grid = QVBoxLayout(self.neigh_population_frame)
142
- grid.setSpacing(15)
143
216
 
144
- self.neigh_lbl = QLabel("NEIGHBORS")
145
- self.neigh_lbl.setStyleSheet("""
146
- font-weight: bold;
147
- padding: 0px;
148
- """)
149
- grid.addWidget(self.neigh_lbl, 30, alignment=Qt.AlignCenter)
150
- self.generate_neighbors_contents()
151
- grid.addWidget(self.ContentsNeigh, 70)
217
+ self.ContentsReference = QFrame()
218
+ layout = QVBoxLayout(self.ContentsReference)
219
+ layout.setContentsMargins(15,15,15,15)
152
220
 
153
- def populate_radii_frame(self):
221
+ population_layout = QHBoxLayout()
222
+ population_layout.addWidget(QLabel('population: '),30)
223
+ self.reference_population_cb = QComboBox()
224
+ self.reference_population_cb.addItems(['targets','effectors'])
225
+ self.reference_population_cb.setToolTip('Select a reference population.')
226
+ population_layout.addWidget(self.reference_population_cb,70)
227
+ layout.addLayout(population_layout)
154
228
 
155
- """
156
- Add widgets and layout in the radii frame.
157
- """
229
+ status_layout = QHBoxLayout()
158
230
 
159
- grid = QVBoxLayout(self.radii_frame)
231
+ status_layout.addWidget(QLabel('status: '), 30)
160
232
 
161
- self.dist_lbl = QLabel("NEIGHBORHOOD CUT-DISTANCES")
162
- self.dist_lbl.setStyleSheet("""
163
- font-weight: bold;
164
- padding: 0px;
165
- """)
166
- grid.addWidget(self.dist_lbl, alignment=Qt.AlignCenter)
167
- self.generate_radii_contents()
168
- grid.addWidget(self.ContentsIso) #1, 0, 1, 4, alignment=Qt.AlignTop
233
+ status_sublayout = QHBoxLayout()
234
+ self.reference_population_status_cb = QComboBox()
235
+ self.reference_population_status_cb.setToolTip('Status of the reference population.')
236
+ status_sublayout.addWidget(self.reference_population_status_cb,95)
169
237
 
238
+ self.reference_switch_status_btn = QPushButton("")
239
+ self.reference_switch_status_btn.setStyleSheet(self.button_select_all)
240
+ self.reference_switch_status_btn.setIcon(icon(MDI6.invert_colors,color="black"))
241
+ self.reference_switch_status_btn.setIconSize(QSize(20, 20))
242
+ self.reference_switch_status_btn.clicked.connect(self.switch_not_reference)
243
+ self.reference_switch_status_btn.setToolTip('Invert status values.')
170
244
 
171
- def generate_radii_contents(self):
245
+ status_sublayout.addWidget(self.reference_switch_status_btn, 5)
172
246
 
173
- self.ContentsIso = QFrame()
174
- layout = QVBoxLayout(self.ContentsIso)
175
- layout.setContentsMargins(0,0,0,0)
247
+ status_layout.addLayout(status_sublayout, 70)
248
+ layout.addLayout(status_layout)
176
249
 
177
- radii_layout = QHBoxLayout()
178
- self.radii_lbl = QLabel('Cut-distance radii:')
179
- self.radii_lbl.setToolTip('From reference cells, in pixel units. Define radii for neighborhood computations.')
180
- radii_layout.addWidget(self.radii_lbl, 90)
181
-
182
- self.del_radius_btn = QPushButton("")
183
- self.del_radius_btn.setStyleSheet(self.parent.parent.parent.button_select_all)
184
- self.del_radius_btn.setIcon(icon(MDI6.trash_can,color="black"))
185
- self.del_radius_btn.setToolTip("Remove radius")
186
- self.del_radius_btn.setIconSize(QSize(20, 20))
187
- radii_layout.addWidget(self.del_radius_btn, 5)
188
-
189
- self.add_radius_btn = QPushButton("")
190
- self.add_radius_btn.setStyleSheet(self.parent.parent.parent.button_select_all)
191
- self.add_radius_btn.setIcon(icon(MDI6.plus,color="black"))
192
- self.add_radius_btn.setToolTip("Add radius")
193
- self.add_radius_btn.setIconSize(QSize(20, 20))
194
- radii_layout.addWidget(self.add_radius_btn, 5)
195
- layout.addLayout(radii_layout)
250
+ event_layout = QHBoxLayout()
251
+ event_layout.addWidget(QLabel('event time: '),30)
252
+ self.event_time_cb = QComboBox()
253
+ self.event_time_cb.setToolTip('Compute average neighborhood metrics before and after this event time.')
254
+ event_layout.addWidget(self.event_time_cb,70)
255
+ layout.addLayout(event_layout)
196
256
 
197
- self.radii_list = ListWidget(self, DistanceChoice, initial_features=["60"], dtype=int)
198
- layout.addWidget(self.radii_list)
257
+ self.fill_cbs_of_reference_population()
258
+ self.reference_population_cb.currentIndexChanged.connect(self.fill_cbs_of_reference_population)
199
259
 
200
- self.del_radius_btn.clicked.connect(self.radii_list.removeSel)
201
- self.add_radius_btn.clicked.connect(self.radii_list.addItem)
202
-
203
- def generate_reference_contents(self):
260
+ grid.addWidget(self.ContentsReference, 70)
204
261
 
205
- self.ContentsReference = QFrame()
206
- layout = QVBoxLayout(self.ContentsReference)
207
- layout.setContentsMargins(15,15,15,15)
262
+ def populate_neighbor_frame(self):
208
263
 
209
- pop_hbox = QHBoxLayout()
210
- pop_hbox.addWidget(QLabel('population: '),30)
211
- self.ref_pop_cb = QComboBox()
212
- self.ref_pop_cb.addItems(['targets','effectors'])
213
- pop_hbox.addWidget(self.ref_pop_cb,70)
214
- layout.addLayout(pop_hbox)
215
-
216
- status_hbox = QHBoxLayout()
217
- status_hbox.addWidget(QLabel('status: '), 30)
218
- self.ref_pop_status_cb = QComboBox()
219
- #self.ref_pop_status_cb.addItems(['--'])
220
-
221
- status_cb_hbox = QHBoxLayout()
222
- status_cb_hbox.setContentsMargins(0,0,0,0)
223
- status_cb_hbox.addWidget(self.ref_pop_status_cb,90)
224
- # replace with not gate
225
-
226
- self.ref_not_gate_btn = QPushButton("")
227
- self.ref_not_gate_btn.setStyleSheet(self.parent.parent.parent.button_select_all)
228
- self.ref_not_gate_btn.setIcon(icon(MDI6.gate_not,color="black"))
229
- self.ref_not_gate_btn.setToolTip("NOT (flip zeros and ones)")
230
- self.ref_not_gate_btn.setIconSize(QSize(20, 20))
231
- self.ref_not_gate_btn.clicked.connect(self.switch_not_reference)
232
- status_cb_hbox.addWidget(self.ref_not_gate_btn, 5)
233
- status_hbox.addLayout(status_cb_hbox,70)
234
- layout.addLayout(status_hbox)
235
-
236
- event_hbox = QHBoxLayout()
237
- event_hbox.addWidget(QLabel('event time: '),30)
238
- self.event_time_cb = QComboBox()
239
- #self.event_time_cb.addItems(['--'])
240
- event_hbox.addWidget(self.event_time_cb,70)
241
- layout.addLayout(event_hbox)
242
-
243
- self.set_combo_boxes_reference()
244
- self.ref_pop_cb.currentIndexChanged.connect(self.set_combo_boxes_reference)
245
-
246
- def switch_not_reference(self):
247
- self.not_status_reference = not self.not_status_reference
248
- if self.not_status_reference:
249
- self.ref_not_gate_btn.setIcon(icon(MDI6.gate_not,color="#1565c0"))
250
- self.ref_not_gate_btn.setIconSize(QSize(20, 20))
251
- else:
252
- self.ref_not_gate_btn.setIcon(icon(MDI6.gate_not,color="black"))
253
- self.ref_not_gate_btn.setIconSize(QSize(20, 20))
264
+ """
265
+ Add widgets and layout in the neighbor population frame.
266
+ """
254
267
 
255
- def generate_neighbors_contents(self):
268
+ grid = QVBoxLayout(self.neigh_population_frame)
269
+ grid.setSpacing(15)
270
+ self.ref_lbl = QLabel("NEIGHBOR")
271
+ self.ref_lbl.setStyleSheet(self.block_title)
272
+ self.ref_lbl.setToolTip('Neighbor population settings.')
273
+ grid.addWidget(self.ref_lbl, 30, alignment=Qt.AlignCenter)
256
274
 
257
275
  self.ContentsNeigh = QFrame()
258
276
  layout = QVBoxLayout(self.ContentsNeigh)
259
277
  layout.setContentsMargins(15,15,15,15)
260
278
 
261
- pop_hbox = QHBoxLayout()
262
- pop_hbox.addWidget(QLabel('population: '),30)
263
- self.neigh_pop_cb = QComboBox()
264
- self.neigh_pop_cb.addItems(['targets','effectors'])
265
- self.neigh_pop_cb.currentIndexChanged.connect(self.set_combo_boxes_neigh)
266
-
267
- pop_hbox.addWidget(self.neigh_pop_cb,70)
268
- layout.addLayout(pop_hbox)
269
-
270
- status_hbox = QHBoxLayout()
271
- status_hbox.addWidget(QLabel('status: '),30)
272
- self.neigh_pop_status_cb = QComboBox()
273
- self.set_combo_boxes_neigh()
274
-
275
- status_cb_hbox = QHBoxLayout()
276
- status_cb_hbox.setContentsMargins(0,0,0,0)
277
- status_cb_hbox.addWidget(self.neigh_pop_status_cb,90)
278
- self.neigh_not_gate_btn = QPushButton("")
279
- self.neigh_not_gate_btn.setStyleSheet(self.parent.parent.parent.button_select_all)
280
- self.neigh_not_gate_btn.setIcon(icon(MDI6.gate_not,color="black"))
281
- self.neigh_not_gate_btn.setToolTip("NOT (flip zeros and ones)")
282
- self.neigh_not_gate_btn.setIconSize(QSize(20, 20))
283
- self.neigh_not_gate_btn.clicked.connect(self.switch_not_neigh)
284
- status_cb_hbox.addWidget(self.neigh_not_gate_btn, 5)
285
- status_hbox.addLayout(status_cb_hbox, 70)
286
- layout.addLayout(status_hbox)
287
-
288
- self.cum_presence_btn = QCheckBox('cumulated presence')
289
- layout.addWidget(self.cum_presence_btn)
279
+ population_layout = QHBoxLayout()
280
+ population_layout.addWidget(QLabel('population: '),30)
281
+ self.neighbor_population_cb = QComboBox()
282
+ self.neighbor_population_cb.addItems(['targets','effectors'])
283
+ self.neighbor_population_cb.setToolTip('Select a neighbor population.')
284
+ population_layout.addWidget(self.neighbor_population_cb,70)
285
+ layout.addLayout(population_layout)
286
+
287
+ status_layout = QHBoxLayout()
288
+
289
+ status_layout.addWidget(QLabel('status: '), 30)
290
+ status_sublayout = QHBoxLayout()
291
+
292
+ self.neighbor_population_status_cb = QComboBox()
293
+ self.neighbor_population_status_cb.setToolTip('Status of the neighbor population.')
294
+ status_sublayout.addWidget(self.neighbor_population_status_cb,95)
295
+
296
+ self.neighbor_switch_status_btn = QPushButton("")
297
+ self.neighbor_switch_status_btn.setStyleSheet(self.button_select_all)
298
+ self.neighbor_switch_status_btn.setIcon(icon(MDI6.invert_colors,color="black"))
299
+ self.neighbor_switch_status_btn.setToolTip("Invert status values.")
300
+ self.neighbor_switch_status_btn.setIconSize(QSize(20, 20))
301
+ self.neighbor_switch_status_btn.clicked.connect(self.switch_not_neigh)
302
+ status_sublayout.addWidget(self.neighbor_switch_status_btn, 5)
303
+ status_layout.addLayout(status_sublayout, 70)
304
+ layout.addLayout(status_layout)
305
+
306
+ self.cumulated_presence_btn = QCheckBox('cumulated presence')
307
+ self.cumulated_presence_btn.setToolTip("Compute the cumulated presence time of each neighbor around a reference cell.")
308
+ layout.addWidget(self.cumulated_presence_btn)
290
309
 
291
310
  self.symmetrize_btn = QCheckBox('symmetrize')
311
+ self.symmetrize_btn.setToolTip("Write the neighborhood of the neighbor cells with respect to the reference cells.")
292
312
  layout.addWidget(self.symmetrize_btn)
313
+
314
+ self.fill_cbs_of_neighbor_population()
315
+ self.neighbor_population_cb.currentIndexChanged.connect(self.fill_cbs_of_neighbor_population)
316
+
317
+ grid.addWidget(self.ContentsNeigh, 70)
318
+
319
+ def fill_cbs_of_neighbor_population(self):
320
+
321
+ population = self.neighbor_population_cb.currentText()
322
+ class_cols, status_cols, time_cols = self.locate_population_specific_columns(population)
323
+ self.neighbor_population_status_cb.clear()
324
+ self.neighbor_population_status_cb.addItems(['--','class', 'status']+class_cols+status_cols)
325
+
326
+ def fill_cbs_of_reference_population(self):
327
+
328
+ population = self.reference_population_cb.currentText()
329
+ class_cols, status_cols, time_cols = self.locate_population_specific_columns(population)
330
+ self.reference_population_status_cb.clear()
331
+ self.reference_population_status_cb.addItems(['--','class', 'status']+class_cols+status_cols)
332
+ self.event_time_cb.addItems(['--', 't0']+time_cols)
333
+
334
+ def switch_not_reference(self):
335
+
336
+ self.not_status_reference = not self.not_status_reference
337
+ if self.not_status_reference:
338
+ self.reference_switch_status_btn.setIcon(icon(MDI6.invert_colors,color=self.celldetective_blue))
339
+ self.reference_switch_status_btn.setIconSize(QSize(20, 20))
340
+ else:
341
+ self.reference_switch_status_btn.setIcon(icon(MDI6.invert_colors,color="black"))
342
+ self.reference_switch_status_btn.setIconSize(QSize(20, 20))
293
343
 
294
344
  def switch_not_neigh(self):
345
+
295
346
  self.not_status_neighbor = not self.not_status_neighbor
296
347
  if self.not_status_neighbor:
297
- self.neigh_not_gate_btn.setIcon(icon(MDI6.gate_not,color="#1565c0"))
298
- self.neigh_not_gate_btn.setIconSize(QSize(20, 20))
348
+ self.neighbor_switch_status_btn.setIcon(icon(MDI6.invert_colors,color=self.celldetective_blue))
349
+ self.neighbor_switch_status_btn.setIconSize(QSize(20, 20))
299
350
  else:
300
- self.neigh_not_gate_btn.setIcon(icon(MDI6.gate_not,color="black"))
301
- self.neigh_not_gate_btn.setIconSize(QSize(20, 20))
302
-
303
- def set_combo_boxes_neigh(self):
304
- pop = self.neigh_pop_cb.currentText()
305
- class_cols, status_cols, _ = self.locate_population_columns(pop)
306
- self.neigh_pop_status_cb.clear()
307
- self.neigh_pop_status_cb.addItems(['--','class','status']+class_cols+status_cols)
308
-
309
- def set_combo_boxes_reference(self):
310
- pop = self.ref_pop_cb.currentText()
311
- class_cols, status_cols, time_cols = self.locate_population_columns(pop)
312
- self.ref_pop_status_cb.clear()
313
- self.ref_pop_status_cb.addItems(['--','class', 'status']+class_cols+status_cols)
314
- self.event_time_cb.addItems(['--', 't0']+time_cols)
351
+ self.neighbor_switch_status_btn.setIcon(icon(MDI6.invert_colors,color="black"))
352
+ self.neighbor_switch_status_btn.setIconSize(QSize(20, 20))
353
+
315
354
 
316
- def locate_population_columns(self, population):
355
+ def locate_population_specific_columns(self, population):
317
356
 
318
357
  # Look for all classes and times
319
- tables = glob(self.exp_dir+os.sep.join(['W*','*','output','tables',f'trajectories_{population}.csv']))
358
+ tables = glob(self.attr_parent.exp_dir+os.sep.join(['W*','*','output','tables',f'trajectories_{population}.csv']))
320
359
  self.all_columns = []
321
360
  for tab in tables:
322
361
  cols = pd.read_csv(tab, nrows=1).columns.tolist()
@@ -356,10 +395,10 @@ class ConfigNeighborhoods(QMainWindow):
356
395
  print('Writing instructions...')
357
396
 
358
397
  neighborhood_options = {}
359
- pop = [self.ref_pop_cb.currentText(), self.neigh_pop_cb.currentText()]
398
+ pop = [self.reference_population_cb.currentText(), self.neighbor_population_cb.currentText()]
360
399
  neighborhood_options.update({'population': pop})
361
400
 
362
- status_options = [self.ref_pop_status_cb.currentText(), self.neigh_pop_status_cb.currentText()]
401
+ status_options = [self.reference_population_status_cb.currentText(), self.neighbor_population_status_cb.currentText()]
363
402
  for k in range(2):
364
403
  if status_options[k]=='--':
365
404
  status_options[k] = None
@@ -368,7 +407,9 @@ class ConfigNeighborhoods(QMainWindow):
368
407
  else:
369
408
  mode = 'self'
370
409
 
371
- distances = self.radii_list.getItems()
410
+ # TO ADAPT
411
+ distances = self.measurements_list.getItems()
412
+ neighborhood_options.update({'neighborhood_type': self.neighborhood_type})
372
413
  neighborhood_options.update({'distance': distances})
373
414
  neighborhood_options.update({'clear_neigh': self.clear_previous_btn.isChecked()})
374
415
  event_time_col = self.event_time_cb.currentText()
@@ -376,9 +417,8 @@ class ConfigNeighborhoods(QMainWindow):
376
417
  event_time_col = None
377
418
  neighborhood_options.update({'event_time_col': event_time_col})
378
419
 
379
-
380
420
  neighborhood_kwargs = {'mode': mode, 'status': status_options, 'not_status_option': [self.not_status_reference, self.not_status_neighbor],
381
- 'compute_cum_sum': self.cum_presence_btn.isChecked(), 'attention_weight': True, 'symmetrize': self.symmetrize_btn.isChecked(),
421
+ 'compute_cum_sum': self.cumulated_presence_btn.isChecked(), 'attention_weight': True, 'symmetrize': self.symmetrize_btn.isChecked(),
382
422
  'include_dead_weight': True}
383
423
 
384
424
  neighborhood_options.update({'neighborhood_kwargs': neighborhood_kwargs})
@@ -387,9 +427,18 @@ class ConfigNeighborhoods(QMainWindow):
387
427
  file_name = self.neigh_instructions
388
428
  with open(file_name, 'w') as f:
389
429
  json.dump(neighborhood_options, f, indent=4)
430
+
431
+
432
+ self.parent_window.protocols.append(neighborhood_options)
433
+ correction_description = ""
434
+ for index, (key, value) in enumerate(neighborhood_options.items()):
435
+ if index > 0:
436
+ correction_description += ", "
437
+ correction_description += str(key) + " : " + str(value)
438
+ self.parent_window.protocol_list.addItem(correction_description)
439
+
390
440
  print('Done.')
391
441
  self.close()
392
-
393
442
 
394
443
  def load_previous_neighborhood_instructions(self):
395
444
 
@@ -400,53 +449,56 @@ class ConfigNeighborhoods(QMainWindow):
400
449
  print('Reading instructions..')
401
450
  if os.path.exists(self.neigh_instructions):
402
451
  with open(self.neigh_instructions, 'r') as f:
452
+
403
453
  neigh_instructions = json.load(f)
404
- print(neigh_instructions)
405
-
406
- if 'distance' in neigh_instructions:
407
- distances = neigh_instructions['distance']
408
- distances = [str(d) for d in distances]
409
- self.radii_list.list_widget.clear()
410
- self.radii_list.list_widget.addItems(distances)
411
-
412
- if 'population' in neigh_instructions:
413
-
414
- pop = neigh_instructions['population']
415
- idx0 = self.ref_pop_cb.findText(pop[0])
416
- self.ref_pop_cb.setCurrentIndex(idx0)
417
- idx1 = self.neigh_pop_cb.findText(pop[1])
418
- self.neigh_pop_cb.setCurrentIndex(idx1)
419
-
420
- if 'clear_neigh' in neigh_instructions:
421
- clear_neigh = neigh_instructions['clear_neigh']
422
- self.clear_previous_btn.setChecked(clear_neigh)
423
-
424
- if 'event_time_col' in neigh_instructions:
425
- event_time_col = neigh_instructions['event_time_col']
426
- if event_time_col is None:
427
- event_time_col = '--'
428
- idx = self.event_time_cb.findText(event_time_col)
429
- self.event_time_cb.setCurrentIndex(idx)
430
-
431
- if 'neighborhood_kwargs' in neigh_instructions:
432
- neighborhood_kwargs = neigh_instructions['neighborhood_kwargs']
433
- if 'compute_cum_sum' in neighborhood_kwargs:
434
- self.cum_presence_btn.setChecked(neighborhood_kwargs['compute_cum_sum'])
435
- if 'symmetrize' in neighborhood_kwargs:
436
- self.symmetrize_btn.setChecked(neighborhood_kwargs['symmetrize'])
437
- if 'status' in neighborhood_kwargs:
438
- status_options = neighborhood_kwargs['status']
439
- status_options = ['--' if s is None else s for s in status_options]
440
- idx0 = self.ref_pop_status_cb.findText(status_options[0])
441
- self.ref_pop_status_cb.setCurrentIndex(idx0)
442
- idx1 = self.neigh_pop_status_cb.findText(status_options[1])
443
- self.neigh_pop_status_cb.setCurrentIndex(idx1)
444
- if 'not_status_option' in neighborhood_kwargs:
445
- not_status_option = neighborhood_kwargs['not_status_option']
446
- if not_status_option[0]:
447
- self.ref_not_gate_btn.click()
448
- if not_status_option[1]:
449
- self.neigh_not_gate_btn.click()
450
-
451
-
452
-
454
+ print(f"Loading the instructions: {neigh_instructions}...")
455
+
456
+ if 'neighborhood_type' not in neigh_instructions:
457
+ neigh_instructions.update({'neighborhood_type': self.neighborhood_type})
458
+
459
+ if self.neighborhood_type==neigh_instructions['neighborhood_type']:
460
+
461
+ if 'distance' in neigh_instructions:
462
+ distances = neigh_instructions['distance']
463
+ distances = [str(d) for d in distances]
464
+ self.measurements_list.list_widget.clear()
465
+ self.measurements_list.list_widget.addItems(distances)
466
+
467
+ if 'population' in neigh_instructions:
468
+
469
+ pop = neigh_instructions['population']
470
+ idx0 = self.reference_population_cb.findText(pop[0])
471
+ self.reference_population_cb.setCurrentIndex(idx0)
472
+ idx1 = self.neighbor_population_cb.findText(pop[1])
473
+ self.neighbor_population_cb.setCurrentIndex(idx1)
474
+
475
+ if 'clear_neigh' in neigh_instructions:
476
+ clear_neigh = neigh_instructions['clear_neigh']
477
+ self.clear_previous_btn.setChecked(clear_neigh)
478
+
479
+ if 'event_time_col' in neigh_instructions:
480
+ event_time_col = neigh_instructions['event_time_col']
481
+ if event_time_col is None:
482
+ event_time_col = '--'
483
+ idx = self.event_time_cb.findText(event_time_col)
484
+ self.event_time_cb.setCurrentIndex(idx)
485
+
486
+ if 'neighborhood_kwargs' in neigh_instructions:
487
+ neighborhood_kwargs = neigh_instructions['neighborhood_kwargs']
488
+ if 'compute_cum_sum' in neighborhood_kwargs:
489
+ self.cumulated_presence_btn.setChecked(neighborhood_kwargs['compute_cum_sum'])
490
+ if 'symmetrize' in neighborhood_kwargs:
491
+ self.symmetrize_btn.setChecked(neighborhood_kwargs['symmetrize'])
492
+ if 'status' in neighborhood_kwargs:
493
+ status_options = neighborhood_kwargs['status']
494
+ status_options = ['--' if s is None else s for s in status_options]
495
+ idx0 = self.reference_population_status_cb.findText(status_options[0])
496
+ self.reference_population_status_cb.setCurrentIndex(idx0)
497
+ idx1 = self.neighbor_population_status_cb.findText(status_options[1])
498
+ self.neighbor_population_status_cb.setCurrentIndex(idx1)
499
+ if 'not_status_option' in neighborhood_kwargs:
500
+ not_status_option = neighborhood_kwargs['not_status_option']
501
+ if not_status_option[0]:
502
+ self.switch_not_reference.click()
503
+ if not_status_option[1]:
504
+ self.switch_not_neigh.click()