cellects 0.1.3__py3-none-any.whl → 0.2.7__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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 +365 -326
  9. cellects/gui/cellects.py +102 -91
  10. cellects/gui/custom_widgets.py +4 -3
  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 +841 -450
  14. cellects/gui/required_output.py +100 -56
  15. cellects/gui/ui_strings.py +840 -0
  16. cellects/gui/video_analysis_window.py +317 -135
  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 -105
  27. cellects/utils/utilitarian.py +86 -9
  28. cellects-0.2.7.dist-info/LICENSE +675 -0
  29. cellects-0.2.7.dist-info/METADATA +829 -0
  30. cellects-0.2.7.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.3.dist-info/LICENSE.odt +0 -0
  34. cellects-0.1.3.dist-info/METADATA +0 -176
  35. cellects-0.1.3.dist-info/RECORD +0 -44
  36. {cellects-0.1.3.dist-info → cellects-0.2.7.dist-info}/WHEEL +0 -0
  37. {cellects-0.1.3.dist-info → cellects-0.2.7.dist-info}/entry_points.txt +0 -0
  38. {cellects-0.1.3.dist-info → cellects-0.2.7.dist-info}/top_level.txt +0 -0
@@ -1,93 +1,124 @@
1
1
  #!/usr/bin/env python3
2
- """ADD DETAIL OF THE MODULE"""
3
- import os
2
+ """GUI window for selecting folders when multiple options exist in Cellects analysis workflow.
3
+
4
+ This module implements a second-stage GUI dialog that appears when multiple experiment folders are available.
5
+ It provides an interface for folder selection via checkboxes and table visualization, with navigation controls to
6
+ proceed to image analysis or return to prior steps. Includes thread-safe background operations for loading data without
7
+ freezing the UI.
8
+
9
+ Main Components
10
+ IfSeveralFoldersWindow : QWidget subclass managing folder selection and analysis workflow navigation
11
+ """
4
12
  import logging
5
- from numpy import min, max, all, any, arange, repeat
13
+ import numpy as np
6
14
  from PySide6 import QtWidgets, QtCore
7
-
8
15
  from cellects.core.cellects_threads import LoadFirstFolderIfSeveralThread
9
- from cellects.gui.custom_widgets import (
10
- WindowType, PButton, FixedText)
16
+ from cellects.gui.custom_widgets import (WindowType, PButton, FixedText)
17
+ from cellects.gui.ui_strings import MF, VAW
11
18
 
12
19
 
13
20
  class IfSeveralFoldersWindow(WindowType):
21
+ """
22
+ Second window of the Cellects GUI, only appears when there are multiple folders.
23
+ """
14
24
  def __init__(self, parent, night_mode):
25
+ """
26
+ Initialize the IfSeveralFolders window with a parent widget and night mode setting.
27
+
28
+ Parameters
29
+ ----------
30
+ parent : QWidget
31
+ The parent widget to which this window will be attached.
32
+ night_mode : bool
33
+ A boolean indicating whether the night mode should be enabled.
34
+
35
+ Examples
36
+ --------
37
+ >>> from PySide6 import QtWidgets
38
+ >>> from cellects.gui.cellects import CellectsMainWidget
39
+ >>> from cellects.gui.if_several_folders_window import IfSeveralFoldersWindow
40
+ >>> import sys
41
+ >>> app = QtWidgets.QApplication([])
42
+ >>> parent = CellectsMainWidget()
43
+ >>> session = IfSeveralFoldersWindow(parent, False)
44
+ >>> session.true_init()
45
+ >>> parent.insertWidget(0, session)
46
+ >>> parent.show()
47
+ >>> sys.exit(app.exec())
48
+ """
15
49
  super().__init__(parent, night_mode)
16
50
  self.setParent(parent)
17
51
 
18
52
  def true_init(self):
