celldetective 1.2.1__tar.gz → 1.2.2.post1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (100) hide show
  1. {celldetective-1.2.1 → celldetective-1.2.2.post1}/PKG-INFO +19 -12
  2. {celldetective-1.2.1 → celldetective-1.2.2.post1}/README.md +12 -6
  3. {celldetective-1.2.1 → celldetective-1.2.2.post1}/celldetective/__main__.py +12 -5
  4. {celldetective-1.2.1 → celldetective-1.2.2.post1}/celldetective/events.py +28 -2
  5. {celldetective-1.2.1 → celldetective-1.2.2.post1}/celldetective/gui/about.py +0 -1
  6. {celldetective-1.2.1 → celldetective-1.2.2.post1}/celldetective/gui/analyze_block.py +3 -18
  7. {celldetective-1.2.1 → celldetective-1.2.2.post1}/celldetective/gui/btrack_options.py +126 -21
  8. {celldetective-1.2.1 → celldetective-1.2.2.post1}/celldetective/gui/classifier_widget.py +67 -111
  9. {celldetective-1.2.1 → celldetective-1.2.2.post1}/celldetective/gui/configure_new_exp.py +37 -4
  10. {celldetective-1.2.1 → celldetective-1.2.2.post1}/celldetective/gui/control_panel.py +14 -30
  11. celldetective-1.2.2.post1/celldetective/gui/generic_signal_plot.py +793 -0
  12. {celldetective-1.2.1 → celldetective-1.2.2.post1}/celldetective/gui/gui_utils.py +401 -226
  13. {celldetective-1.2.1 → celldetective-1.2.2.post1}/celldetective/gui/json_readers.py +0 -2
  14. {celldetective-1.2.1 → celldetective-1.2.2.post1}/celldetective/gui/layouts.py +269 -25
  15. {celldetective-1.2.1 → celldetective-1.2.2.post1}/celldetective/gui/measurement_options.py +14 -23
  16. {celldetective-1.2.1 → celldetective-1.2.2.post1}/celldetective/gui/neighborhood_options.py +3 -15
  17. {celldetective-1.2.1 → celldetective-1.2.2.post1}/celldetective/gui/plot_measurements.py +10 -23
  18. celldetective-1.2.2.post1/celldetective/gui/plot_signals_ui.py +437 -0
  19. {celldetective-1.2.1 → celldetective-1.2.2.post1}/celldetective/gui/process_block.py +320 -186
  20. {celldetective-1.2.1 → celldetective-1.2.2.post1}/celldetective/gui/retrain_segmentation_model_options.py +30 -47
  21. {celldetective-1.2.1 → celldetective-1.2.2.post1}/celldetective/gui/retrain_signal_model_options.py +5 -14
  22. {celldetective-1.2.1 → celldetective-1.2.2.post1}/celldetective/gui/seg_model_loader.py +129 -113
  23. {celldetective-1.2.1 → celldetective-1.2.2.post1}/celldetective/gui/signal_annotator.py +89 -99
  24. {celldetective-1.2.1 → celldetective-1.2.2.post1}/celldetective/gui/signal_annotator2.py +5 -9
  25. {celldetective-1.2.1 → celldetective-1.2.2.post1}/celldetective/gui/styles.py +32 -0
  26. celldetective-1.2.2.post1/celldetective/gui/survival_ui.py +277 -0
  27. {celldetective-1.2.1 → celldetective-1.2.2.post1}/celldetective/gui/tableUI.py +0 -1
  28. {celldetective-1.2.1 → celldetective-1.2.2.post1}/celldetective/gui/thresholds_gui.py +38 -11
  29. {celldetective-1.2.1 → celldetective-1.2.2.post1}/celldetective/gui/viewers.py +6 -7
  30. {celldetective-1.2.1 → celldetective-1.2.2.post1}/celldetective/io.py +60 -82
  31. {celldetective-1.2.1 → celldetective-1.2.2.post1}/celldetective/measure.py +374 -15
  32. {celldetective-1.2.1 → celldetective-1.2.2.post1}/celldetective/neighborhood.py +1 -7
  33. {celldetective-1.2.1 → celldetective-1.2.2.post1}/celldetective/preprocessing.py +2 -4
  34. {celldetective-1.2.1 → celldetective-1.2.2.post1}/celldetective/relative_measurements.py +0 -3
  35. {celldetective-1.2.1 → celldetective-1.2.2.post1}/celldetective/scripts/analyze_signals.py +0 -1
  36. {celldetective-1.2.1 → celldetective-1.2.2.post1}/celldetective/scripts/measure_cells.py +1 -3
  37. {celldetective-1.2.1 → celldetective-1.2.2.post1}/celldetective/scripts/measure_relative.py +1 -2
  38. {celldetective-1.2.1 → celldetective-1.2.2.post1}/celldetective/scripts/segment_cells.py +16 -12
  39. {celldetective-1.2.1 → celldetective-1.2.2.post1}/celldetective/scripts/segment_cells_thresholds.py +17 -10
  40. {celldetective-1.2.1 → celldetective-1.2.2.post1}/celldetective/scripts/track_cells.py +18 -18
  41. {celldetective-1.2.1 → celldetective-1.2.2.post1}/celldetective/scripts/train_segmentation_model.py +1 -2
  42. {celldetective-1.2.1 → celldetective-1.2.2.post1}/celldetective/scripts/train_signal_model.py +0 -3
  43. {celldetective-1.2.1 → celldetective-1.2.2.post1}/celldetective/segmentation.py +1 -1
  44. {celldetective-1.2.1 → celldetective-1.2.2.post1}/celldetective/signals.py +17 -8
  45. {celldetective-1.2.1 → celldetective-1.2.2.post1}/celldetective/tracking.py +2 -1
  46. {celldetective-1.2.1 → celldetective-1.2.2.post1}/celldetective/utils.py +42 -2
  47. {celldetective-1.2.1 → celldetective-1.2.2.post1}/celldetective.egg-info/PKG-INFO +19 -12
  48. {celldetective-1.2.1 → celldetective-1.2.2.post1}/celldetective.egg-info/SOURCES.txt +1 -6
  49. {celldetective-1.2.1 → celldetective-1.2.2.post1}/celldetective.egg-info/requires.txt +6 -5
  50. {celldetective-1.2.1 → celldetective-1.2.2.post1}/setup.py +1 -1
  51. celldetective-1.2.1/celldetective/gui/plot_signals_ui.py +0 -1071
  52. celldetective-1.2.1/celldetective/gui/survival_ui.py +0 -940
  53. celldetective-1.2.1/celldetective/models/segmentation_effectors/primNK_cfse/config_input.json +0 -29
  54. celldetective-1.2.1/celldetective/models/segmentation_effectors/primNK_cfse/cp-cfse-transfer +0 -0
  55. celldetective-1.2.1/celldetective/models/segmentation_effectors/primNK_cfse/training_instructions.json +0 -37
  56. celldetective-1.2.1/celldetective/models/segmentation_effectors/ricm-bimodal/config_input.json +0 -130
  57. celldetective-1.2.1/celldetective/models/segmentation_effectors/ricm-bimodal/ricm-bimodal +0 -0
  58. celldetective-1.2.1/celldetective/models/segmentation_effectors/ricm-bimodal/training_instructions.json +0 -37
  59. {celldetective-1.2.1 → celldetective-1.2.2.post1}/LICENSE +0 -0
  60. {celldetective-1.2.1 → celldetective-1.2.2.post1}/celldetective/__init__.py +0 -0
  61. {celldetective-1.2.1 → celldetective-1.2.2.post1}/celldetective/datasets/segmentation_annotations/blank +0 -0
  62. {celldetective-1.2.1 → celldetective-1.2.2.post1}/celldetective/datasets/signal_annotations/blank +0 -0
  63. {celldetective-1.2.1 → celldetective-1.2.2.post1}/celldetective/extra_properties.py +0 -0
  64. {celldetective-1.2.1 → celldetective-1.2.2.post1}/celldetective/filters.py +0 -0
  65. {celldetective-1.2.1 → celldetective-1.2.2.post1}/celldetective/gui/__init__.py +0 -0
  66. {celldetective-1.2.1 → celldetective-1.2.2.post1}/celldetective/gui/signal_annotator_options.py +0 -0
  67. {celldetective-1.2.1 → celldetective-1.2.2.post1}/celldetective/icons/logo-large.png +0 -0
  68. {celldetective-1.2.1 → celldetective-1.2.2.post1}/celldetective/icons/logo.png +0 -0
  69. {celldetective-1.2.1 → celldetective-1.2.2.post1}/celldetective/icons/signals_icon.png +0 -0
  70. {celldetective-1.2.1 → celldetective-1.2.2.post1}/celldetective/icons/splash-test.png +0 -0
  71. {celldetective-1.2.1 → celldetective-1.2.2.post1}/celldetective/icons/splash.png +0 -0
  72. {celldetective-1.2.1 → celldetective-1.2.2.post1}/celldetective/icons/splash0.png +0 -0
  73. {celldetective-1.2.1 → celldetective-1.2.2.post1}/celldetective/icons/survival2.png +0 -0
  74. {celldetective-1.2.1 → celldetective-1.2.2.post1}/celldetective/icons/vignette_signals2.png +0 -0
  75. {celldetective-1.2.1 → celldetective-1.2.2.post1}/celldetective/icons/vignette_signals2.svg +0 -0
  76. {celldetective-1.2.1 → celldetective-1.2.2.post1}/celldetective/links/zenodo.json +0 -0
  77. {celldetective-1.2.1 → celldetective-1.2.2.post1}/celldetective/models/pair_signal_detection/blank +0 -0
  78. {celldetective-1.2.1 → celldetective-1.2.2.post1}/celldetective/models/segmentation_effectors/blank +0 -0
  79. {celldetective-1.2.1 → celldetective-1.2.2.post1}/celldetective/models/segmentation_generic/blank +0 -0
  80. {celldetective-1.2.1 → celldetective-1.2.2.post1}/celldetective/models/segmentation_targets/blank +0 -0
  81. {celldetective-1.2.1 → celldetective-1.2.2.post1}/celldetective/models/signal_detection/blank +0 -0
  82. {celldetective-1.2.1 → celldetective-1.2.2.post1}/celldetective/models/tracking_configs/mcf7.json +0 -0
  83. {celldetective-1.2.1 → celldetective-1.2.2.post1}/celldetective/models/tracking_configs/ricm.json +0 -0
  84. {celldetective-1.2.1 → celldetective-1.2.2.post1}/celldetective/models/tracking_configs/ricm2.json +0 -0
  85. {celldetective-1.2.1 → celldetective-1.2.2.post1}/celldetective.egg-info/dependency_links.txt +0 -0
  86. {celldetective-1.2.1 → celldetective-1.2.2.post1}/celldetective.egg-info/entry_points.txt +0 -0
  87. {celldetective-1.2.1 → celldetective-1.2.2.post1}/celldetective.egg-info/not-zip-safe +0 -0
  88. {celldetective-1.2.1 → celldetective-1.2.2.post1}/celldetective.egg-info/top_level.txt +0 -0
  89. {celldetective-1.2.1 → celldetective-1.2.2.post1}/setup.cfg +0 -0
  90. {celldetective-1.2.1 → celldetective-1.2.2.post1}/tests/__init__.py +0 -0
  91. {celldetective-1.2.1 → celldetective-1.2.2.post1}/tests/test_events.py +0 -0
  92. {celldetective-1.2.1 → celldetective-1.2.2.post1}/tests/test_filters.py +0 -0
  93. {celldetective-1.2.1 → celldetective-1.2.2.post1}/tests/test_io.py +0 -0
  94. {celldetective-1.2.1 → celldetective-1.2.2.post1}/tests/test_measure.py +0 -0
  95. {celldetective-1.2.1 → celldetective-1.2.2.post1}/tests/test_neighborhood.py +0 -0
  96. {celldetective-1.2.1 → celldetective-1.2.2.post1}/tests/test_preprocessing.py +0 -0
  97. {celldetective-1.2.1 → celldetective-1.2.2.post1}/tests/test_segmentation.py +0 -0
  98. {celldetective-1.2.1 → celldetective-1.2.2.post1}/tests/test_signals.py +0 -0
  99. {celldetective-1.2.1 → celldetective-1.2.2.post1}/tests/test_tracking.py +0 -0
  100. {celldetective-1.2.1 → celldetective-1.2.2.post1}/tests/test_utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: celldetective
