cellects 0.1.2__py3-none-any.whl → 0.2.6__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 (38) hide show
  1. cellects/__main__.py +65 -25
  2. cellects/config/all_vars_dict.py +18 -17
  3. cellects/core/cellects_threads.py +1034 -396
  4. cellects/core/motion_analysis.py +1664 -2010
  5. cellects/core/one_image_analysis.py +1082 -1061
  6. cellects/core/program_organizer.py +1687 -1316
  7. cellects/core/script_based_run.py +80 -76
  8. cellects/gui/advanced_parameters.py +390 -330
  9. cellects/gui/cellects.py +102 -91
  10. cellects/gui/custom_widgets.py +16 -33
  11. cellects/gui/first_window.py +226 -104
  12. cellects/gui/if_several_folders_window.py +117 -68
  13. cellects/gui/image_analysis_window.py +866 -454
  14. cellects/gui/required_output.py +104 -57
  15. cellects/gui/ui_strings.py +840 -0
  16. cellects/gui/video_analysis_window.py +333 -155
  17. cellects/image_analysis/cell_leaving_detection.py +64 -4
  18. cellects/image_analysis/image_segmentation.py +451 -22
  19. cellects/image_analysis/morphological_operations.py +2166 -1635
  20. cellects/image_analysis/network_functions.py +616 -253
  21. cellects/image_analysis/one_image_analysis_threads.py +94 -153
  22. cellects/image_analysis/oscillations_functions.py +131 -0
  23. cellects/image_analysis/progressively_add_distant_shapes.py +2 -3
  24. cellects/image_analysis/shape_descriptors.py +517 -466
  25. cellects/utils/formulas.py +169 -6
  26. cellects/utils/load_display_save.py +362 -109
  27. cellects/utils/utilitarian.py +86 -9
  28. cellects-0.2.6.dist-info/LICENSE +675 -0
  29. cellects-0.2.6.dist-info/METADATA +829 -0
  30. cellects-0.2.6.dist-info/RECORD +44 -0
  31. cellects/core/one_video_per_blob.py +0 -540
  32. cellects/image_analysis/cluster_flux_study.py +0 -102
  33. cellects-0.1.2.dist-info/LICENSE.odt +0 -0
  34. cellects-0.1.2.dist-info/METADATA +0 -132
  35. cellects-0.1.2.dist-info/RECORD +0 -44
  36. {cellects-0.1.2.dist-info → cellects-0.2.6.dist-info}/WHEEL +0 -0
  37. {cellects-0.1.2.dist-info → cellects-0.2.6.dist-info}/entry_points.txt +0 -0
  38. {cellects-0.1.2.dist-info → cellects-0.2.6.dist-info}/top_level.txt +0 -0
@@ -1,12 +1,20 @@
1
1
  #!/usr/bin/env python3