53
+ """
54
+ Initialize the IfSeveralFoldersWindow with UI components and settings.
55
+
56
+ Extended Description
57
+ --------------------
58
+ This method sets up the user interface for the IfSeveralFoldersWindow,
59
+ including labels, a table widget for folders and sample sizes, checkboxes,
60
+ buttons for video analysis and running tasks directly, and navigation
61
+ buttons for previous and next steps. The window supports multiple folder
62
+ selection and provides a means to control the analysis process.
63
+
64
+ Notes
65
+ -----
66
+ This method assumes that the parent widget has a 'po' attribute with specific settings and variables.
67
+ """
19
68
  logging.info("Initialize IfSeveralFoldersWindow")
20
69
  self.thread = {}
21
70
  self.thread["LoadFirstFolderIfSeveral"] = LoadFirstFolderIfSeveralThread(self.parent())
22
71
  self.next_clicked_once:bool = False
23
72
  self.layout = QtWidgets.QVBoxLayout()
24
- # self.layout.setAlignment(QtCore.Qt.AlignLeading)
25
- # self.layout.setGeometry(QtCore.QRect(9, 9, 2 * self.parent().screen_width // 3, 2 * self.parent().screen_height // 3))
26
73
 
27
74
  self.title_label = FixedText('Select folders to analyze', police=30, night_mode=self.parent().po.all['night_mode'])
28
75
  self.title_label.setAlignment(QtCore.Qt.AlignHCenter)
29
- # self.layout.addWidget(self.title_label, 0, 0, 1, - 1)
30
76
  self.layout.addWidget(self.title_label)
31
77
  self.layout.addItem(self.vertical_space)
32
78
 
33
79
  # 1) add a check box allowing to select every folders
34
80
  self.cb_layout = QtWidgets.QHBoxLayout()
35
81
  self.cb_widget = QtWidgets.QWidget()
36
- self.cb_label = FixedText('Check to select all folders:', tip="Otherwise, use Ctrl/Cmd to select the folders to analyze", night_mode=self.parent().po.all['night_mode'])
82
+ self.cb_label = FixedText(MF["Check_to_select_all_folders"]["label"] + ':', tip=MF["Check_to_select_all_folders"]["tips"], night_mode=self.parent().po.all['night_mode'])
37
83
  self.cb = QtWidgets.QCheckBox()
38
84
  self.cb.setChecked(True)
39
85
  self.cb.clicked.connect(self.checked)
40
- # self.cb.stateChanged.connect(self.checked)
41
-
42
- # self.layout.addWidget(self.cb_label, 1, 0, 1, 1)
43
- # self.layout.addWidget(self.cb, 1, 1, 1, 1)
44
86
  self.cb_layout.addWidget(self.cb_label)
45
87
  self.cb_layout.addWidget(self.cb)
46
88
  self.cb_layout.addItem(self.horizontal_space)
47
89
  self.cb_widget.setLayout(self.cb_layout)
48
90
  self.layout.addWidget(self.cb_widget)
49
- # spacerItem = QtWidgets.QSpacerItem(0, 1, QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Expanding)
50
- # self.layout.addItem(spacerItem, 1, 2, 1, 3)
51
91
 
52
92
  # 2) Create a folder list and sample number per folder
53
93
  self.tableau = QtWidgets.QTableWidget() # Scroll Area which contains the widgets, set as the centralWidget
54
94
  self.tableau.setColumnCount(2)
55
95
  self.tableau.setRowCount(len(self.parent().po.all['folder_list']))
56
96
  self.tableau.setHorizontalHeaderLabels(['Folders', 'Sample size'])
57
- # if len(self.parent().po.all['sample_number_per_folder']) < 2:
58
97
  self.parent().po.all['sample_number_per_folder'] = np.repeat(int(self.parent().po.all['first_folder_sample_number']), self.parent().po.all['folder_number'])
59
98
 
60
99
  for i, folder in enumerate(self.parent().po.all['folder_list']):
61
100
  self.tableau.setItem(i, 0, QtWidgets.QTableWidgetItem(folder))