3
- Version: 1.2.1
3
+ Version: 1.2.2.post1
4
4
  Summary: description
5
5
  Home-page: http://github.com/remyeltorro/celldetective
6
6
  Author: Rémy Torro
@@ -12,14 +12,14 @@ Requires-Dist: wheel
12
12
  Requires-Dist: nbsphinx
13
13
  Requires-Dist: nbsphinx_link
14
14
  Requires-Dist: sphinx_rtd_theme
15
- Requires-Dist: sphinx==5.0.2
16
- Requires-Dist: jinja2<3.1
15
+ Requires-Dist: sphinx
16
+ Requires-Dist: jinja2
17
17
  Requires-Dist: ipykernel
18
18
  Requires-Dist: stardist
19
19
  Requires-Dist: cellpose<3
20
20
  Requires-Dist: scikit-learn
21
21
  Requires-Dist: btrack
22
- Requires-Dist: tensorflow<=2.12.1
22
+ Requires-Dist: tensorflow~=2.15.0
23
23
  Requires-Dist: napari
24
24
  Requires-Dist: tqdm
25
25
  Requires-Dist: mahotas
@@ -32,10 +32,11 @@ Requires-Dist: seaborn
32
32
  Requires-Dist: opencv-python-headless==4.7.0.72
33
33
  Requires-Dist: liblapack