2
- """
3
- This is the third main widget of the GUI of Cellects
4
- It process the video analysis computations by running threads connected to the program_organizer,
5
- especially, most computation are then processed by the MotionAnalysis class
2
+ """Third main widget for Cellects GUI enabling video analysis configuration and execution.
3
+
4
+ This module implements a video tracking interface for analyzing cell movement through configurable parameters like
5
+ arena selection, segmentation methods, and smoothing thresholds. It provides interactive controls including spinboxes,
6
+ comboboxes, buttons for detection/post-processing, and an image display area with full-screen support. Threaded
7
+ operations (VideoReaderThread, OneArenaThread) handle background processing to maintain UI responsiveness.
8
+
9
+ Main Components
10
+ VideoAnalysisWindow : QWidget subclass implementing the video analysis interface with tab navigation, parameter
11
+ controls, and thread coordination
12
+
13
+ Notes
14
+ Uses QThread for background operations to maintain UI responsiveness.
6
15
  """
7
16
  import logging
8
17
  import numpy as np
9
- import cv2
10
18
  from PySide6 import QtWidgets, QtCore
11
19
 
12
20
  from cellects.core.cellects_threads import (
@@ -15,13 +23,54 @@ from cellects.core.cellects_threads import (
15
23
  from cellects.gui.custom_widgets import (
16
24
  MainTabsType, InsertImage, FullScreenImage, PButton, Spinbox,
17
25
  Combobox, Checkbox, FixedText)
26
+ from cellects.gui.ui_strings import FW, VAW
18
27
 
19
28
 
20
29
  class VideoAnalysisWindow(MainTabsType):
21
30
  def __init__(self, parent, night_mode):
31
+ """
32
+ Initialize the VideoAnalysis window with a parent widget and night mode setting.
33
+
34
+ Parameters
35
+ ----------
36
+ parent : QWidget
37
+ The parent widget to which this window will be attached.
38
+ night_mode : bool
39
+ A boolean indicating whether the night mode should be enabled.
40
+
41
+ Examples
42
+ --------
43
+ >>> from PySide6 import QtWidgets
44
+ >>> from cellects.gui.cellects import CellectsMainWidget
45
+ >>> from cellects.gui.video_analysis_window import VideoAnalysisWindow
46
+ >>> import sys
47
+ >>> app = QtWidgets.QApplication([])
48
+ >>> parent = CellectsMainWidget()
49
+ >>> session = VideoAnalysisWindow(parent, False)
50
+ >>> session.true_init()
51
+ >>> parent.insertWidget(0, session)
52
+ >>> parent.show()
53
+ >>> sys.exit(app.exec())
54
+ """
22
55
  super().__init__(parent, night_mode)
23
56
  logging.info("Initialize VideoAnalysisWindow")
24
57
  self.setParent(parent)
58
+ self.true_init()
59
+
60
+ def true_init(self):
61
+ """
62
+ Initialize the video tracking interface and set up its UI components.
63
+
64
+ Extended Description
65
+ --------------------
66
+ This method initializes various tabs, threads, and UI elements for the video tracking interface. It sets up
67
+ event handlers for tab clicks and configures layout components such as labels, buttons, spinboxes, and
68
+ comboboxes.
69
+
70
+ Notes
71
+ -----
72
+ This method assumes that the parent widget has a 'po' attribute with specific settings and variables.
73
+ """
25
74
  self.data_tab.set_not_in_use()
26
75
  self.image_tab.set_not_usable()
27
76
  self.video_tab.set_in_use()
@@ -33,21 +82,10 @@ class VideoAnalysisWindow(MainTabsType):
33
82
  self.thread['ChangeOneRepResult'] = ChangeOneRepResultThread(self.parent())
34
83
  self.thread['RunAll'] = RunAllThread(self.parent())
35
84
  self.previous_arena = 0
36
-
37
- self.layout = QtWidgets.QGridLayout()
38
- self.grid_widget = QtWidgets.QWidget()
39
-
40
- # self.title = FixedText('Video tracking', police=30, night_mode=self.parent().po.all['night_mode'])
41
- # self.title.setAlignment(QtCore.Qt.AlignHCenter)
42
85
  curr_row_main_layout = 0
43
86
  ncol = 1
44
- # self.layout.addWidget(self.title, curr_row_main_layout, 0, 2, ncol)
45
- # curr_row_main_layout += 2
46
- self.layout.addItem(self.vertical_space, curr_row_main_layout, 0, 1, ncol)
87
+ self.Vlayout.addItem(self.vertical_space)#, curr_row_main_layout, 0, 1, ncol)
47
88
  curr_row_main_layout += 1
48
- #
49
- # self.layout.addWidget(self.arena_widget, curr_row_main_layout, 0)
50
- # curr_row_main_layout += 1
51
89
 
52
90
  # Open subtitle
53
91
  self.general_step_widget = QtWidgets.QWidget()
@@ -61,7 +99,7 @@ class VideoAnalysisWindow(MainTabsType):
61
99
  self.general_step_layout.addWidget(self.general_step_button)
62
100
  self.general_step_layout.addItem(self.horizontal_space)
63
101
  self.general_step_widget.setLayout(self.general_step_layout)
64
- self.layout.addWidget(self.general_step_widget, curr_row_main_layout, 0, 1, ncol)
102
+ self.Vlayout.addWidget(self.general_step_widget)#, curr_row_main_layout, 0, 1, ncol)
65
103
  curr_row_main_layout += 1
66
104
 
67
105
  # Open central widget
@@ -72,18 +110,12 @@ class VideoAnalysisWindow(MainTabsType):
72
110
  self.left_options_widget = QtWidgets.QWidget()
73
111
  self.left_options_layout = QtWidgets.QVBoxLayout()
74
112
  self.left_options_widget.setSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Maximum)
75
- # self.left_options_widget.setFixedWidth(420)
76
113
 
77
114
  self.arena_widget = QtWidgets.QWidget()
78
115
  self.arena_layout = QtWidgets.QHBoxLayout()
79
- self.arena_label = FixedText('Arena to analyze:',
80
- tip="Among selected folders, choose a arena from the first folder\nThen, click on *Quick (or *Full) detection* to load and analyse one arena\nFinally, click on *Read* to see the resulting analysis\n\nSupplementary information:\nLoading will be faster if videos are already saved as ind_*.npy\n*Post processing* automatically runs *Detection* and *Detection* automatically runs *Load One arena*\nEach being faster than the previous one",
116
+ self.arena_label = FixedText(VAW["Arena_to_analyze"]["label"] + ':',
117
+ tip=VAW["Arena_to_analyze"]["tips"],
81
118
  night_mode=self.parent().po.all['night_mode'])
82
- # if isinstance(self.parent().po.all['sample_number_per_folder'], int):
83
- # self.parent().po.all['folder_number'] = 1
84
- # if self.parent().po.all['folder_number'] > 1:
85
- # sample_size = self.parent().po.all['sample_number_per_folder']
86
- # else:
87
119
  sample_size = self.parent().po.all['sample_number_per_folder'][0]
88
120
  if self.parent().po.all['arena'] > sample_size:
89
121
  self.parent().po.all['arena'] = 1
@@ -92,12 +124,9 @@ class VideoAnalysisWindow(MainTabsType):
92
124
  night_mode=self.parent().po.all['night_mode'])
93
125
  self.arena.valueChanged.connect(self.arena_changed)
94
126
 
95
- # self.arena_layout.addItem(self.horizontal_space)
96
127
  self.arena_layout.addWidget(self.arena_label)
97
128
  self.arena_layout.addWidget(self.arena)
98
- # self.arena_layout.addItem(self.horizontal_space)
99
129
  self.arena_widget.setLayout(self.arena_layout)
100
- # self.arena_layout.setAlignment(QtCore.Qt.AlignHCenter)
101
130
  self.left_options_layout.addWidget(self.arena_widget)
102
131
 
103
132
 
@@ -110,13 +139,12 @@ class VideoAnalysisWindow(MainTabsType):
110
139
  self.parent().po.vars['repeat_video_smoothing'] = self.parent().po.vars['iterate_smoothing']
111
140
  self.maximal_growth_factor = Spinbox(min=0, max=0.5, val=self.parent().po.vars['maximal_growth_factor'],
112
141
  decimals=3, night_mode=self.parent().po.all['night_mode'])
113
- self.maximal_growth_factor_label = FixedText('Maximal growth factor:',
114
- tip="This factor should be tried and increased (resp. decreases)\nif the analysis underestimates (resp. overestimates) the cell size.\nThe maximal growth factor is a proportion of pixels in the image. \nIt tells Cellects how much the cell(s) can possibly move or grow from one image to the next.\nIn other words, this is the upper limit of the proportion of the image\nthat can change from being the background to being covered by the cell(s).",
142
+ self.maximal_growth_factor_label = FixedText(VAW["Maximal_growth_factor"]["label"] + ':',
143
+ tip=VAW["Maximal_growth_factor"]["tips"],
115
144
  night_mode=self.parent().po.all['night_mode'])
116
145
  self.maximal_growth_factor.valueChanged.connect(self.maximal_growth_factor_changed)
117
146
  self.growth_per_frame_layout.addWidget(self.maximal_growth_factor_label)
118
147
  self.growth_per_frame_layout.addWidget(self.maximal_growth_factor)
119
- # self.growth_per_frame_layout.setAlignment(QtCore.Qt.AlignHCenter)
120
148
  self.growth_per_frame_widget.setLayout(self.growth_per_frame_layout)
121
149
  self.left_options_layout.addWidget(self.growth_per_frame_widget)
122
150
 
@@ -124,45 +152,36 @@ class VideoAnalysisWindow(MainTabsType):
124
152
  self.iterate_layout = QtWidgets.QHBoxLayout()
125
153
  self.repeat_video_smoothing = Spinbox(min=0, max=10, val=self.parent().po.vars['repeat_video_smoothing'],
126
154
  night_mode=self.parent().po.all['night_mode'])
127
- self.repeat_video_smoothing_label = FixedText('Repeat video smoothing:',
128
- tip="Increase (with steps of 1) if video noise is the source of detection failure",
155
+ self.repeat_video_smoothing_label = FixedText(VAW["Temporal_smoothing"]["label"] + ':',
156
+ tip=VAW["Temporal_smoothing"]["tips"],
129
157
  night_mode=self.parent().po.all['night_mode'])
130
158
  self.repeat_video_smoothing.valueChanged.connect(self.repeat_video_smoothing_changed)
131
159
  self.iterate_layout.addWidget(self.repeat_video_smoothing_label)
132
160
  self.iterate_layout.addWidget(self.repeat_video_smoothing)
133
- # self.iterate_layout.setAlignment(QtCore.Qt.AlignHCenter)
134
161
  self.iterate_widget.setLayout(self.iterate_layout)
135
162
  self.left_options_layout.addWidget(self.iterate_widget)
136
163
 
137
164
 
138
- self.select_option_label = FixedText('Segmentation method:',
139
- tip='Select the option allowing the best cell delimitation.',
165
+ self.select_option_label = FixedText(VAW["Segmentation_method"]["label"] + ':',
166
+ tip=VAW["Segmentation_method"]["tips"],
140
167
  night_mode=self.parent().po.all['night_mode'])
141
168
  self.select_option = Combobox([], night_mode=self.parent().po.all['night_mode'])
142
169
  self.select_option_label.setSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Maximum)
143
170
  self.select_option.setSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Maximum)
144
171
  self.select_option.setFixedWidth(175)
145
- # self.select_option_label.setFixedWidth(265)
146
- # self.select_option.setFixedWidth(150)
147
172
  self.select_option.addItem("1. Frame by frame")
148
173
  self.select_option.addItem("2. Dynamical threshold")
149
174
  self.select_option.addItem("3. Dynamical slope")
150
175
  self.select_option.addItem("4. Threshold and Slope")
151
176
  self.select_option.addItem("5. Threshold or Slope")
152
- # for option in range(5):
153
- # self.select_option.addItem(f"Option {option + 1}")
154
177
  self.select_option.setCurrentIndex(self.parent().po.all['video_option'])
155
178
  self.select_option.currentTextChanged.connect(self.option_changed)
156
- # self.select_option_label.setVisible(self.parent().po.vars["color_number"] == 2)
157
- # self.select_option.setVisible(self.parent().po.vars["color_number"] == 2)
158
179
 
159
180
  # Open the choose best option row layout
160
181
  self.options_row_widget = QtWidgets.QWidget()
161
182
  self.options_row_layout = QtWidgets.QHBoxLayout()
162
- # self.options_row_layout.addItem(self.horizontal_space)
163
183
  self.options_row_layout.addWidget(self.select_option_label)
164
184
  self.options_row_layout.addWidget(self.select_option)
165
- # self.options_row_layout.addItem(self.horizontal_space)
166
185
  self.options_row_layout.setAlignment(QtCore.Qt.AlignHCenter)
167
186
  self.options_row_layout.setAlignment(QtCore.Qt.AlignVCenter)
168
187
  self.options_row_widget.setLayout(self.options_row_layout)
@@ -184,13 +203,19 @@ class VideoAnalysisWindow(MainTabsType):
184
203
  self.right_options_widget = QtWidgets.QWidget()
185
204
  self.right_options_layout = QtWidgets.QVBoxLayout()
186
205
  self.right_options_widget.setSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Maximum)
187
- # self.right_options_widget.setFixedWidth(420)
188
206
 
189
207
  self.compute_all_options_label = FixedText('Compute all options',
190
- tip='Uncheck to do a Post processing on only one option and earn computation time\nSelecting one of the remaining options will display the result from a Detection',
208
+ tip=VAW["Segmentation_method"]["tips"],
191
209
  night_mode=self.parent().po.all['night_mode'])
192
210
  self.compute_all_options_cb = Checkbox(self.parent().po.all['compute_all_options'])
193
- self.compute_all_options_cb.setStyleSheet("margin-left:0%; margin-right:0%;")
211
+ self.compute_all_options_cb.setStyleSheet("QCheckBox::indicator {width: 12px;height: 12px;background-color: transparent;"
212
+ "border-radius: 5px;border-style: solid;border-width: 1px;"
213
+ "border-color: rgb(100,100,100);}"
214
+ "QCheckBox::indicator:checked {background-color: rgb(70,130,180);}"
215
+ "QCheckBox:checked, QCheckBox::indicator:checked {border-color: black black white white;}"
216
+ "QCheckBox:checked {background-color: transparent;}"
217
+ "QCheckBox:margin-left {0%}"
218
+ "QCheckBox:margin-right {0%}")
194
219
  self.compute_all_options_cb.stateChanged.connect(self.compute_all_options_check)
195
220
  self.all_options_row_widget = QtWidgets.QWidget()
196
221
  self.all_options_row_layout = QtWidgets.QHBoxLayout()
@@ -201,11 +226,13 @@ class VideoAnalysisWindow(MainTabsType):
201
226
  self.all_options_row_widget.setLayout(self.all_options_row_layout)
202
227
  self.right_options_layout.addWidget(self.all_options_row_widget)
203
228
 
204
- self.load_one_arena = PButton('Load One arena', night_mode=self.parent().po.all['night_mode'])
229
+ self.load_one_arena = PButton(VAW["Load_one_arena"]["label"], tip=VAW["Load_one_arena"]["tips"],
230
+ night_mode=self.parent().po.all['night_mode'])
205
231
  self.load_one_arena.clicked.connect(self.load_one_arena_is_clicked)
206
- self.detection = PButton('Detection', night_mode=self.parent().po.all['night_mode'])
232
+ self.detection = PButton(VAW["Detection"]["label"], tip=VAW["Detection"]["tips"],
233
+ night_mode=self.parent().po.all['night_mode'])
207
234
  self.detection.clicked.connect(self.detection_is_clicked)
208
- self.read = PButton('Read', night_mode=self.parent().po.all['night_mode'])
235
+ self.read = PButton(VAW["Read"]["label"], tip=VAW["Read"]["tips"], night_mode=self.parent().po.all['night_mode'])
209
236
  self.read.clicked.connect(self.read_is_clicked)
210
237
  self.read.setVisible(False)
211
238
  self.right_options_layout.addWidget(self.load_one_arena, alignment=QtCore.Qt.AlignCenter)
@@ -219,10 +246,7 @@ class VideoAnalysisWindow(MainTabsType):
219
246
  self.video_display_layout.addItem(self.horizontal_space)
220
247
  # Close central widget
221
248
  self.video_display_widget.setLayout(self.video_display_layout)
222
- # self.video_display_widget.setSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Maximum)
223
- # self.video_display_widget.setAlignment(QtCore.Qt.AlignHCenter)
224
- # self.video_display_widget.setFixedHeight(500)
225
- self.layout.addWidget(self.video_display_widget, curr_row_main_layout, 0)
249
+ self.Vlayout.addWidget(self.video_display_widget)#, curr_row_main_layout, 0)
226
250
  curr_row_main_layout += 1
227
251
 
228
252
  # Open Second step row
@@ -234,15 +258,21 @@ class VideoAnalysisWindow(MainTabsType):
234
258
  self.fading_widget = QtWidgets.QWidget()
235
259
  self.fading_layout = QtWidgets.QHBoxLayout()
236
260
  self.do_fading = Checkbox(self.parent().po.vars['do_fading'])
237
- self.do_fading.setStyleSheet("margin-left:0%; margin-right:0%;")
261
+ self.do_fading.setStyleSheet("QCheckBox::indicator {width: 12px;height: 12px;background-color: transparent;"
262
+ "border-radius: 5px;border-style: solid;border-width: 1px;"
263
+ "border-color: rgb(100,100,100);}"
264
+ "QCheckBox::indicator:checked {background-color: rgb(70,130,180);}"
265
+ "QCheckBox:checked, QCheckBox::indicator:checked {border-color: black black white white;}"
266
+ "QCheckBox:checked {background-color: transparent;}"
267
+ "QCheckBox:margin-left {0%}"
268
+ "QCheckBox:margin-right {0%}")
238
269
  self.do_fading.stateChanged.connect(self.do_fading_check)
239
270
  self.fading = Spinbox(min=- 1, max=1, val=self.parent().po.vars['fading'], decimals=2,
240
271
  night_mode=self.parent().po.all['night_mode'])
241
- self.fading_label = FixedText('Fading detection',
242
- tip="Set a value between -1 and 1\nnear - 1: it will never detect when the cell leaves an area\nnear 1: it may stop detecting cell (because cell will be considered left from any area)",
272
+ self.fading_label = FixedText(VAW["Fading_detection"]["label"],
273
+ tip=VAW["Fading_detection"]["tips"],
243
274
  night_mode=self.parent().po.all['night_mode'])
244
275
  self.fading.valueChanged.connect(self.fading_changed)
245
- # self.fading.setVisible(self.parent().po.vars['do_fading'])
246
276
  self.fading_layout.addWidget(self.do_fading)
247
277
  self.fading_layout.addWidget(self.fading_label)
248
278
  self.fading_layout.addWidget(self.fading)
@@ -250,23 +280,23 @@ class VideoAnalysisWindow(MainTabsType):
250
280
  self.fading_widget.setLayout(self.fading_layout)
251
281
  self.second_step_layout.addWidget(self.fading_widget)
252
282
 
253
- self.post_processing = PButton('Post processing', night_mode=self.parent().po.all['night_mode'])
283
+ self.post_processing = PButton(VAW["Post_processing"]["label"], tip=VAW["Post_processing"]["tips"],
284
+ night_mode=self.parent().po.all['night_mode'])
254
285
  self.post_processing.clicked.connect(self.post_processing_is_clicked)
255
286
  self.second_step_layout.addWidget(self.post_processing)
256
- # self.second_step_layout.addWidget(self.post_processing, alignment=QtCore.Qt.AlignCenter)
257
287
 
258
- self.save_one_result = PButton('Save One Result', night_mode=self.parent().po.all['night_mode'])
288
+ self.save_one_result = PButton(VAW["Save_one_result"]["label"], tip=VAW["Save_one_result"]["tips"],
289
+ night_mode=self.parent().po.all['night_mode'])
259
290
  self.save_one_result.clicked.connect(self.save_one_result_is_clicked)
260
291
  self.second_step_layout.addWidget(self.save_one_result)
261
- # self.second_step_layout.addWidget(self.save_one_result, alignment=QtCore.Qt.AlignCenter)
262
292
 
263
293
  # Close Second step row
264
294
  self.second_step_layout.setAlignment(QtCore.Qt.AlignHCenter)
265
295
  self.second_step_layout.addItem(self.horizontal_space)
266
296
  self.second_step_widget.setLayout(self.second_step_layout)
267
- self.layout.addItem(self.vertical_space, curr_row_main_layout, 0, 1, ncol)
297
+ self.Vlayout.addItem(self.vertical_space)#, curr_row_main_layout, 0, 1, ncol)
268
298
  curr_row_main_layout += 1
269
- self.layout.addWidget(self.second_step_widget, curr_row_main_layout, 0)
299
+ self.Vlayout.addWidget(self.second_step_widget)#, curr_row_main_layout, 0)
270
300
  curr_row_main_layout += 1
271
301
 
272
302
  # Open last options row widget
@@ -274,42 +304,27 @@ class VideoAnalysisWindow(MainTabsType):
274
304
  self.last_options_layout = QtWidgets.QHBoxLayout()
275
305
  self.last_options_layout.addItem(self.horizontal_space)
276
306
 
277
- # # advanced mode widget
278
- # self.advanced_mode_widget = QtWidgets.QWidget()
279
- # self.advanced_mode_layout = QtWidgets.QHBoxLayout()
280
- # advanced_mode = self.parent().po.all['expert_mode']
281
- # self.advanced_mode_cb = Checkbox(self.parent().po.all['expert_mode'])
282
- # self.advanced_mode_cb.setStyleSheet("margin-left:0%; margin-right:0%;")
283
- # self.advanced_mode_cb.stateChanged.connect(self.advanced_mode_check)
284
- # self.advanced_mode_label = FixedText('Go to step 2 directly', align='l',
285
- # tip="Allow the user to try Post processing before having tuned the parameters related to Detection.",
286
- # night_mode=self.parent().po.all['night_mode'])
287
- # # self.advanced_mode_label.setAlignment(QtCore.Qt.AlignTop)
288
- # self.advanced_mode_layout.addWidget(self.advanced_mode_cb)
289
- # self.advanced_mode_layout.addWidget(self.advanced_mode_label)
290
- # self.advanced_mode_layout.addItem(self.horizontal_space)
291
- # self.advanced_mode_layout.setAlignment(QtCore.Qt.AlignHCenter)
292
- # self.advanced_mode_widget.setLayout(self.advanced_mode_layout)
293
- # self.last_options_layout.addWidget(self.advanced_mode_widget)
294
-
295
- self.advanced_parameters = PButton('Advanced Parameters', night_mode=self.parent().po.all['night_mode'])
307
+ self.advanced_parameters = PButton(FW["Advanced_parameters"]["label"], tip=FW["Advanced_parameters"]["tips"],
308
+ night_mode=self.parent().po.all['night_mode'])
296
309
  self.advanced_parameters.clicked.connect(self.advanced_parameters_is_clicked)
297
310
  self.last_options_layout.addWidget(self.advanced_parameters)
298
311
 
299
312
  # Required Outputs widget
300
- self.required_outputs = PButton('Required Outputs', night_mode=self.parent().po.all['night_mode'])
313
+ self.required_outputs = PButton(FW["Required_outputs"]["label"], tip=FW["Required_outputs"]["tips"],
314
+ night_mode=self.parent().po.all['night_mode'])
301
315
  self.required_outputs.clicked.connect(self.required_outputs_is_clicked)
302
316
  self.last_options_layout.addWidget(self.required_outputs)
303
317
 
304
318
  # Save all choices widget
305
- self.save_all_vars = PButton('Save all choices', night_mode=self.parent().po.all['night_mode'])
319
+ self.save_all_vars = PButton(VAW["Save_all_choices"]["label"], tip=VAW["Save_all_choices"]["tips"],
320
+ night_mode=self.parent().po.all['night_mode'])
306
321
  self.save_all_vars.clicked.connect(self.save_current_settings)
307
322
  self.last_options_layout.addWidget(self.save_all_vars)
308
323
 
309
324
  # Close last options widget
310
325
  self.last_options_layout.addItem(self.horizontal_space)
311
326
  self.last_options_widget.setLayout(self.last_options_layout)
312
- self.layout.addWidget(self.last_options_widget, curr_row_main_layout, 0)
327
+ self.Vlayout.addWidget(self.last_options_widget)#, curr_row_main_layout, 0)
313
328
  curr_row_main_layout += 1
314
329
 
315
330
  self.message = QtWidgets.QLabel(self)
@@ -320,7 +335,8 @@ class VideoAnalysisWindow(MainTabsType):
320
335
  self.previous = PButton('Previous', night_mode=self.parent().po.all['night_mode'])
321
336
  self.previous.clicked.connect(self.previous_is_clicked)
322
337
 
323
- self.run_all = PButton('Run All', night_mode=self.parent().po.all['night_mode'])
338
+ self.run_all = PButton(VAW["Run_All"]["label"], tip=VAW["Run_All"]["tips"],
339
+ night_mode=self.parent().po.all['night_mode'])
324
340
  self.run_all.clicked.connect(self.run_all_is_clicked)
325
341
 
326
342
  # Open last row widget
@@ -332,21 +348,32 @@ class VideoAnalysisWindow(MainTabsType):
332
348
  self.last_row_layout.addWidget(self.run_all)
333
349
  # Close last row widget
334
350
  self.last_row_widget.setLayout(self.last_row_layout)
335
- self.layout.addItem(self.vertical_space, curr_row_main_layout, 0, 1, ncol)
336
- self.layout.addWidget(self.last_row_widget, curr_row_main_layout, 0)
351
+ self.Vlayout.addItem(self.vertical_space)#, curr_row_main_layout, 0, 1, ncol)
352
+ self.Vlayout.addWidget(self.last_row_widget)#, curr_row_main_layout + 1, 0)
337
353
 
338
- self.grid_widget.setLayout(self.layout)
339
- self.Vlayout.addItem(self.vertical_space)
340
- self.Vlayout.addWidget(self.grid_widget)
341
354
  self.setLayout(self.Vlayout)
342
- # self.advanced_mode_check()
343
355
 
344
356
  def display_conditionally_visible_widgets(self):
357
+ """
358
+ Display Conditionally Visible Widgets
359
+ """
345
360
  self.select_option_label.setVisible(self.parent().po.vars["color_number"] == 2)
346
361
  self.select_option.setVisible(self.parent().po.vars["color_number"] == 2)
347
362
  self.fading.setVisible(self.parent().po.vars['do_fading'])
348
363
 
349
364
  def step_done_is_clicked(self):
365
+ """
366
+ Step the analysis progress when 'Done' button is clicked.
367
+
368
+ Increments the current step and updates the UI accordingly based on the
369
+ new step value. Updates labels, tooltips, and visibility of widgets.
370
+
371
+ Notes
372
+ -----
373
+ This method is automatically called when the 'Done' button is clicked.
374
+ It updates the GUI elements to reflect progress in a multi-step
375
+ analysis process.
376
+ """
350
377
  self.current_step += 1
351
378
  if self.current_step == 1:
352
379
  self.general_step_label.setText('Step 2: Tune fading and advanced parameters to improve Post processing')
@@ -361,6 +388,9 @@ class VideoAnalysisWindow(MainTabsType):
361
388
  self.general_step_button.setVisible(False)
362
389
 
363
390
  def reset_general_step(self):
391
+ """
392
+ Reset the general step counter and update UI labels.
393
+ """
364
394
  self.current_step = 0
365
395
  self.general_step_label.setText('Step 1: Tune parameters to improve Detection')
366
396
  self.general_step_label.setToolTip('Detection uses only the visible parameters and those\npreviously determined on the first or last image.')
@@ -368,13 +398,29 @@ class VideoAnalysisWindow(MainTabsType):
368
398
  self.second_step_widget.setVisible(False)
369
399
 
370
400
  def full_screen_display(self, event):
401
+ """
402
+ Full-screen display of an image.
403
+
404
+ This method creates a full-screen image popup and displays it. The
405
+ full-screen image is initialized with the current image to display,
406
+ and its size is set to match the screen dimensions.
407
+ """
371
408
  self.popup_img = FullScreenImage(self.parent().image_to_display, self.parent().screen_width, self.parent().screen_height)
372
409
  self.popup_img.show()
373
410
 
374
411
  def option_changed(self):
375
412
  """