62
101
  self.tableau.setItem(i, 1, QtWidgets.QTableWidgetItem(str(self.parent().po.all['sample_number_per_folder'][i])))
63
- # if isinstance(self.parent().po.all['sample_number_per_folder'], int):
64
- # self.tableau.setItem(i, 1, QtWidgets.QTableWidgetItem(str(self.parent().po.all['sample_number_per_folder'])))
65
- # else:
66
- # self.tableau.setItem(i, 1, QtWidgets.QTableWidgetItem(str(self.parent().po.all['sample_number_per_folder'][i])))
67
102
  self.tableau.horizontalHeader().setSectionResizeMode(0, QtWidgets.QHeaderView.ResizeToContents)
68
103
  self.tableau.horizontalHeader().setSectionResizeMode(1, QtWidgets.QHeaderView.ResizeToContents)
69
104
  self.tableau.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
70
105
  self.tableau.selectAll()
71
106
  self.tableau.itemSelectionChanged.connect(self.item_selection_changed)
72
107
 
73
- # self.tableau.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection)
74
108
  self.tableau.setShowGrid(False)
75
109
  self.tableau.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
76
110
  self.tableau.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded)
77
111
  self.tableau.horizontalHeader().hide()
78
112
  self.tableau.verticalHeader().hide()
79
- # self.layout.addWidget(self.tableau, 2, 0, 1, 1)
80
113
  self.layout.addWidget(self.tableau)
81
114
 
82
- # spaceItem = QtWidgets.QSpacerItem(1, 1, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Maximum)
83
- # self.layout.addItem(spaceItem, 3, 0)
84
-
85
115
  # Create the shortcuts row
86
116
  self.shortcuts_widget = QtWidgets.QWidget()
87
117
  self.shortcuts_layout = QtWidgets.QHBoxLayout()
88
118
  self.Video_analysis_window = PButton("Video tracking window", night_mode=self.parent().po.all['night_mode'])
89
119
  self.Video_analysis_window.clicked.connect(self.Video_analysis_window_is_clicked)
90
- self.Run_all_directly = PButton("Run all directly", night_mode=self.parent().po.all['night_mode'])
120
+ self.Run_all_directly = PButton("Run all directly", tip=VAW["Run_All"]["tips"],
121
+ night_mode=self.parent().po.all['night_mode'])
91
122
  self.Run_all_directly.clicked.connect(self.Run_all_directly_is_clicked)
92
123
  self.Video_analysis_window.setVisible(False)
93
124
  self.Run_all_directly.setVisible(False)
@@ -101,7 +132,6 @@ class IfSeveralFoldersWindow(WindowType):
101
132
  self.last_row_layout = QtWidgets.QHBoxLayout()
102
133
  self.last_row_widget = QtWidgets.QWidget()
103
134
  self.previous = PButton('Previous', night_mode=self.parent().po.all['night_mode'])
104
- # self.layout.addWidget(self.previous, 4, 0)
105
135
  self.previous.clicked.connect(self.previous_is_clicked)
106
136
 
107
137
  # 4) Message
@@ -109,13 +139,10 @@ class IfSeveralFoldersWindow(WindowType):
109
139
  self.message.setText('')
110
140
  self.message.setStyleSheet("color: rgb(230, 145, 18)")
111
141
  self.message.setAlignment(QtCore.Qt.AlignRight)
112
- # self.layout.addWidget(self.message, 4, 1)
113
142
 
114
143
  # 5) Next button
115
144
  self.next = PButton('Next', night_mode=self.parent().po.all['night_mode'])
116
- # self.layout.addWidget(self.next, 4, 2)
117
145
  self.next.clicked.connect(self.next_is_clicked)
118
- # self.setLayout(self.layout)
119
146
  self.last_row_layout.addWidget(self.previous)
120
147
  self.last_row_layout.addItem(self.horizontal_space)
121
148
  self.last_row_layout.addWidget(self.message)