34
34
  Requires-Dist: gputools
35
- Requires-Dist: lmfit~=1.2.2
36
- Requires-Dist: superqt[cmap]>=0.6.1
35
+ Requires-Dist: lmfit
36
+ Requires-Dist: superqt[cmap]
37
37
  Requires-Dist: setuptools
38
38
  Requires-Dist: matplotlib_scalebar
39
+ Requires-Dist: numpy==1.26.4
39
40
 
40
41
  # Celldetective
41
42
 
@@ -166,23 +167,25 @@ steps.
166
167
 
167
168
  To use the software, you must install python, *e.g.* through
168
169
  [Anaconda](https://www.anaconda.com/download). We developed and tested
169
- the software in Python 3.9.18.
170
+ the software in Python 3.9 and more recently 3.11.
170
171
 
171
172
  # Installation
172
173
 
173
174
  ## Stable release
174
175
 
175
- Celldetective can be installed with `pip`:
176
+ Celldetective requires a version of Python between 3.9 and 3.11 (included). If your Python version is older or more recent, consider using `conda` to create an environment as described below.
177
+
178
+ With the proper Python version, Celldetective can be directly installed with `pip`:
176
179
 
177
180
  ``` bash
178
181
  pip install celldetective
179
182
  ```
180
183
 
181
- We recommend that you create an environment to use Celldetective, *e.g.*
184
+ We recommend that you create an environment to use Celldetective, to protect your package versions and fix the Python version *e.g.*
182
185
  with `conda`:
183
186
 
184
187
  ``` bash
185
- conda create -n celldetective python=3.9.18 pyqt
188
+ conda create -n celldetective python=3.11 pyqt
186
189
  conda activate celldetective
187
190
  pip install celldetective
188
191
  ```
@@ -208,6 +211,10 @@ will be immediately available in the python environment:
208
211
  git clone git://github.com/remyeltorro/celldetective.git
209
212
  cd celldetective
210
213
 
214
+ # optional: create an environment
215
+ conda create -n celldetective python=3.11 pyqt
216
+ conda activate celldetective
217
+
211
218
  # install the celldetective package in editable/development mode
212
219
  pip install -r requirements.txt
213
220
  pip install -e .
@@ -230,10 +237,10 @@ with package requirements for other projects. Run the following lines to
230
237
  create an environment named \"celldetective\":
231
238
 
232
239
  ``` bash
233
- conda create -n celldetective python=3.9.18 pyqt
240
+ conda create -n celldetective python=3.11 pyqt
234
241
  conda activate celldetective
235
242
  pip install -r requirements.txt
236
- pip install .
243
+ pip install -e .
237
244
  ```
238
245
 
239
246
  The installation of the dependencies will take a few minutes (up to half
@@ -127,23 +127,25 @@ steps.
127
127
 
128
128
  To use the software, you must install python, *e.g.* through
129
129
  [Anaconda](https://www.anaconda.com/download). We developed and tested
130
- the software in Python 3.9.18.
130
+ the software in Python 3.9 and more recently 3.11.
131
131
 
132
132
  # Installation
133
133
 
134
134
  ## Stable release
135
135
 
136
- Celldetective can be installed with `pip`:
136
+ Celldetective requires a version of Python between 3.9 and 3.11 (included). If your Python version is older or more recent, consider using `conda` to create an environment as described below.
137
+
138
+ With the proper Python version, Celldetective can be directly installed with `pip`:
137
139
 
138
140
  ``` bash
139
141
  pip install celldetective
140
142
  ```
141
143
 
142
- We recommend that you create an environment to use Celldetective, *e.g.*
144
+ We recommend that you create an environment to use Celldetective, to protect your package versions and fix the Python version *e.g.*
143
145
  with `conda`:
144
146
 
145
147
  ``` bash
146
- conda create -n celldetective python=3.9.18 pyqt
148
+ conda create -n celldetective python=3.11 pyqt
147
149
  conda activate celldetective
148
150
  pip install celldetective
149
151
  ```
@@ -169,6 +171,10 @@ will be immediately available in the python environment:
169
171
  git clone git://github.com/remyeltorro/celldetective.git
170
172
  cd celldetective
171
173
 
174
+ # optional: create an environment
175
+ conda create -n celldetective python=3.11 pyqt
176
+ conda activate celldetective
177
+
172
178
  # install the celldetective package in editable/development mode
173
179
  pip install -r requirements.txt
174
180
  pip install -e .
@@ -191,10 +197,10 @@ with package requirements for other projects. Run the following lines to
191
197
  create an environment named \"celldetective\":
192
198
 
193
199
  ``` bash
194
- conda create -n celldetective python=3.9.18 pyqt
200
+ conda create -n celldetective python=3.11 pyqt
195
201
  conda activate celldetective
196
202
  pip install -r requirements.txt
197
- pip install .
203
+ pip install -e .
198
204
  ```
199
205
 
200
206
  The installation of the dependencies will take a few minutes (up to half
@@ -27,10 +27,10 @@ class AppInitWindow(QMainWindow):
27
27
 
28
28
  try:
29
29
  subprocess.check_output('nvidia-smi')
30
- print('Nvidia GPU detected')
30
+ print('NVIDIA GPU detected (activate or disable in Memory & Threads)...')
31
31
  self.use_gpu = True
32
32
  except Exception: # this command not being found can raise quite a few different errors depending on the configuration
33
- print('No Nvidia GPU in system!')
33
+ print('No NVIDIA GPU detected...')
34
34
  self.use_gpu = False
35
35
 
36
36
  self.soft_path = get_software_location()
@@ -170,13 +170,16 @@ class AppInitWindow(QMainWindow):
170
170
 
171
171
  self.recentFileActs = []
172
172
  self.threads_config_path = os.sep.join([self.soft_path,'celldetective','threads.json'])
173
+ print('Reading previous Memory & Threads settings...')
173
174
  if os.path.exists(self.threads_config_path):
174
175
  with open(self.threads_config_path, 'r') as f:
175
176
  self.threads_config = json.load(f)
176
177
  if 'use_gpu' in self.threads_config:
177
178
  self.use_gpu = bool(self.threads_config['use_gpu'])
179
+ print(f'Use GPU: {self.use_gpu}...')
178
180
  if 'n_threads' in self.threads_config:
179
181
  self.n_threads = int(self.threads_config['n_threads'])
182
+ print(f'Number of threads: {self.n_threads}...')
180
183
 
181
184
 
182
185
  def reload_previous_experiments(self):
@@ -250,9 +253,9 @@ class AppInitWindow(QMainWindow):
250
253
  self.open_directory()
251
254
 
252
255
  def load_recent_exp(self, path):
253
- print('loading?')
254
- print('you selected path ', path)
256
+
255
257
  self.experiment_path_selection.setText(path)
258
+ print(f'Attempt to load experiment folder: {path}...')
256
259
  self.open_directory()
257
260
 
258
261
  def open_about_window(self):
@@ -351,7 +354,7 @@ class AppInitWindow(QMainWindow):
351
354
  print(f"Found {self.number_of_wells} wells...")
352
355
  number_pos = []
353
356
  for w in wells:
354
- position_folders = glob(os.sep.join([w,f"{w.split(os.sep)[-2][1]}*", os.sep]))
357
+ position_folders = glob(os.sep.join([w,f"{w.split(os.sep)[-1][1]}*", os.sep]))
355
358
  number_pos.append(len(position_folders))
356
359
  print(f"Number of positions per well: {number_pos}")
357
360
 
@@ -393,6 +396,7 @@ if __name__ == "__main__":
393
396
  # myappid = 'mycompany.myproduct.subproduct.version' # arbitrary string
394
397
  # ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID(myappid)
395
398
  splash=True
399
+ print('Loading the libraries...')
396
400
 
397
401
  App = QApplication(sys.argv)
398
402
  #App.setWindowIcon(QIcon(os.sep.join([get_software_location(),'celldetective','icons','mexican-hat.png'])))
@@ -425,7 +429,10 @@ if __name__ == "__main__":
425
429
  import psutil
426
430
  import subprocess
427
431
  import json
432
+ # import matplotlib
433
+ # matplotlib.rcParams.update({'font.size': 8})
428
434
 
435
+ print('Libraries successfully loaded...')
429
436
 
430
437
  window = AppInitWindow(App)
431
438
 
@@ -1,5 +1,5 @@
1
1
  import numpy as np
2
-
2
+ from lifelines import KaplanMeierFitter
3
3
 
4
4
  def switch_to_events(classes, event_times, max_times, origin_times=None, left_censored=True, FrameToMin=None):
5
5
 
@@ -104,4 +104,30 @@ def switch_to_events(classes, event_times, max_times, origin_times=None, left_ce
104
104
  if FrameToMin is not None:
105
105
  #print('convert to minutes!', FrameToMin)
106
106
  survival_times = [s*FrameToMin for s in survival_times]
107
- return events, survival_times
107
+ return events, survival_times
108
+
109
+ def compute_survival(df, class_of_interest, t_event, t_reference=None, FrameToMin=1):
110
+
111
+ cols = list(df.columns)
112
+ assert class_of_interest in cols,"The requested class cannot be found in the dataframe..."
113
+ assert t_event in cols,"The event time cannot be found in the dataframe..."
114
+ left_censored = False
115
+
116
+ classes = df.groupby(['position','TRACK_ID'])[class_of_interest].min().values
117
+ event_times = df.groupby(['position','TRACK_ID'])[t_event].min().values
118
+ max_times = df.groupby(['position','TRACK_ID'])['FRAME'].max().values
119
+
120
+ if t_reference is not None:
121
+ left_censored = True
122
+ assert t_reference in cols,"The reference time cannot be found in the dataframe..."
123
+ first_detections = df.groupby(['position','TRACK_ID'])[t_reference].max().values
124
+
125
+ events, survival_times = switch_to_events(classes, event_times, max_times, origin_times=first_detections, left_censored=left_censored, FrameToMin=FrameToMin)
126
+ ks = KaplanMeierFitter()
127
+ if len(events)>0:
128
+ ks.fit(survival_times, event_observed=events)
129
+ else:
130
+ ks = None
131
+
132
+ return ks
133
+
@@ -2,7 +2,6 @@ from PyQt5.QtWidgets import QWidget, QVBoxLayout, QLabel
2
2
  from PyQt5.QtGui import QPixmap
3
3
  from PyQt5.QtCore import Qt
4
4
  from celldetective.utils import get_software_location
5
- import celldetective
6
5
  import os
7
6
  from celldetective.gui.gui_utils import center_window
8
7
 
@@ -1,25 +1,10 @@
1
- from PyQt5.QtWidgets import QFrame, QGridLayout, QComboBox, QLabel, QPushButton, QVBoxLayout, QHBoxLayout, QCheckBox, \
2
- QMessageBox, QSpacerItem, QSizePolicy
1
+ from PyQt5.QtWidgets import QFrame, QLabel, QPushButton, QVBoxLayout, \
2
+ QSpacerItem, QSizePolicy
3
3
  from PyQt5.QtCore import Qt, QSize
4
4
  from PyQt5.QtGui import QIcon
5
-
6
- from superqt.fonticon import icon
7
- from fonticon_mdi6 import MDI6
8
- import gc
9
-
10
5
  from celldetective.gui.plot_measurements import ConfigMeasurementsPlot
11
- from celldetective.io import get_segmentation_models_list, control_segmentation_napari, get_signal_models_list, control_tracking_btrack
12
6
  from celldetective.gui import ConfigSurvival, ConfigSignalPlot
13
- from celldetective.gui.gui_utils import QHSeperationLine
14
- from celldetective.segmentation import segment_at_position, segment_from_threshold_at_position
15
- from celldetective.tracking import track_at_position
16
- from celldetective.measure import measure_at_position
17
- from celldetective.signals import analyze_signals_at_position
18
- import numpy as np
19
- from glob import glob
20
- from natsort import natsorted
21
7
  import os
22
- import pandas as pd
23
8
  from celldetective.gui import Styles
24
9
 
25
10
  class AnalysisPanel(QFrame, Styles):
@@ -94,7 +79,7 @@ class AnalysisPanel(QFrame, Styles):
94
79
  self.configSurvival.show()
95
80
 
96
81
  def configure_plot_signals(self):
97
- print('plot signal analysis starting!!!')
82
+ print('Configure a signal collapse representation...')
98
83
  self.ConfigSignalPlot = ConfigSignalPlot(self)
99
84
  self.ConfigSignalPlot.show()
100
85
 
@@ -1,7 +1,7 @@
1
1
  from PyQt5.QtWidgets import QMainWindow, QApplication, QMessageBox, QScrollArea, QComboBox, QFrame, QCheckBox, QFileDialog, QGridLayout, QTextEdit, QLineEdit, QVBoxLayout, QWidget, QLabel, QHBoxLayout, QPushButton
2
2
  from PyQt5.QtCore import Qt, QSize
3
- from celldetective.gui.gui_utils import center_window, FeatureChoice, ListWidget, QHSeperationLine, FigureCanvas
4
- from superqt import QLabeledDoubleRangeSlider, QLabeledDoubleSlider,QLabeledSlider
3
+ from celldetective.gui.gui_utils import center_window, FeatureChoice, ListWidget, QHSeperationLine, FigureCanvas, help_generic
4
+ from superqt import QLabeledDoubleSlider,QLabeledSlider
5
5
  from superqt.fonticon import icon
6
6
  from fonticon_mdi6 import MDI6
7
7
  from celldetective.utils import extract_experiment_channels, get_software_location
@@ -47,8 +47,9 @@ class ConfigTracking(QMainWindow, Styles):
47
47
 
48
48
  center_window(self)
49
49
  self.setMinimumWidth(540)
50
- self.setMinimumHeight(int(0.3*self.screen_height))
51
- self.setMaximumHeight(int(0.8*self.screen_height))
50
+ self.minimum_height = 300
51
+ # self.setMinimumHeight(int(0.3*self.screen_height))
52
+ # self.setMaximumHeight(int(0.8*self.screen_height))
52
53
  self.populate_widget()
53
54
  self.load_previous_tracking_instructions()
54
55
 
@@ -116,7 +117,6 @@ class ConfigTracking(QMainWindow, Styles):
116
117
  self.select_post_proc_btn = QPushButton()
117
118
  self.select_post_proc_btn.clicked.connect(self.activate_post_proc_options)
118
119
  self.select_post_proc_btn.setStyleSheet(self.button_select_all)
119
- grid.addWidget(self.select_post_proc_btn, 0,0,1,4,alignment=Qt.AlignLeft)
120
120
 
121
121
  self.post_proc_lbl = QLabel("POST-PROCESSING")
122
122
  self.post_proc_lbl.setStyleSheet("""
@@ -125,19 +125,100 @@ class ConfigTracking(QMainWindow, Styles):
125
125
  """)
126
126
  grid.addWidget(self.post_proc_lbl, 0, 0, 1, 4, alignment=Qt.AlignCenter)
127
127
 
128
+ title_hbox = QHBoxLayout()
129
+
128
130
  self.collapse_post_proc_btn = QPushButton()
129
131
  self.collapse_post_proc_btn.setIcon(icon(MDI6.chevron_down,color="black"))
130
132
  self.collapse_post_proc_btn.setIconSize(QSize(20, 20))
131
133
  self.collapse_post_proc_btn.setStyleSheet(self.button_select_all)
132
- grid.addWidget(self.collapse_post_proc_btn, 0, 0, 1, 4, alignment=Qt.AlignRight)
134
+ #grid.addWidget(self.collapse_post_proc_btn, 0, 0, 1, 4, alignment=Qt.AlignRight)
135
+
136
+ self.help_post_btn = QPushButton()
137
+ self.help_post_btn.setIcon(icon(MDI6.help_circle,color=self.help_color))
138
+ self.help_post_btn.setIconSize(QSize(20, 20))
139
+ self.help_post_btn.clicked.connect(self.help_post)
140
+ self.help_post_btn.setStyleSheet(self.button_select_all)
141
+ self.help_post_btn.setToolTip("Help.")
142
+
143
+ title_hbox.addWidget(self.select_post_proc_btn, 5)
144
+ title_hbox.addWidget(QLabel(), 85, alignment=Qt.AlignCenter)
145
+ title_hbox.addWidget(self.help_post_btn, 5)
146
+ title_hbox.addWidget(self.collapse_post_proc_btn, 5)
147
+ grid.addLayout(title_hbox, 0,0,1,4)
133
148
 
134
149
  self.generate_post_proc_panel_contents()
135
150
  grid.addWidget(self.ContentsPostProc, 1, 0, 1, 4, alignment=Qt.AlignTop)
136
151
  self.collapse_post_proc_btn.clicked.connect(lambda: self.ContentsPostProc.setHidden(not self.ContentsPostProc.isHidden()))
137
- # self.collapse_post_proc_btn.clicked.connect(self.collapse_features_advanced)
152
+ self.collapse_post_proc_btn.clicked.connect(self.collapse_post_advanced)
138
153
  self.ContentsPostProc.hide()
139
154
  self.uncheck_post_proc()
140
155
 
156
+ def collapse_post_advanced(self):
157
+
158
+ features_open = not self.ContentsFeatures.isHidden()
159
+ config_open = not self.ContentsConfig.isHidden()
160
+ post_open = not self.ContentsPostProc.isHidden()
161
+ is_open = np.array([features_open, config_open, post_open])
162
+
163
+ if self.ContentsPostProc.isHidden():
164
+ self.collapse_post_proc_btn.setIcon(icon(MDI6.chevron_down,color="black"))
165
+ self.collapse_post_proc_btn.setIconSize(QSize(20, 20))
166
+ if len(is_open[is_open])==0:
167
+ self.scroll_area.setMinimumHeight(int(self.minimum_height))
168
+ self.adjustSize()
169
+ else:
170
+ self.collapse_post_proc_btn.setIcon(icon(MDI6.chevron_up,color="black"))
171
+ self.collapse_post_proc_btn.setIconSize(QSize(20, 20))
172
+ self.scroll_area.setMinimumHeight(min(int(930), int(0.9*self.screen_height)))
173
+
174
+
175
+ def help_post(self):
176
+
177
+ """
178
+ Helper for track post-processing strategy.
179
+ """
180
+
181
+ dict_path = os.sep.join([get_software_location(),'celldetective','gui','help','track-postprocessing.json'])
182
+
183
+ with open(dict_path) as f:
184
+ d = json.load(f)
185
+
186
+ suggestion = help_generic(d)
187
+ if isinstance(suggestion, str):
188
+ print(f"{suggestion=}")
189
+ msgBox = QMessageBox()
190
+ msgBox.setIcon(QMessageBox.Information)
191
+ msgBox.setTextFormat(Qt.RichText)
192
+ msgBox.setText(rf"{suggestion}")
193
+ msgBox.setWindowTitle("Info")
194
+ msgBox.setStandardButtons(QMessageBox.Ok)
195
+ returnValue = msgBox.exec()
196
+ if returnValue == QMessageBox.Ok:
197
+ return None
198
+
199
+ def help_feature(self):
200
+
201
+ """
202
+ Helper for track post-processing strategy.
203
+ """
204
+
205
+ dict_path = os.sep.join([get_software_location(),'celldetective','gui','help','feature-btrack.json'])
206
+
207
+ with open(dict_path) as f:
208
+ d = json.load(f)
209
+
210
+ suggestion = help_generic(d)
211
+ if isinstance(suggestion, str):
212
+ print(f"{suggestion=}")
213
+ msgBox = QMessageBox()
214
+ msgBox.setIcon(QMessageBox.Information)
215
+ msgBox.setTextFormat(Qt.RichText)
216
+ msgBox.setText(rf"{suggestion}")
217
+ msgBox.setWindowTitle("Info")
218
+ msgBox.setStandardButtons(QMessageBox.Ok)
219
+ returnValue = msgBox.exec()
220
+ if returnValue == QMessageBox.Ok:
221
+ return None
141
222
 
142
223
  def populate_features_frame(self):
143
224
 
@@ -146,12 +227,11 @@ class ConfigTracking(QMainWindow, Styles):
146
227
  """
147
228
 
148
229
  grid = QGridLayout(self.features_frame)
149
-
230
+ title_hbox = QHBoxLayout()
231
+
150
232
  self.select_features_btn = QPushButton()
151
233
  self.select_features_btn.clicked.connect(self.activate_feature_options)
152
234
  self.select_features_btn.setStyleSheet(self.button_select_all)
153
- grid.addWidget(self.select_features_btn, 0,0,1,4,alignment=Qt.AlignLeft)
154
-
155
235
 
156
236
  self.feature_lbl = QLabel("FEATURES")
157
237
  self.feature_lbl.setStyleSheet("""
@@ -164,7 +244,19 @@ class ConfigTracking(QMainWindow, Styles):
164
244
  self.collapse_features_btn.setIcon(icon(MDI6.chevron_down,color="black"))
165
245
  self.collapse_features_btn.setIconSize(QSize(20, 20))
166
246
  self.collapse_features_btn.setStyleSheet(self.button_select_all)
167
- grid.addWidget(self.collapse_features_btn, 0, 0, 1, 4, alignment=Qt.AlignRight)
247
+
248
+ self.help_feature_btn = QPushButton()
249
+ self.help_feature_btn.setIcon(icon(MDI6.help_circle,color=self.help_color))
250
+ self.help_feature_btn.setIconSize(QSize(20, 20))
251
+ self.help_feature_btn.clicked.connect(self.help_feature)
252
+ self.help_feature_btn.setStyleSheet(self.button_select_all)
253
+ self.help_feature_btn.setToolTip("Help.")
254
+
255
+ title_hbox.addWidget(self.select_features_btn, 5)
256
+ title_hbox.addWidget(QLabel(), 85, alignment=Qt.AlignCenter)
257
+ title_hbox.addWidget(self.help_feature_btn, 5)
258
+ title_hbox.addWidget(self.collapse_features_btn, 5)
259
+ grid.addLayout(title_hbox, 0,0,1,4)
168
260
 
169
261
  self.generate_feature_panel_contents()
170
262
  grid.addWidget(self.ContentsFeatures, 1, 0, 1, 4, alignment=Qt.AlignTop)
@@ -179,16 +271,22 @@ class ConfigTracking(QMainWindow, Styles):
179
271
  Switch the chevron icon and adjust the size for the FEATURES frame.
180
272
  """
181
273
 
274
+ features_open = not self.ContentsFeatures.isHidden()
275
+ config_open = not self.ContentsConfig.isHidden()
276
+ post_open = not self.ContentsPostProc.isHidden()
277
+ is_open = np.array([features_open, config_open, post_open])
278
+
182
279
  if self.ContentsFeatures.isHidden():
183
280
  self.collapse_features_btn.setIcon(icon(MDI6.chevron_down,color="black"))
184
281
  self.collapse_features_btn.setIconSize(QSize(20, 20))
185
- self.button_widget.adjustSize()
186
- self.adjustSize()
282
+ if len(is_open[is_open])==0:
283
+ self.scroll_area.setMinimumHeight(int(self.minimum_height))
284
+ self.adjustSize()
187
285
  else:
188
286
  self.collapse_features_btn.setIcon(icon(MDI6.chevron_up,color="black"))
189
287
  self.collapse_features_btn.setIconSize(QSize(20, 20))
190
- self.button_widget.adjustSize()
191
- self.adjustSize()
288
+ self.scroll_area.setMinimumHeight(min(int(930), int(0.9*self.screen_height)))
289
+
192
290
 
193
291
  def generate_post_proc_panel_contents(self):
194
292
 
@@ -273,7 +371,7 @@ class ConfigTracking(QMainWindow, Styles):
273
371
  self.add_feature_btn.setToolTip("Add feature")
274
372
  self.add_feature_btn.setIconSize(QSize(20, 20))
275
373
 
276
- self.features_list = ListWidget(self, FeatureChoice, initial_features=['area','intensity_mean',])
374
+ self.features_list = ListWidget(FeatureChoice, initial_features=['area','intensity_mean',])
277
375
 
278
376
  self.del_feature_btn.clicked.connect(self.features_list.removeSel)
279
377
  self.add_feature_btn.clicked.connect(self.features_list.addItem)
@@ -447,16 +545,22 @@ class ConfigTracking(QMainWindow, Styles):
447
545
  Switch the chevron icon and adjust the size for the CONFIG frame.
448
546
  """
449
547
 
548
+ features_open = not self.ContentsFeatures.isHidden()
549
+ config_open = not self.ContentsConfig.isHidden()
550
+ post_open = not self.ContentsPostProc.isHidden()
551
+ is_open = np.array([features_open, config_open, post_open])
552
+
450
553
  if self.ContentsConfig.isHidden():
451
554
  self.collapse_config_btn.setIcon(icon(MDI6.chevron_down,color="black"))
452
555
  self.collapse_config_btn.setIconSize(QSize(20, 20))
453
- self.button_widget.adjustSize()
454
- self.adjustSize()
556
+ if len(is_open[is_open])==0:
557
+ self.scroll_area.setMinimumHeight(int(self.minimum_height))
558
+ self.adjustSize()
455
559
  else:
456
560
  self.collapse_config_btn.setIcon(icon(MDI6.chevron_up,color="black"))
457
561
  self.collapse_config_btn.setIconSize(QSize(20, 20))
458
- self.button_widget.adjustSize()
459
- self.adjustSize()
562
+ self.scroll_area.setMinimumHeight(min(int(930), int(0.9*self.screen_height)))
563
+
460
564
 
461
565
  def generate_config_panel_contents(self):
462
566
 
@@ -884,7 +988,8 @@ class ConfigTracking(QMainWindow, Styles):
884
988
  self.fig, self.ax = plt.subplots(1,1,figsize=(4,3))
885
989
  self.hist_window = FigureCanvas(self.fig, title="Haralick: control digitized histogram")
886
990
  self.ax.clear()
887
- self.ax.hist(norm_img.flatten(), bins=self.haralick_options['n_intensity_bins'])
991
+ flat = norm_img.flatten()
992
+ self.ax.hist(flat[flat==flat], bins=self.haralick_options['n_intensity_bins'])
888
993
  self.ax.set_xlabel('gray level value')
889
994
  self.ax.set_ylabel('#')
890
995
  plt.tight_layout()