376
- Update the video, save parameters
377
- :return:
413
+ Handles the logic for changing video option settings and logging the appropriate actions.
414
+
415
+ This method is responsible for updating various flags and configuration variables
416
+ based on the selected video option. It also logs informational messages regarding
417
+ the behavior of the segmentation algorithms being enabled or disabled.
418
+
419
+ Notes
420
+ -----
421
+ This function updates the parent object's configuration variables and logs messages
422
+ based on the selected video option. The behavior changes depending on the number of
423
+ colors detected and the specific video option chosen.
378
424
  """
379
425
  self.parent().po.all['video_option'] = self.select_option.currentIndex()
380
426
  self.parent().po.vars['frame_by_frame_segmentation'] = False
@@ -401,26 +447,17 @@ class VideoAnalysisWindow(MainTabsType):
401
447
  elif self.parent().po.all['video_option'] == 4:
402
448
  logging.info(f"This option will detect cell(s) using the dynamic threshold OR slope algorithms with a maximal growth factor of {self.parent().po.vars['maximal_growth_factor']}")
403
449
  self.parent().po.vars['true_if_use_light_AND_slope_else_OR'] = False
404
- # self.parent().po.motion
405
-
406
- # def advanced_mode_check(self):
407
- # advanced_mode = self.advanced_mode_cb.isChecked()
408
- # self.parent().po.all['expert_mode'] = advanced_mode
409
- # self.second_step_widget.setVisible(advanced_mode or self.current_step > 0)
410
- # if advanced_mode:
411
- # if self.current_step == 0:
412
- # self.current_step += 1
413
- # self.general_step_label.setText('Step 2: Tune fading and advanced parameters to improve Post processing')
414
- # self.save_one_result.setVisible(self.current_step == 2)
415
-
416
- # self.maximal_growth_factor.setVisible(advanced_mode)
417
- # self.maximal_growth_factor_label.setVisible(advanced_mode)
418
- # self.fading.setVisible(advanced_mode)
419
- # self.fading_label.setVisible(advanced_mode)
420
- # self.repeat_video_smoothing.setVisible(advanced_mode)
421
- # self.repeat_video_smoothing_label.setVisible(advanced_mode)
422
450
 
423
451
  def data_tab_is_clicked(self):
452
+ """
453
+ Handles the logic for when the "Data specifications" button is clicked in the interface,
454
+ leading to the FirstWindow.
455
+
456
+ Notes
457
+ -----
458
+ This function displays an error message when a thread relative to the current window is running.
459
+ This function also save the id of the following window for later use.
460
+ """
424
461
  if self.thread['VideoReader'].isRunning() or self.thread['OneArena'].isRunning() or self.thread['ChangeOneRepResult'].isRunning() or self.parent().firstwindow.thread["RunAll"].isRunning():
425
462
  self.message.setText("Wait for the analysis to end, or restart Cellects")
426
463
  else:
@@ -428,6 +465,15 @@ class VideoAnalysisWindow(MainTabsType):
428
465
  self.parent().change_widget(0) # FirstWidget
429
466
 
430
467
  def image_tab_is_clicked(self):
468
+ """
469
+ Handles the logic for when the "Image analysis" button is clicked in the interface,
470
+ leading to the image analysis window.
471
+
472
+ Notes
473
+ -----
474
+ This function displays an error message when a thread relative to the current window is running.
475
+ This function also save the id of the following window for later use.
476
+ """
431
477
  if self.image_tab.state != "not_usable":
432
478
  if self.thread['VideoReader'].isRunning() or self.thread['OneArena'].isRunning() or self.thread[
433
479
  'ChangeOneRepResult'].isRunning() or self.parent().firstwindow.thread["RunAll"].isRunning():
@@ -438,27 +484,59 @@ class VideoAnalysisWindow(MainTabsType):
438
484
 
439
485
 
440
486
  def required_outputs_is_clicked(self):
487
+ """
488
+ Sets the required outputs flag and changes the widget to the "Required Output" window.
489
+ """
441
490
  self.parent().last_is_first = False
442
491
  self.parent().change_widget(4) # RequiredOutput
443
492
 
444
493
  def advanced_parameters_is_clicked(self):
494
+ """
495
+ Modifies the interface to display advanced parameters.
496
+ """
445
497
  self.parent().last_is_first = False
446
498
  self.parent().widget(5).update_csc_editing_display()
447
499
  self.parent().change_widget(5) # AdvancedParameters
448
500
 
449
501
  def previous_is_clicked(self):
502
+ """
503
+ Transition to the previous tab based on current tab history.
504
+
505
+ This method handles the logic for navigating back through the
506
+ application's tabs when "previous" is clicked. It updates the current
507
+ tab to the one that was last visited, cycling through the predefined
508
+ order of tabs.
509
+
510
+ Notes
511
+ -----
512
+ This function is part of a state-machine-like navigation system that
513
+ tracks tab history. It assumes the parent widget has methods `last_tab`
514
+ and `change_widget` for managing the current view.
515
+ """
450
516
  if self.parent().last_tab == "data_specifications":
451
517
  self.parent().change_widget(0) # FirstWidget
452
518
  elif self.parent().last_tab == "image_analysis":
453
519
  self.parent().change_widget(2) # ThirdWidget
454
520
  self.parent().last_tab = "video_analysis"
455
- # self.parent().change_widget(2) # SecondWidget
456
521
 
457
522
  def save_all_vars_thread(self):
523
+ """
524
+ Start the 'SaveAllVars' thread if it is not already running.
525
+
526
+ This method is used to ensure that variable saving operations are performed
527
+ in a separate thread to avoid blocking the main application.
528
+ """
458
529
  if not self.parent().thread['SaveAllVars'].isRunning():
459
530
  self.parent().thread['SaveAllVars'].start() # SaveAllVarsThreadInThirdWidget
460
531
 
461
532
  def save_current_settings(self):
533
+ """
534
+ Saves the current settings from UI components to persistent storage.
535
+
536
+ This method captures the values of various UI components and stores
537
+ them in a persistent data structure to ensure settings are saved across
538
+ sessions.
539
+ """
462
540
  self.parent().po.vars['maximal_growth_factor'] = self.maximal_growth_factor.value()
463
541
  self.parent().po.vars['repeat_video_smoothing'] = int(np.round(self.repeat_video_smoothing.value()))
464
542
  self.parent().po.vars['do_fading'] = self.do_fading.isChecked()
@@ -468,24 +546,40 @@ class VideoAnalysisWindow(MainTabsType):
468
546
  self.save_all_vars_thread()
469
547
 
470
548
  def repeat_video_smoothing_changed(self):
549
+ """
550
+ Save the repeat_video_smoothing spinbox value to set how many times the pixel intensity dynamics will be
551
+ smoothed.
552
+ """
471
553
  self.parent().po.vars['repeat_video_smoothing'] = int(np.round(self.repeat_video_smoothing.value()))
472
- # self.save_all_vars_is_clicked()
473
554
 
474
555
  def do_fading_check(self):
556
+ """
557
+ Save the fading checkbox value to allow cases where pixels can be left by the specimen(s).
558
+ """
475
559
  self.parent().po.vars['do_fading'] = self.do_fading.isChecked()
476
560
  self.fading.setVisible(self.parent().po.vars['do_fading'])
477
561
 
478
562
  def fading_changed(self):
563
+ """
564
+ Save the fading spinbox value to modify how intensity must decrease to detect a pixel left by the specimen(s).
565
+ """
479
566
  self.parent().po.vars['fading'] = self.fading.value()
480
- # self.save_all_vars_is_clicked()
481
567
 
482
568
  def maximal_growth_factor_changed(self):
569
+ """
570
+ Save the maximal_growth_factor spinbox value to modulate the maximal growth between two frames.
571
+ """
483
572
  self.parent().po.vars['maximal_growth_factor'] = self.maximal_growth_factor.value()
484
- # self.save_all_vars_is_clicked()
485
573
 
486
574
  def arena_changed(self):
487
575
  """