@@ -126,23 +153,51 @@ class IfSeveralFoldersWindow(WindowType):
126
153
  self.setLayout(self.layout)
127
154
 
128
155
  def checked(self):
156
+ """
157
+ Check or uncheck all entries in the tableau based on checkbox state.
158
+
159
+ If the associated checkbox is checked, select all items in the
160
+ tableau. Otherwise, clear the selection.
161
+ """
129
162
  if self.cb.isChecked():
130
163
  self.tableau.selectAll()
131
164
  else:
132
165
  self.tableau.clearSelection()
133
166
 
134
167
  def item_selection_changed(self):
168
+ """
169
+ Update the checkbox state based on the number of selected items.
170
+ """
135
171
  if (len(self.tableau.selectedItems()) // 2) == len(self.parent().po.all['folder_list']):
136
172
  self.cb.setChecked(True)
137
173
  else:
138
174
  self.cb.setChecked(False)
139
175
 
140
176
  def previous_is_clicked(self):
177
+ """
178
+ Handles the logic for when a "Previous" button is clicked in the interface, leading to the FirstWindow.
179
+
180
+ It modifies internal state to force the decision between IfSeveralFoldersWindow and ImageAnalysisWindow to be
181
+ done once again if the user clicks on the "Next" button of the FirstWindow.
182
+ """
141
183
  self.next_clicked_once = False
142
184
  self.parent().firstwindow.instantiate = True
143
185
  self.parent().change_widget(0)
144
186
 
145
187
  def next_is_clicked(self):
188
+ """
189
+ Handles the logic for when a "Next" button is clicked in the interface, leading to the ImageAnalysisWindow.
190
+
191
+ If `self.next_clicked_once` is True, instanties widgets and performs image analysis.
192
+ Otherwise, checks for selected folders and samples. Updates internal state and starts
193
+ a thread for loading the first folder if multiple folders are selected.
194
+
195
+ Notes
196
+ -----
197
+ This function updates the internal state based on user selection and starts a thread
198
+ for loading data. The `self.parent().po.update_folder_id` method is called to update
199
+ folder IDs.
200
+ """
146
201
  if self.next_clicked_once:
147
202
  self.instantiates_widgets_and_do_image_analysis()
148
203
  else:
@@ -151,12 +206,8 @@ class IfSeveralFoldersWindow(WindowType):
151
206
  if item_number == 0:
152
207
  self.message.setText("Select at least one folder")
153
208
  else:
154
- # self.tableau.selectedItems()
155
209
  sample_number_per_folder = []
156
210
  folder_list = []
157
- # sample_number =
158
- # if isinstance(self.parent().po.all['sample_number_per_folder'], int):
159
- # sample_number = self.parent().po.all['sample_number_per_folder']
160
211
  for i in np.arange(item_number):
161
212
  if i % 2 == 0:
162
213
  folder_list.append(self.tableau.selectedItems()[i].text())
@@ -164,31 +215,22 @@ class IfSeveralFoldersWindow(WindowType):
164
215
  sample_number_per_folder.append(int(self.tableau.selectedItems()[i].text()))
165
216
  self.parent().po.all['first_folder_sample_number'] = int(self.tableau.selectedItems()[1].text())
166
217
 
167
- #
168
- # for index in self.tableau.selectionModel().selectedRows():
169
- # folder_list.append(self.parent().po.all['folder_list'][index.row()])
170
- # # if not isinstance(self.parent().po.all['sample_number_per_folder'], int):
171
- # sample_number = self.parent().po.all['sample_number_per_folder'][index.row()]
172
- # sample_number_per_folder.append(sample_number)
173
-
174
218
  self.parent().po.all['folder_list'] = folder_list
175
219
  self.parent().po.all['sample_number_per_folder'] = sample_number_per_folder
176
220
  self.parent().po.update_folder_id(self.parent().po.all['first_folder_sample_number'],
177
221
  self.parent().po.all['folder_list'][0])
178
- print(os.getcwd())
179
- # if not isinstance(self.parent().po.all['sample_number_per_folder'], int):
180
- # self.parent().po.update_folder_id(self.parent().po.all['sample_number_per_folder'][0], self.parent().po.all['folder_list'][0])
181
- # else:
182
- # self.parent().po.update_folder_id(self.parent().po.all['sample_number_per_folder'], self.parent().po.all['folder_list'][0])
183
-
184
- # if self.parent.subwidgets_stack.count() == 5:
185
- # self.parent.instantiate_widget(ImageAnalysisWindow(self.parent))
186
- # if not self.parent().imageanalysiswindow.initialized:
187
-
188
222
  self.thread["LoadFirstFolderIfSeveral"].start()
189
223
  self.thread["LoadFirstFolderIfSeveral"].message_when_thread_finished.connect(self.first_folder_loaded)
190
224
 
191
- def first_folder_loaded(self, first_exp_ready_to_run):
225
+ def first_folder_loaded(self, first_exp_ready_to_run: bool):
226
+ """
227
+ Set the visibility of widgets and messages based on whether data is found.
228
+
229
+ Parameters
230
+ ----------
231
+ first_exp_ready_to_run : bool
232
+ Indicates if the experiment data is ready to be run.
233
+ """
192
234
  if first_exp_ready_to_run:
193
235
  self.cb_widget.setVisible(False)
194
236
  self.tableau.setVisible(False)
@@ -206,34 +248,41 @@ class IfSeveralFoldersWindow(WindowType):
206
248
  self.instantiates_widgets_and_do_image_analysis()
207
249
 
208
250
  def instantiates_widgets_and_do_image_analysis(self):
209
- print(os.getcwd())
251
+ """
252
+ Instantiate widgets and initialize the image analysis window.
253
+ -----
254
+ This function is responsible for:
255
+ - Instantiating widgets with a specific condition.
256
+ - Initializing the true initialization of the image analysis window.
257
+ - Remember to not re-instantiate the image analysis window if the user goes back to the first window.
258
+ - Changing the current widget to ImageAnalysisWindow.
259
+ """
210
260
  self.parent().instantiate_widgets(severalfolder_included=False)
211
261
  self.parent().imageanalysiswindow.true_init()
212
262
  self.parent().firstwindow.instantiate = False
213
- print(os.getcwd())
214
263
  self.parent().change_widget(2)# ImageAnalysisWindow
215
- # self.parent().change_widget(3) # VideoAnalysisWindow
216
264
 
217
265
  def Video_analysis_window_is_clicked(self):
266
+ """
267
+ Save the identity of the current widget (for future navigation) and change to the video analysis window.
268
+ """
218
269
  self.parent().last_tab = "data_specifications"
219
- # self.parent().po.update_folder_id(self.parent().po.all['sample_number_per_folder'][0],
220
- # self.parent().po.all['folder_list'][0])
221
270
  self.parent().change_widget(3)
222
271
 
223
272
  def Run_all_directly_is_clicked(self):
273
+ """
274
+ Run the "Run all directly" operation in the parent window.
275
+
276
+ This function triggers the execution of the "Run all directly"
277
+ functionality by calling the corresponding method in the parent
278
+ window and then updates the state accordingly.
279
+ """
224
280
  self.parent().firstwindow.Run_all_directly_is_clicked()
225
281
  self.previous_is_clicked()
226
282
 
227
283
  def closeEvent(self, event):
284
+ """
285
+ Handle the close event for a QWidget.
286
+ """
228
287
  event.accept
229
288
 
230
-
231
- # if __name__ == "__main__":
232
- # from cellects.gui.cellects import CellectsMainWidget
233
- # import sys
234
- # app = QtWidgets.QApplication([])
235
- # parent = CellectsMainWidget()
236
- # session = IfSeveralFoldersWindow(parent, False)
237
- # parent.insertWidget(0, session)
238
- # parent.show()
239
- # sys.exit(app.exec())