488
- Put motion to None allows the class OneArenaThread to load the selected arena
576
+ Resets the loaded arena when its video and processing threads are not running.
577
+
578
+ Notes
579
+ -----
580
+ This function is part of a larger class responsible for managing video and
581
+ arena processing threads. It should be called when all relevant threads are not
582
+ running to ensure the arena's state is properly reset.
489
583
  """
490
584
  if not self.thread['VideoReader'].isRunning() and not self.thread['OneArena'].isRunning() and not self.thread['ChangeOneRepResult'].isRunning():
491
585
  self.parent().po.motion = None
@@ -494,31 +588,64 @@ class VideoAnalysisWindow(MainTabsType):
494
588
  self.parent().po.all['arena'] = int(np.round(self.arena.value()))
495
589
 
496
590
  def load_one_arena_is_clicked(self):
591
+ """
592
+ Load one arena if clicked.
593
+
594
+ Resets the general step, sets `load_quick_full` to 0, and runs the arena in a separate thread.
595
+ """
497
596
  self.reset_general_step()
498
- # self.save_all_vars_is_clicked()
499
597
  self.parent().po.load_quick_full = 0
500
598
  self.run_one_arena_thread()
501
599
 
502
600
  def compute_all_options_check(self):
601
+ """
602
+ Save the compute_all_options checkbox value to process every video segmentation algorithms during the next run.
603
+ """
503
604
  self.parent().po.all['compute_all_options'] = self.compute_all_options_cb.isChecked()
504
605
 
505
606
  def detection_is_clicked(self):
607
+ """
608
+ Trigger detection when a button is clicked.
609
+
610
+ This method handles the logic when the user clicks the "detection" button.
611
+ It resets certain states, sets a flag for quick full processing,
612
+ and starts a thread to run the detection in one arena.
613
+
614
+ Notes
615
+ -----
616
+ This method is part of a larger state machine for handling user interactions.
617
+ It assumes that the parent object has a `po` attribute with a `load_quick_full`
618
+ flag and a method to run an arena thread.
619
+ """
506
620
  self.reset_general_step()
507
- # self.save_all_vars_is_clicked()
508
621
  self.parent().po.load_quick_full = 1
509
622
  self.run_one_arena_thread()
510
623
 
511
624
  def post_processing_is_clicked(self):
512
- # self.save_all_vars_is_clicked()
625
+ """
626
+ Trigger post-processing when a button is clicked.
627
+
628
+ Extended Description
629
+ -------------------
630
+ This function updates the parent object's load_quick_full attribute,
631
+ logs a specific variable value, and runs an arena thread.
632
+ """
513
633
  self.parent().po.load_quick_full = 2
514
634
  logging.info(self.parent().po.vars['maximal_growth_factor'])
515
635
  self.run_one_arena_thread()
516
636
 
517
637
  def run_one_arena_thread(self):
518
638
  """
519
- Make sure that the previous thread is not running and start the OneArenaThread
520
- According to the button clicked, this class will only load, load and quick segment,
521
- or load, quickly segment and fully detect the cell(s) dynamic
639
+ Run the OneArena thread for processing.
640
+
641
+ Executes the OneArena thread to load video, initialize analysis,
642
+ stop any running instance of the thread, save settings, and connect
643
+ signals for displaying messages, images, and handling completion events.
644
+
645
+ Notes
646
+ -----
647
+ Ensures that the previous arena settings are cleared and connects signals
648
+ to display messages and images during thread execution.
522
649
  """
523
650
  if self.thread['OneArena']._isRunning:
524
651
  self.thread['OneArena'].stop()
@@ -526,20 +653,23 @@ class VideoAnalysisWindow(MainTabsType):
526
653
  if self.previous_arena != self.parent().po.all['arena']:
527
654
  self.parent().po.motion = None
528
655
  self.message.setText("Load the video and initialize analysis, wait...")
529
- # if not self.parent().po.first_exp_ready_to_run:
530
- # self.parent().po.use_data_to_run_cellects_quickly = True
531
656
  self.thread['OneArena'].start() # OneArenaThreadInThirdWidget
532
657
  self.thread['OneArena'].message_from_thread_starting.connect(self.display_message_from_thread)
533
658
  self.thread['OneArena'].when_loading_finished.connect(self.when_loading_thread_finished)
534
659
  self.thread['OneArena'].when_detection_finished.connect(self.when_detection_finished)
535
660
  self.thread['OneArena'].image_from_thread.connect(self.display_image_during_thread)
536
661
 
537
- def when_loading_thread_finished(self, save_loaded_video):
662
+ def when_loading_thread_finished(self, save_loaded_video: bool):
663
+ """
664
+ Ends the loading thread process and handles post-loading actions.
665
+
666
+ Notes
667
+ ----------
668
+ This method assumes that the parent object has a `po` attribute with an
669
+ 'arena' key and a `load_quick_full` attribute. It also assumes that the
670
+ parent object has a 'thread' dictionary and a message UI component.
671
+ """
538
672
  self.previous_arena = self.parent().po.all['arena']
539
- # if not self.parent().po.vars['already_greyscale']:
540
- # self.parent().po.motion.analysis_instance = self.parent().po.motion.visu.copy()
541
- # else:
542
- # self.parent().po.motion.analysis_instance = self.parent().po.motion.converted_video.copy()
543
673
  if save_loaded_video:
544
674
  self.thread['WriteVideo'] = WriteVideoThread(self.parent())
545
675
  self.thread['WriteVideo'].start()
@@ -547,13 +677,32 @@ class VideoAnalysisWindow(MainTabsType):
547
677
  self.message.setText("Loading done, you can watch the video")
548
678
  self.read.setVisible(True)
549
679
 
550
- def when_detection_finished(self, message):
551
- # self.option_changed()
680
+ def when_detection_finished(self, message: str):
681
+ """
682
+ Handles the completion of video detection and updates the UI accordingly.
683
+
684
+ When the video detection is finished, this function waits for the
685
+ VideoReader thread to complete if it's running. It then processes the
686
+ last frame of the video based on the configured visualization and motion
687
+ detection settings. Finally, it updates the UI with the processed image
688
+ and sets appropriate labels' visibility.
689
+
690
+ Parameters
691
+ ----------
692
+ message : str
693
+ The message to display upon completion of detection.
694
+ This could be a status update or any relevant information.
695
+
696
+ Notes
697
+ -----
698
+ This function assumes that the parent object has attributes `po` and
699
+ `image_to_display`, and methods like `display_image.update_image`.
700
+ """
552
701
  self.previous_arena = self.parent().po.all['arena']
553
702
  if self.thread['VideoReader'].isRunning(): # VideoReaderThreadInThirdWidget
554
703
  self.thread['VideoReader'].wait()
555
704
  if self.parent().po.load_quick_full > 0:
556
- image = self.parent().po.motion.segmentation[-1, ...]
705
+ image = self.parent().po.motion.segmented[-1, ...]
557
706
  if self.parent().po.motion.visu is None:
558
707
  image = self.parent().po.motion.converted_video[-1, ...] * (1 - image)
559
708
  image = np.round(image).astype(np.uint8)
@@ -563,20 +712,34 @@ class VideoAnalysisWindow(MainTabsType):
563
712
  image = self.parent().po.motion.visu[-1, ...] * (1 - image)
564
713
  self.parent().image_to_display = image
565
714
  self.display_image.update_image(image)
566
-
567
715
  self.message.setText(message)
568
-
569
716
  self.select_option_label.setVisible(self.parent().po.vars["color_number"] == 2)
570
717
  self.select_option.setVisible(self.parent().po.vars["color_number"] == 2)
571
718
  self.read.setVisible(True)
572
- # self.save_one_result.setVisible(True)
573
719
 
574
- def display_image_during_thread(self, dictionary):
720
+ def display_image_during_thread(self, dictionary: dict):
721
+ """
722
+ Display an image and set a message during a thread operation.
723
+
724
+ Parameters
725
+ ----------
726
+ dictionary : dict
727
+ A dictionary containing the 'message' and 'current_image'.
728
+ The message is a string to display.
729
+ The current_image is the image data that will be displayed.
730
+ """
575
731
  self.message.setText(dictionary['message'])
576
732
  self.parent().image_to_display = dictionary['current_image']
577
733
  self.display_image.update_image(dictionary['current_image'])
578
734
 
579
735
  def save_one_result_is_clicked(self):
736
+ """
737
+ Finalize one arena analysis and save the result if conditions are met.
738
+
739
+ This function checks various conditions before starting a thread to
740
+ finalize the analysis and save the result. It ensures that certain
741
+ threads are not running before proceeding.
742
+ """
580
743
  if self.parent().po.motion is not None:
581
744
  if self.parent().po.load_quick_full == 2:
582
745
  if not self.thread['OneArena'].isRunning() and not self.thread['ChangeOneRepResult'].isRunning():
@@ -592,56 +755,71 @@ class VideoAnalysisWindow(MainTabsType):
592
755
  self.message.setText("Run Post processing first")
593
756
 
594
757
  def read_is_clicked(self):
758
+ """
759
+ Read a video corresponding to a numbered arena (numbered using natural sorting) in the image
760
+
761
+ This function checks if the detection has been run and if the video reader or analysis thread is running.
762
+ If both threads are idle, it starts the video reading process. Otherwise, it updates the message accordingly.
763
+ """
595
764
  if self.parent().po.motion is not None:
596
- if self.parent().po.motion.segmentation is not None:
765
+ if self.parent().po.motion.segmented is not None:
597
766
  if not self.thread['OneArena'].isRunning() and not self.thread['VideoReader'].isRunning():
598
767
  self.thread['VideoReader'].start() # VideoReaderThreadInThirdWidget
599
768
  self.thread['VideoReader'].message_from_thread.connect(self.display_image_during_thread)
600
- # if self.parent().po.computed_video_options[self.parent().po.all['video_option']]:
601
- # self.message.setText("Run detection to visualize analysis")
602
769
  else:
603
770
  self.message.setText("Wait for the analysis to end")
604
771
  else:
605
772
  self.message.setText("Run detection first")
606
773
  else:
607
774
  self.message.setText("Run detection first")
608
- #
609
- # def video_display(self, dictionary):
610
- # self.drawn_image = dictionary['image']
611
- # self.display_image.update_image(dictionary['image'], self.parent().po.vars['contour_color'])
612
- # self.message.setText(dictionary['message'])
613
- # # self.message.setText(f"Reading done, try to change parameters if necessary")
614
775
 
615
776
  def run_all_is_clicked(self):
777
+ """
778
+ Handle the click event to start the complete analysis.
779
+
780
+ This function checks if any threads are running and starts the
781
+ 'RunAll' thread if none of them are active. It also updates
782
+ various attributes and messages related to the analysis process.
783
+
784
+ Notes
785
+ -----
786
+ This function will only start the analysis if no other threads
787
+ are running. It updates several attributes of the parent object.
788
+ """
616
789
  if self.thread['OneArena'].isRunning() or self.thread['ChangeOneRepResult'].isRunning():
617
790
  self.message.setText("Wait for the current analysis to end")
618
791
  else:
619
792
  if self.thread['VideoReader'].isRunning():
620
793
  self.thread['VideoReader'].wait()
621
- # self.save_all_vars_is_clicked()
622
- # self.save_current_settings()
623
794
  if self.parent().firstwindow.thread["RunAll"].isRunning():
624
795
  self.message.setText('Analysis has already begun in the first window.')
625
796
  else:
626
797
  if not self.thread['RunAll'].isRunning():
627
- # self.save_all_vars_is_clicked()
628
798
  self.save_current_settings()
629
799
  self.parent().po.motion = None
630
800
  self.parent().po.converted_video = None
631
801
  self.parent().po.converted_video2 = None
632
802
  self.parent().po.visu = None
633
803
  self.message.setText("Complete analysis has started, wait...")
634
- # if not self.parent().po.first_exp_ready_to_run:
635
- # self.parent().po.use_data_to_run_cellects_quickly = True
636
804
  self.thread['RunAll'].start() # RunAllThread
637
805
  self.thread['RunAll'].message_from_thread.connect(self.display_message_from_thread)
638
806
  self.thread['RunAll'].image_from_thread.connect(self.display_image_during_thread)
639
- # self.parent().imageanalysiswindow.true_init()
640
807
 
641
- def display_message_from_thread(self, text_from_thread):
808
+ def display_message_from_thread(self, text_from_thread: str):
809
+ """
810
+ Updates the message displayed in the UI with text from a thread.
811
+
812
+ Parameters
813
+ ----------
814
+ text_from_thread : str
815
+ The text to be displayed in the UI message.
816
+ """
642
817
  self.message.setText(text_from_thread)
643
818
 
644
819
  def closeEvent(self, event):
820
+ """
821
+ Handle the close event for a QWidget.
822
+ """
645
823
  event.accept
646
824
 
647
825