celldetective 1.3.3.post1__tar.gz → 1.3.4__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 (116) hide show
  1. {celldetective-1.3.3.post1 → celldetective-1.3.4}/PKG-INFO +2 -1
  2. celldetective-1.3.4/celldetective/__main__.py +66 -0
  3. celldetective-1.3.4/celldetective/_version.py +1 -0
  4. {celldetective-1.3.3.post1 → celldetective-1.3.4}/celldetective/extra_properties.py +21 -0
  5. {celldetective-1.3.3.post1 → celldetective-1.3.4}/celldetective/filters.py +15 -2
  6. {celldetective-1.3.3.post1 → celldetective-1.3.4}/celldetective/gui/InitWindow.py +28 -34
  7. celldetective-1.3.4/celldetective/gui/analyze_block.py +81 -0
  8. {celldetective-1.3.3.post1 → celldetective-1.3.4}/celldetective/gui/classifier_widget.py +1 -1
  9. {celldetective-1.3.3.post1 → celldetective-1.3.4}/celldetective/gui/control_panel.py +98 -27
  10. {celldetective-1.3.3.post1 → celldetective-1.3.4}/celldetective/gui/generic_signal_plot.py +35 -18
  11. {celldetective-1.3.3.post1 → celldetective-1.3.4}/celldetective/gui/gui_utils.py +143 -2
  12. {celldetective-1.3.3.post1 → celldetective-1.3.4}/celldetective/gui/layouts.py +7 -6
  13. {celldetective-1.3.3.post1 → celldetective-1.3.4}/celldetective/gui/measurement_options.py +3 -11
  14. {celldetective-1.3.3.post1 → celldetective-1.3.4}/celldetective/gui/plot_measurements.py +5 -13
  15. {celldetective-1.3.3.post1 → celldetective-1.3.4}/celldetective/gui/plot_signals_ui.py +30 -30
  16. {celldetective-1.3.3.post1 → celldetective-1.3.4}/celldetective/gui/process_block.py +61 -103
  17. {celldetective-1.3.3.post1 → celldetective-1.3.4}/celldetective/gui/signal_annotator.py +50 -32
  18. {celldetective-1.3.3.post1 → celldetective-1.3.4}/celldetective/gui/signal_annotator2.py +7 -4
  19. {celldetective-1.3.3.post1 → celldetective-1.3.4}/celldetective/gui/styles.py +13 -0
  20. {celldetective-1.3.3.post1 → celldetective-1.3.4}/celldetective/gui/survival_ui.py +8 -21
  21. {celldetective-1.3.3.post1 → celldetective-1.3.4}/celldetective/gui/tableUI.py +1 -2
  22. {celldetective-1.3.3.post1 → celldetective-1.3.4}/celldetective/gui/thresholds_gui.py +0 -6
  23. {celldetective-1.3.3.post1 → celldetective-1.3.4}/celldetective/gui/viewers.py +1 -5
  24. {celldetective-1.3.3.post1 → celldetective-1.3.4}/celldetective/io.py +31 -4
  25. {celldetective-1.3.3.post1 → celldetective-1.3.4}/celldetective/measure.py +8 -5
  26. {celldetective-1.3.3.post1 → celldetective-1.3.4}/celldetective/neighborhood.py +0 -2
  27. {celldetective-1.3.3.post1 → celldetective-1.3.4}/celldetective/scripts/measure_cells.py +21 -9
  28. {celldetective-1.3.3.post1 → celldetective-1.3.4}/celldetective/signals.py +77 -66
  29. {celldetective-1.3.3.post1 → celldetective-1.3.4}/celldetective/tracking.py +19 -13
  30. {celldetective-1.3.3.post1 → celldetective-1.3.4}/celldetective.egg-info/PKG-INFO +2 -1
  31. {celldetective-1.3.3.post1 → celldetective-1.3.4}/celldetective.egg-info/requires.txt +1 -0
  32. {celldetective-1.3.3.post1 → celldetective-1.3.4}/tests/test_qt.py +5 -3
  33. celldetective-1.3.3.post1/celldetective/__main__.py +0 -40
  34. celldetective-1.3.3.post1/celldetective/_version.py +0 -1
  35. celldetective-1.3.3.post1/celldetective/gui/analyze_block.py +0 -576
  36. {celldetective-1.3.3.post1 → celldetective-1.3.4}/LICENSE +0 -0
  37. {celldetective-1.3.3.post1 → celldetective-1.3.4}/README.md +0 -0
  38. {celldetective-1.3.3.post1 → celldetective-1.3.4}/celldetective/__init__.py +0 -0
  39. {celldetective-1.3.3.post1 → celldetective-1.3.4}/celldetective/datasets/segmentation_annotations/blank +0 -0
  40. {celldetective-1.3.3.post1 → celldetective-1.3.4}/celldetective/datasets/signal_annotations/blank +0 -0
  41. {celldetective-1.3.3.post1 → celldetective-1.3.4}/celldetective/events.py +0 -0
  42. {celldetective-1.3.3.post1 → celldetective-1.3.4}/celldetective/gui/__init__.py +0 -0
  43. {celldetective-1.3.3.post1 → celldetective-1.3.4}/celldetective/gui/about.py +0 -0
  44. {celldetective-1.3.3.post1 → celldetective-1.3.4}/celldetective/gui/btrack_options.py +0 -0
  45. {celldetective-1.3.3.post1 → celldetective-1.3.4}/celldetective/gui/configure_new_exp.py +0 -0
  46. {celldetective-1.3.3.post1 → celldetective-1.3.4}/celldetective/gui/help/DL-segmentation-strategy.json +0 -0
  47. {celldetective-1.3.3.post1 → celldetective-1.3.4}/celldetective/gui/help/Threshold-vs-DL.json +0 -0
  48. {celldetective-1.3.3.post1 → celldetective-1.3.4}/celldetective/gui/help/cell-populations.json +0 -0
  49. {celldetective-1.3.3.post1 → celldetective-1.3.4}/celldetective/gui/help/exp-structure.json +0 -0
  50. {celldetective-1.3.3.post1 → celldetective-1.3.4}/celldetective/gui/help/feature-btrack.json +0 -0
  51. {celldetective-1.3.3.post1 → celldetective-1.3.4}/celldetective/gui/help/neighborhood.json +0 -0
  52. {celldetective-1.3.3.post1 → celldetective-1.3.4}/celldetective/gui/help/prefilter-for-segmentation.json +0 -0
  53. {celldetective-1.3.3.post1 → celldetective-1.3.4}/celldetective/gui/help/preprocessing.json +0 -0
  54. {celldetective-1.3.3.post1 → celldetective-1.3.4}/celldetective/gui/help/propagate-classification.json +0 -0
  55. {celldetective-1.3.3.post1 → celldetective-1.3.4}/celldetective/gui/help/track-postprocessing.json +0 -0
  56. {celldetective-1.3.3.post1 → celldetective-1.3.4}/celldetective/gui/help/tracking.json +0 -0
  57. {celldetective-1.3.3.post1 → celldetective-1.3.4}/celldetective/gui/json_readers.py +0 -0
  58. {celldetective-1.3.3.post1 → celldetective-1.3.4}/celldetective/gui/neighborhood_options.py +0 -0
  59. {celldetective-1.3.3.post1 → celldetective-1.3.4}/celldetective/gui/retrain_segmentation_model_options.py +0 -0
  60. {celldetective-1.3.3.post1 → celldetective-1.3.4}/celldetective/gui/retrain_signal_model_options.py +0 -0
  61. {celldetective-1.3.3.post1 → celldetective-1.3.4}/celldetective/gui/seg_model_loader.py +0 -0
  62. {celldetective-1.3.3.post1 → celldetective-1.3.4}/celldetective/gui/signal_annotator_options.py +0 -0
  63. {celldetective-1.3.3.post1 → celldetective-1.3.4}/celldetective/icons/logo-large.png +0 -0
  64. {celldetective-1.3.3.post1 → celldetective-1.3.4}/celldetective/icons/logo.png +0 -0
  65. {celldetective-1.3.3.post1 → celldetective-1.3.4}/celldetective/icons/signals_icon.png +0 -0
  66. {celldetective-1.3.3.post1 → celldetective-1.3.4}/celldetective/icons/splash-test.png +0 -0
  67. {celldetective-1.3.3.post1 → celldetective-1.3.4}/celldetective/icons/splash.png +0 -0
  68. {celldetective-1.3.3.post1 → celldetective-1.3.4}/celldetective/icons/splash0.png +0 -0
  69. {celldetective-1.3.3.post1 → celldetective-1.3.4}/celldetective/icons/survival2.png +0 -0
  70. {celldetective-1.3.3.post1 → celldetective-1.3.4}/celldetective/icons/vignette_signals2.png +0 -0
  71. {celldetective-1.3.3.post1 → celldetective-1.3.4}/celldetective/icons/vignette_signals2.svg +0 -0
  72. {celldetective-1.3.3.post1 → celldetective-1.3.4}/celldetective/links/zenodo.json +0 -0
  73. {celldetective-1.3.3.post1 → celldetective-1.3.4}/celldetective/models/pair_signal_detection/blank +0 -0
  74. {celldetective-1.3.3.post1 → celldetective-1.3.4}/celldetective/models/segmentation_effectors/blank +0 -0
  75. {celldetective-1.3.3.post1 → celldetective-1.3.4}/celldetective/models/segmentation_effectors/ricm_bf_all_last/config_input.json +0 -0
  76. {celldetective-1.3.3.post1 → celldetective-1.3.4}/celldetective/models/segmentation_effectors/ricm_bf_all_last/ricm_bf_all_last +0 -0
  77. {celldetective-1.3.3.post1 → celldetective-1.3.4}/celldetective/models/segmentation_effectors/ricm_bf_all_last/training_instructions.json +0 -0
  78. {celldetective-1.3.3.post1 → celldetective-1.3.4}/celldetective/models/segmentation_effectors/test-transfer/config_input.json +0 -0
  79. {celldetective-1.3.3.post1 → celldetective-1.3.4}/celldetective/models/segmentation_effectors/test-transfer/test-transfer +0 -0
  80. {celldetective-1.3.3.post1 → celldetective-1.3.4}/celldetective/models/segmentation_generic/blank +0 -0
  81. {celldetective-1.3.3.post1 → celldetective-1.3.4}/celldetective/models/segmentation_targets/blank +0 -0
  82. {celldetective-1.3.3.post1 → celldetective-1.3.4}/celldetective/models/signal_detection/blank +0 -0
  83. {celldetective-1.3.3.post1 → celldetective-1.3.4}/celldetective/models/tracking_configs/biased_motion.json +0 -0
  84. {celldetective-1.3.3.post1 → celldetective-1.3.4}/celldetective/models/tracking_configs/mcf7.json +0 -0
  85. {celldetective-1.3.3.post1 → celldetective-1.3.4}/celldetective/models/tracking_configs/no_z_motion.json +0 -0
  86. {celldetective-1.3.3.post1 → celldetective-1.3.4}/celldetective/models/tracking_configs/ricm.json +0 -0
  87. {celldetective-1.3.3.post1 → celldetective-1.3.4}/celldetective/models/tracking_configs/ricm2.json +0 -0
  88. {celldetective-1.3.3.post1 → celldetective-1.3.4}/celldetective/preprocessing.py +0 -0
  89. {celldetective-1.3.3.post1 → celldetective-1.3.4}/celldetective/relative_measurements.py +0 -0
  90. {celldetective-1.3.3.post1 → celldetective-1.3.4}/celldetective/scripts/analyze_signals.py +0 -0
  91. {celldetective-1.3.3.post1 → celldetective-1.3.4}/celldetective/scripts/measure_relative.py +0 -0
  92. {celldetective-1.3.3.post1 → celldetective-1.3.4}/celldetective/scripts/segment_cells.py +0 -0
  93. {celldetective-1.3.3.post1 → celldetective-1.3.4}/celldetective/scripts/segment_cells_thresholds.py +0 -0
  94. {celldetective-1.3.3.post1 → celldetective-1.3.4}/celldetective/scripts/track_cells.py +0 -0
  95. {celldetective-1.3.3.post1 → celldetective-1.3.4}/celldetective/scripts/train_segmentation_model.py +0 -0
  96. {celldetective-1.3.3.post1 → celldetective-1.3.4}/celldetective/scripts/train_signal_model.py +0 -0
  97. {celldetective-1.3.3.post1 → celldetective-1.3.4}/celldetective/segmentation.py +0 -0
  98. {celldetective-1.3.3.post1 → celldetective-1.3.4}/celldetective/utils.py +0 -0
  99. {celldetective-1.3.3.post1 → celldetective-1.3.4}/celldetective.egg-info/SOURCES.txt +0 -0
  100. {celldetective-1.3.3.post1 → celldetective-1.3.4}/celldetective.egg-info/dependency_links.txt +0 -0
  101. {celldetective-1.3.3.post1 → celldetective-1.3.4}/celldetective.egg-info/entry_points.txt +0 -0
  102. {celldetective-1.3.3.post1 → celldetective-1.3.4}/celldetective.egg-info/not-zip-safe +0 -0
  103. {celldetective-1.3.3.post1 → celldetective-1.3.4}/celldetective.egg-info/top_level.txt +0 -0
  104. {celldetective-1.3.3.post1 → celldetective-1.3.4}/setup.cfg +0 -0
  105. {celldetective-1.3.3.post1 → celldetective-1.3.4}/setup.py +0 -0
  106. {celldetective-1.3.3.post1 → celldetective-1.3.4}/tests/__init__.py +0 -0
  107. {celldetective-1.3.3.post1 → celldetective-1.3.4}/tests/test_events.py +0 -0
  108. {celldetective-1.3.3.post1 → celldetective-1.3.4}/tests/test_filters.py +0 -0
  109. {celldetective-1.3.3.post1 → celldetective-1.3.4}/tests/test_io.py +0 -0
  110. {celldetective-1.3.3.post1 → celldetective-1.3.4}/tests/test_measure.py +0 -0
  111. {celldetective-1.3.3.post1 → celldetective-1.3.4}/tests/test_neighborhood.py +0 -0
  112. {celldetective-1.3.3.post1 → celldetective-1.3.4}/tests/test_preprocessing.py +0 -0
  113. {celldetective-1.3.3.post1 → celldetective-1.3.4}/tests/test_segmentation.py +0 -0
  114. {celldetective-1.3.3.post1 → celldetective-1.3.4}/tests/test_signals.py +0 -0
  115. {celldetective-1.3.3.post1 → celldetective-1.3.4}/tests/test_tracking.py +0 -0
  116. {celldetective-1.3.3.post1 → celldetective-1.3.4}/tests/test_utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: celldetective
3
- Version: 1.3.3.post1
3
+ Version: 1.3.4
4
4
  Summary: description
5
5
  Home-page: http://github.com/remyeltorro/celldetective
6
6
  Author: Rémy Torro
@@ -41,6 +41,7 @@ Requires-Dist: pytest
41
41
  Requires-Dist: pytest-qt
42
42
  Requires-Dist: h5py
43
43
  Requires-Dist: cliffs_delta
44
+ Requires-Dist: requests
44
45
 
45
46
  # Celldetective
46
47
 
@@ -0,0 +1,66 @@
1
+ #!/usr/bin/env python3
2
+ import sys
3
+ from PyQt5.QtWidgets import QApplication, QSplashScreen
4
+ from PyQt5.QtGui import QPixmap
5
+ from os import sep
6
+ from celldetective.utils import get_software_location
7
+ from time import time, sleep
8
+
9
+ #os.environ['QT_DEBUG_PLUGINS'] = '1'
10
+
11
+ if __name__ == "__main__":
12
+
13
+ splash=True
14
+ print('Loading the libraries...')
15
+
16
+ App = QApplication(sys.argv)
17
+ App.setStyle("Fusion")
18
+
19
+ software_location = get_software_location()
20
+
21
+ if splash:
22
+ start = time()
23
+ splash_pix = QPixmap(sep.join([software_location,'celldetective','icons','splash.png']))
24
+ splash = QSplashScreen(splash_pix)
25
+ splash.setMask(splash_pix.mask())
26
+ splash.show()
27
+ #App.processEvents(QEventLoop.AllEvents, 300)
28
+ while time() - start < 1:
29
+ sleep(0.001)
30
+ App.processEvents()
31
+
32
+ try:
33
+
34
+ import requests
35
+ import re
36
+ from celldetective import __version__
37
+
38
+ package = 'celldetective'
39
+ response = requests.get(f'https://pypi.org/pypi/{package}/json')
40
+ latest_version = response.json()['info']['version']
41
+
42
+ latest_version_num = re.sub('[^0-9]','', latest_version)
43
+ current_version_num = re.sub('[^0-9]','',__version__)
44
+
45
+ if len(latest_version_num)!=len(current_version_num):
46
+ max_length = max([len(latest_version_num),len(current_version_num)])
47
+ latest_version_num = int(latest_version_num.zfill(max_length - len(latest_version_num)))
48
+ current_version_num = int(current_version_num.zfill(max_length - len(current_version_num)))
49
+
50
+ if latest_version_num > current_version_num:
51
+ print('Update is available...\nPlease update using `pip install --upgrade celldetective`...')
52
+
53
+ except Exception as e:
54
+
55
+ print(f"{e=}")
56
+
57
+ from celldetective.gui.InitWindow import AppInitWindow
58
+
59
+ print('Libraries successfully loaded...')
60
+
61
+ window = AppInitWindow(App, software_location=software_location)
62
+
63
+ if splash:
64
+ splash.finish(window)
65
+
66
+ sys.exit(App.exec())
@@ -0,0 +1 @@
1
+ __version__ = "1.3.4"
@@ -29,6 +29,27 @@ from celldetective.utils import interpolate_nan, contour_of_instance_segmentatio
29
29
 
30
30
  # Percentiles
31
31
 
32
+ def custom_area(regionmask):
33
+ return np.sum(regionmask)
34
+
35
+ def intensity_area_under_one(regionmask, intensity_image):
36
+
37
+ subregion = regionmask[intensity_image<1]
38
+ if len(subregion)>0:
39
+ return np.sum(subregion)
40
+ else:
41
+ return 0.0
42
+
43
+ def intensity_fraction_of_area_under_one(regionmask, intensity_image):
44
+
45
+ subregion = regionmask[intensity_image<1]
46
+ area = np.sum(regionmask)
47
+
48
+ if len(subregion) > 0:
49
+ return float(np.sum(subregion)) / float(area)
50
+ else:
51
+ return 0.0
52
+
32
53
  def intensity_percentile_ninety_nine(regionmask, intensity_image):
33
54
  return np.nanpercentile(intensity_image[regionmask],99)
34
55
 
@@ -4,15 +4,19 @@ import scipy.ndimage as snd
4
4
  import numpy as np
5
5
 
6
6
  def gauss_filter(img, sigma, interpolate=True, *kwargs):
7
+
7
8
  if interpolate:
8
9
  img = interpolate_nan(img.astype(float))
10
+
9
11
  return snd.gaussian_filter(img.astype(float), sigma, *kwargs)
10
12
 
11
13
  def median_filter(img, size, interpolate=True, *kwargs):
14
+
12
15
  if interpolate:
13
16
  img = interpolate_nan(img.astype(float))
14
17
 
15
18
  size = int(size)
19
+
16
20
  return snd.median_filter(img, size, *kwargs)
17
21
 
18
22
  def maximum_filter(img, size, interpolate=True, *kwargs):
@@ -65,13 +69,17 @@ def std_filter(img, size, interpolate=True):
65
69
 
66
70
  if interpolate:
67
71
  img = interpolate_nan(img.astype(float))
72
+
68
73
  size = int(size)
69
74
  img = img.astype(float)
75
+
70
76
  win_mean = snd.uniform_filter(img, (size,size), mode='wrap')
71
77
  win_sqr_mean = snd.uniform_filter(img**2, (size, size), mode='wrap')
72
- win_sqr_mean[win_sqr_mean!=win_sqr_mean] = 0.
73
78
  win_sqr_mean[win_sqr_mean<=0.] = 0. # add this to prevent sqrt from breaking
74
- img = np.sqrt(win_sqr_mean - win_mean**2)
79
+
80
+ sub = np.subtract(win_sqr_mean,win_mean**2)
81
+ sub[sub<=0.] = 0.
82
+ img = np.sqrt(sub)
75
83
 
76
84
  return img
77
85
 
@@ -96,16 +104,21 @@ def local_filter(img, *kwargs):
96
104
  return binary.astype(float)
97
105
 
98
106
  def niblack_filter(img, *kwargs):
107
+
99
108
  thresh = threshold_niblack(img, *kwargs)
100
109
  binary = img >= thresh
101
110
  return binary.astype(float)
102
111
 
103
112
  def sauvola_filter(img, *kwargs):
113
+
104
114
  thresh = threshold_sauvola(img, *kwargs)
105
115
  binary = img >= thresh
106
116
  return binary.astype(float)
107
117
 
108
118
  def log_filter(img, sigma, *kwargs):
119
+
120
+ if interpolate:
121
+ img = interpolate_nan(img.astype(float))
109
122
  return snd.gaussian_laplace(img.astype(float), sigma, *kwargs)
110
123
 
111
124
  def tophat_filter(img, size, connectivity=4, interpolate=True, *kwargs):
@@ -1,48 +1,49 @@
1
- from PyQt5.QtWidgets import QApplication, QMainWindow
2
- from celldetective.utils import get_software_location, download_zenodo_file
3
1
  import os
2
+
3
+ from PyQt5.QtWidgets import QApplication, QMainWindow
4
4
  from PyQt5.QtWidgets import QFileDialog, QWidget, QVBoxLayout, QCheckBox, QHBoxLayout, QLabel, QLineEdit, QPushButton, QMessageBox, QMenu, QAction
5
5
  from PyQt5.QtCore import Qt, QUrl
6
6
  from PyQt5.QtGui import QIcon, QDesktopServices, QIntValidator
7
+
7
8
  from glob import glob
8
9
  from superqt.fonticon import icon
9
10
  from fonticon_mdi6 import MDI6
10
- import gc
11
- from celldetective.gui import Styles, ControlPanel, ConfigNewExperiment
12
- from celldetective.gui.gui_utils import center_window
13
- import subprocess
14
- import os
11
+
15
12
  from celldetective.gui.about import AboutWidget
16
13
  from celldetective.io import correct_annotation
17
- import psutil
18
- import subprocess
14
+ from celldetective.utils import download_zenodo_file
15
+ from celldetective.gui.gui_utils import center_window
16
+ from celldetective.gui import Styles, ControlPanel, ConfigNewExperiment
17
+
18
+ import gc
19
+ from subprocess import check_output, Popen
20
+ from psutil import cpu_count
19
21
  import json
20
22
 
21
- class AppInitWindow(QMainWindow):
23
+ class AppInitWindow(QMainWindow, Styles):
22
24
 
23
25
  """
24
26
  Initial window to set the experiment folder or create a new one.
25
27
  """
26
28
 
27
- def __init__(self, parent_window=None):
29
+ def __init__(self, parent_window=None, software_location=None):
30
+
28
31
  super().__init__()
29
32
 
30
33
  self.parent_window = parent_window
31
- self.Styles = Styles()
32
- self.init_styles()
33
34
  self.setWindowTitle("celldetective")
34
35
 
35
- self.n_threads = min([1,psutil.cpu_count()])
36
+ self.n_threads = min([1,cpu_count()])
36
37
 
37
38
  try:
38
- subprocess.check_output('nvidia-smi')
39
+ check_output('nvidia-smi')
39
40
  print('NVIDIA GPU detected (activate or disable in Memory & Threads)...')
40
41
  self.use_gpu = True
41
42
  except Exception: # this command not being found can raise quite a few different errors depending on the configuration
42
43
  print('No NVIDIA GPU detected...')
43
44
  self.use_gpu = False
44
-
45
- self.soft_path = get_software_location()
45
+
46
+ self.soft_path = software_location
46
47
  self.onlyInt = QIntValidator()
47
48
  self.setWindowIcon(QIcon(os.sep.join([self.soft_path,'celldetective','icons','logo.png'])))
48
49
  center_window(self)
@@ -65,6 +66,7 @@ class AppInitWindow(QMainWindow):
65
66
  self.show()
66
67
 
67
68
  def closeEvent(self, event):
69
+
68
70
  QApplication.closeAllWindows()
69
71
  event.accept()
70
72
  gc.collect()
@@ -188,6 +190,9 @@ class AppInitWindow(QMainWindow):
188
190
  def download_spreading_assay_demo(self):
189
191
 
190
192
  self.target_dir = str(QFileDialog.getExistingDirectory(self, 'Select Folder for Download'))
193
+ if self.target_dir=='':
194
+ return None
195
+
191
196
  if not os.path.exists(os.sep.join([self.target_dir,'demo_ricm'])):
192
197
  download_zenodo_file('demo_ricm', self.target_dir)
193
198
  self.experiment_path_selection.setText(os.sep.join([self.target_dir, 'demo_ricm']))
@@ -196,6 +201,9 @@ class AppInitWindow(QMainWindow):
196
201
  def download_cytotoxicity_assay_demo(self):
197
202
 
198
203
  self.target_dir = str(QFileDialog.getExistingDirectory(self, 'Select Folder for Download'))
204
+ if self.target_dir=='':
205
+ return None
206
+
199
207
  if not os.path.exists(os.sep.join([self.target_dir,'demo_adcc'])):
200
208
  download_zenodo_file('demo_adcc', self.target_dir)
201
209
  self.experiment_path_selection.setText(os.sep.join([self.target_dir, 'demo_adcc']))
@@ -302,9 +310,10 @@ class AppInitWindow(QMainWindow):
302
310
  QDesktopServices.openUrl(doc_url)
303
311
 
304
312
  def open_models_folder(self):
313
+
305
314
  path = os.sep.join([self.soft_path,'celldetective','models',os.sep])
306
315
  try:
307
- subprocess.Popen(f'explorer {os.path.realpath(path)}')
316
+ Popen(f'explorer {os.path.realpath(path)}')
308
317
  except:
309
318
 
310
319
  try:
@@ -312,9 +321,6 @@ class AppInitWindow(QMainWindow):
312
321
  except:
313
322
  return None
314
323
 
315
-
316
- #os.system(f'start {os.path.realpath(path)}')
317
-
318
324
  def create_buttons_hbox(self):
319
325
 
320
326
  self.buttons_layout = QHBoxLayout()
@@ -344,18 +350,6 @@ class AppInitWindow(QMainWindow):
344
350
  else:
345
351
  self.validate_button.setEnabled(False)
346
352
 
347
- def init_styles(self):
348
-
349
- """
350
- Initialize styles.
351
- """
352
-
353
- self.qtab_style = self.Styles.qtab_style
354
- self.button_style_sheet = self.Styles.button_style_sheet
355
- self.button_style_sheet_2 = self.Styles.button_style_sheet_2
356
- self.button_style_sheet_2_not_done = self.Styles.button_style_sheet_2_not_done
357
- self.button_style_sheet_3 = self.Styles.button_style_sheet_3
358
- self.button_select_all = self.Styles.button_select_all
359
353
 
360
354
  def set_experiment_path(self, path):
361
355
  self.experiment_path_selection.setText(path)
@@ -414,7 +408,7 @@ class AppInitWindow(QMainWindow):
414
408
  self.experiment_path_selection.setText(self.foldername)
415
409
  else:
416
410
  return None
417
- if not os.path.exists(self.foldername+"/config.ini"):
411
+ if not os.path.exists(os.sep.join([self.foldername,"config.ini"])):
418
412
  msgBox = QMessageBox()
419
413
  msgBox.setIcon(QMessageBox.Warning)
420
414
  msgBox.setText("No configuration can be found in the selected folder...")
@@ -0,0 +1,81 @@
1
+ from PyQt5.QtWidgets import QFrame, QLabel, QPushButton, QVBoxLayout, \
2
+ QSpacerItem, QSizePolicy
3
+ from PyQt5.QtCore import Qt, QSize
4
+ from PyQt5.QtGui import QIcon
5
+ from celldetective.gui.plot_measurements import ConfigMeasurementsPlot
6
+ from celldetective.gui import ConfigSurvival, ConfigSignalPlot
7
+ import os
8
+ from celldetective.gui import Styles
9
+
10
+ class AnalysisPanel(QFrame, Styles):
11
+ def __init__(self, parent_window, title=None):
12
+
13
+ super().__init__()
14
+ self.parent_window = parent_window
15
+ self.title = title
16
+ if self.title is None:
17
+ self.title=''
18
+ self.exp_channels = self.parent_window.exp_channels
19
+ self.exp_dir = self.parent_window.exp_dir
20
+ self.soft_path = self.parent_window.parent_window.soft_path
21
+
22
+ self.setFrameStyle(QFrame.StyledPanel | QFrame.Raised)
23
+ self.grid = QVBoxLayout(self)
24
+ self.grid.setSpacing(20)
25
+ self.generate_header()
26
+
27
+ def generate_header(self):
28
+
29
+ """
30
+ Read the mode and prepare a collapsable block to process a specific cell population.
31
+
32
+ """
33
+
34
+ panel_title = QLabel("Survival")
35
+ panel_title.setStyleSheet("""
36
+ font-weight: bold;
37
+ padding: 0px;
38
+ """)
39
+
40
+ self.grid.addWidget(panel_title, alignment=Qt.AlignCenter)
41
+
42
+ self.survival_btn = QPushButton("plot survival")
43
+ self.survival_btn.setIcon(QIcon(QIcon(os.sep.join([self.soft_path,'celldetective','icons','survival2.png']))))
44
+ self.survival_btn.setStyleSheet(self.button_style_sheet_2)
45
+ self.survival_btn.setIconSize(QSize(35, 35))
46
+ self.survival_btn.clicked.connect(self.configure_survival)
47
+ self.grid.addWidget(self.survival_btn)
48
+
49
+ signal_lbl = QLabel("Single-cell signals")
50
+ signal_lbl.setStyleSheet("""
51
+ font-weight: bold;
52
+ padding: 0px;
53
+ """)
54
+
55
+ self.grid.addWidget(signal_lbl, alignment=Qt.AlignCenter)
56
+
57
+ self.plot_signal_btn = QPushButton("plot signals")
58
+ self.plot_signal_btn.setIcon(QIcon(QIcon(os.sep.join([self.soft_path,'celldetective','icons','signals_icon.png']))))
59
+ self.plot_signal_btn.setStyleSheet(self.button_style_sheet_2)
60
+ self.plot_signal_btn.setIconSize(QSize(35, 35))
61
+ self.plot_signal_btn.clicked.connect(self.configure_plot_signals)
62
+ self.grid.addWidget(self.plot_signal_btn)
63
+
64
+ verticalSpacer = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding)
65
+ self.grid.addItem(verticalSpacer)
66
+
67
+ def configure_survival(self):
68
+ print('survival analysis starting!!!')
69
+ self.configSurvival = ConfigSurvival(self)
70
+ self.configSurvival.show()
71
+
72
+ def configure_plot_signals(self):
73
+ print('Configure a signal collapse representation...')
74
+ self.ConfigSignalPlot = ConfigSignalPlot(self)
75
+ self.ConfigSignalPlot.show()
76
+
77
+ def configure_plot_measurements(self):
78
+
79
+ print('plot measurements analysis starting!!!')
80
+ self.ConfigMeasurementsPlot_wg = ConfigMeasurementsPlot(self)
81
+ self.ConfigMeasurementsPlot_wg.show()
@@ -10,7 +10,7 @@ import numpy as np
10
10
  import matplotlib.pyplot as plt
11
11
  import json
12
12
 
13
- from celldetective.gui.gui_utils import FigureCanvas, center_window, color_from_status, help_generic, color_from_class
13
+ from celldetective.gui.gui_utils import FigureCanvas, center_window, color_from_status, help_generic
14
14
  from celldetective.gui import Styles
15
15
  from celldetective.utils import get_software_location
16
16
  from celldetective.measure import classify_cells_from_query, interpret_track_classification
@@ -1,7 +1,7 @@
1
- from PyQt5.QtWidgets import QMainWindow, QComboBox, QPushButton, QHBoxLayout, QLabel, QWidget, QGridLayout, QFrame, \
1
+ from PyQt5.QtWidgets import QMainWindow, QPushButton, QHBoxLayout, QLabel, QWidget, QGridLayout, QFrame, \
2
2
  QTabWidget, QVBoxLayout, QMessageBox, QScrollArea, QDesktopWidget
3
3
  from PyQt5.QtCore import Qt, QSize
4
- from celldetective.gui.gui_utils import center_window, QHSeperationLine
4
+ from celldetective.gui.gui_utils import center_window, QHSeperationLine, QCheckableComboBox
5
5
  from celldetective.utils import _extract_labels_from_config, ConfigSectionMap, extract_experiment_channels, extract_identity_col
6
6
  from celldetective.gui import ConfigEditor, ProcessPanel, PreprocessingPanel, AnalysisPanel, NeighPanel
7
7
  from celldetective.io import get_experiment_wells, get_config, get_spatial_calibration, get_temporal_calibration, get_experiment_concentrations, get_experiment_cell_types, get_experiment_antibodies, get_experiment_pharmaceutical_agents
@@ -18,6 +18,7 @@ from celldetective.utils import extract_experiment_channels
18
18
  from celldetective.gui import Styles
19
19
  import pandas as pd
20
20
 
21
+
21
22
  class ControlPanel(QMainWindow, Styles):
22
23
 
23
24
  def __init__(self, parent_window=None, exp_dir=""):
@@ -90,7 +91,7 @@ class ControlPanel(QMainWindow, Styles):
90
91
  self.initial_width = self.size().width()
91
92
  self.screen_height = desktop.screenGeometry().height()
92
93
  self.screen_width = desktop.screenGeometry().width()
93
- self.scroll.setMinimumWidth(425)
94
+ self.scroll.setMinimumWidth(440)
94
95
 
95
96
  def init_wells_and_positions(self):
96
97
 
@@ -138,23 +139,23 @@ class ControlPanel(QMainWindow, Styles):
138
139
  self.edit_config_button.clicked.connect(self.open_config_editor)
139
140
  self.edit_config_button.setStyleSheet(self.button_select_all)
140
141
 
141
- self.well_list = QComboBox()
142
+ self.well_list = QCheckableComboBox(obj='well', parent_window=self)
142
143
  thresh = 32
143
- self.well_truncated = [w[:thresh - 3]+'...' if len(w)>thresh else w for w in self.well_labels]
144
- self.well_list.addItems(self.well_truncated) #self.well_labels
145
- for i in range(len(self.well_labels)):
146
- self.well_list.setItemData(i, self.well_labels[i], Qt.ToolTipRole)
147
- self.well_list.addItems(["*"])
148
- self.well_list.activated.connect(self.display_positions)
149
- self.to_disable.append(self.well_list)
144
+ self.well_truncated = [w[:thresh - 3]+'...' if len(w)>thresh else w for w in self.well_labels]
145
+ for i in range(len(self.well_truncated)):
146
+ self.well_list.addItem(self.well_truncated[i], tooltip=self.well_labels[i])
150
147
 
151
- self.position_list = QComboBox()
152
- self.position_list.addItems(["*"])
148
+ self.position_list = QCheckableComboBox(obj='position', parent_window=self)
153
149
  self.position_list.addItems(self.positions[0])
154
- self.position_list.activated.connect(self.update_position_options)
155
150
  self.to_disable.append(self.position_list)
156
151
  #self.locate_selected_position()
157
152
 
153
+ self.well_list.activated.connect(self.display_positions)
154
+ self.well_list.setCurrentIndex(0)
155
+
156
+ self.position_list.activated.connect(self.update_position_options)
157
+ self.position_list.setCurrentIndex(0)
158
+
158
159
  self.view_stack_btn = QPushButton()
159
160
  self.view_stack_btn.setStyleSheet(self.button_select_all)
160
161
  self.view_stack_btn.setIcon(icon(MDI6.image_check, color="black"))
@@ -163,6 +164,24 @@ class ControlPanel(QMainWindow, Styles):
163
164
  self.view_stack_btn.clicked.connect(self.view_current_stack)
164
165
  self.view_stack_btn.setEnabled(False)
165
166
 
167
+ self.select_all_wells_btn = QPushButton()
168
+ self.select_all_wells_btn.setIcon(icon(MDI6.select_all,color="black"))
169
+ self.select_all_wells_btn.setIconSize(QSize(20, 20))
170
+ self.select_all_wells_btn.setToolTip("Select all wells.")
171
+ self.select_all_wells_btn.clicked.connect(self.select_all_wells)
172
+ self.select_all_wells_btn.setStyleSheet(self.button_select_all)
173
+ self.select_all_wells_option = False
174
+
175
+
176
+ self.select_all_pos_btn = QPushButton()
177
+ self.select_all_pos_btn.setIcon(icon(MDI6.select_all,color="black"))
178
+ self.select_all_pos_btn.setIconSize(QSize(20, 20))
179
+ self.select_all_pos_btn.setToolTip("Select all positions.")
180
+ self.select_all_pos_btn.clicked.connect(self.select_all_positions)
181
+ self.select_all_pos_btn.setStyleSheet(self.button_select_all)
182
+ self.select_all_pos_option = False
183
+
184
+
166
185
  well_lbl = QLabel('Well: ')
167
186
  well_lbl.setAlignment(Qt.AlignRight)
168
187
 
@@ -196,20 +215,52 @@ class ControlPanel(QMainWindow, Styles):
196
215
  # Well row
197
216
  well_hbox = QHBoxLayout()
198
217
  well_hbox.addWidget(well_lbl, 25, alignment=Qt.AlignVCenter)
199
- well_hbox.addWidget(self.well_list, 75)
218
+ well_subhbox = QHBoxLayout()
219
+ well_subhbox.addWidget(self.well_list, 95)
220
+ well_subhbox.addWidget(self.select_all_wells_btn, 5)
221
+ well_hbox.addLayout(well_subhbox, 75)
200
222
  vbox.addLayout(well_hbox)
201
223
 
202
224
  # Position row
203
225
  position_hbox = QHBoxLayout()
204
226
  position_hbox.addWidget(pos_lbl, 25, alignment=Qt.AlignVCenter)
205
227
  pos_subhbox = QHBoxLayout()
206
- pos_subhbox.addWidget(self.position_list, 95)
228
+ pos_subhbox.addWidget(self.position_list, 90)
229
+ pos_subhbox.addWidget(self.select_all_pos_btn, 5)
207
230
  pos_subhbox.addWidget(self.view_stack_btn, 5)
208
231
  position_hbox.addLayout(pos_subhbox, 75)
209
232
  vbox.addLayout(position_hbox)
210
233
 
211
234
  vbox.addWidget(hsep)
212
235
 
236
+ def select_all_wells(self):
237
+
238
+ if not self.select_all_wells_option:
239
+ self.well_list.selectAll()
240
+ self.select_all_wells_option = True
241
+ self.select_all_wells_btn.setIcon(icon(MDI6.select_all,color=self.celldetective_blue))
242
+ self.select_all_wells_btn.setIconSize(QSize(20, 20))
243
+ self.display_positions()
244
+ else:
245
+ self.well_list.unselectAll()
246
+ self.select_all_wells_option = False
247
+ self.select_all_wells_btn.setIcon(icon(MDI6.select_all,color="black"))
248
+ self.select_all_wells_btn.setIconSize(QSize(20, 20))
249
+ self.display_positions()
250
+
251
+ def select_all_positions(self):
252
+
253
+ if not self.select_all_pos_option:
254
+ self.position_list.selectAll()
255
+ self.select_all_pos_option = True
256
+ self.select_all_pos_btn.setIcon(icon(MDI6.select_all,color=self.celldetective_blue))
257
+ self.select_all_pos_btn.setIconSize(QSize(20, 20))
258
+ else:
259
+ self.position_list.unselectAll()
260
+ self.select_all_pos_option = False
261
+ self.select_all_pos_btn.setIcon(icon(MDI6.select_all,color="black"))
262
+ self.select_all_pos_btn.setIconSize(QSize(20, 20))
263
+
213
264
  def locate_image(self):
214
265
 
215
266
  """
@@ -341,17 +392,30 @@ class ControlPanel(QMainWindow, Styles):
341
392
  Show the positions as the well is changed.
342
393
  """
343
394
 
344
- if self.well_list.currentText()=="*":
395
+ if self.well_list.isMultipleSelection():
396
+
345
397
  self.position_list.clear()
346
- self.position_list.addItems(["*"])
347
398
  position_linspace = np.linspace(0,len(self.positions[0])-1,len(self.positions[0]),dtype=int)
348
399
  position_linspace = [str(s) for s in position_linspace]
349
400
  self.position_list.addItems(position_linspace)
401
+ if self.select_all_pos_option:
402
+ self.select_all_pos_btn.click()
403
+ self.select_all_pos_btn.click()
404
+
405
+ elif not self.well_list.isAnySelected():
406
+
407
+ self.position_list.unselectAll()
408
+ if self.select_all_pos_option:
409
+ self.select_all_pos_btn.click()
410
+
350
411
  else:
351
- pos_index = self.well_list.currentIndex()
412
+ pos_index = self.well_list.getSelectedIndices()[0]
352
413
  self.position_list.clear()
353
- self.position_list.addItems(["*"])
354
414
  self.position_list.addItems(self.positions[pos_index])
415
+ if self.select_all_pos_option:
416
+ self.select_all_pos_btn.click()
417
+ self.position_list.setCurrentIndex(0)
418
+
355
419
  self.update_position_options()
356
420
 
357
421
  def open_config_editor(self):
@@ -366,7 +430,7 @@ class ControlPanel(QMainWindow, Styles):
366
430
 
367
431
  """
368
432
 
369
- if self.well_list.currentText()=="*":
433
+ if self.well_list.isMultipleSelection():
370
434
  msgBox = QMessageBox()
371
435
  msgBox.setIcon(QMessageBox.Critical)
372
436
  msgBox.setText("Please select a single well...")
@@ -376,12 +440,12 @@ class ControlPanel(QMainWindow, Styles):
376
440
  if returnValue == QMessageBox.Ok:
377
441
  return False
378
442
  else:
379
- self.well_index = [self.well_list.currentIndex()]
443
+ self.well_index = self.well_list.getSelectedIndices() #[self.well_list.currentIndex()]
380
444
 
381
445
  for w_idx in self.well_index:
382
446
 
383
447
  pos = self.positions[w_idx]
384
- if self.position_list.currentText()=="*":
448
+ if not self.position_list.isSingleSelection():
385
449
  msgBox = QMessageBox()
386
450
  msgBox.setIcon(QMessageBox.Critical)
387
451
  msgBox.setText("Please select a single position...")
@@ -391,11 +455,12 @@ class ControlPanel(QMainWindow, Styles):
391
455
  if returnValue == QMessageBox.Ok:
392
456
  return False
393
457
  else:
394
- pos_indices = natsorted([pos.index(self.position_list.currentText())])
458
+ pos_indices = self.position_list.getSelectedIndices()
395
459
 
396
460
  well = self.wells[w_idx]
397
461
 
398
462
  for pos_idx in pos_indices:
463
+
399
464
  self.pos = natsorted(glob(well+f"{os.path.split(well)[-1].replace('W','').replace(os.sep,'')}*{os.sep}"))[pos_idx]
400
465
  if not os.path.exists(self.pos + 'output'):
401
466
  os.mkdir(self.pos + 'output')
@@ -405,6 +470,7 @@ class ControlPanel(QMainWindow, Styles):
405
470
  return True
406
471
 
407
472
  def create_config_dir(self):
473
+
408
474
  self.config_folder = self.exp_dir+'configs'+os.sep
409
475
  if not os.path.exists(self.config_folder):
410
476
  os.mkdir(self.config_folder)
@@ -413,7 +479,8 @@ class ControlPanel(QMainWindow, Styles):
413
479
 
414
480
  self.pos = self.position_list.currentText()
415
481
  panels = [self.ProcessEffectors, self.ProcessTargets]
416
- if self.position_list.currentText()=="*":
482
+
483
+ if self.position_list.isMultipleSelection() or not self.position_list.isAnySelected():
417
484
 
418
485
  for p in panels:
419
486
  p.check_seg_btn.setEnabled(False)
@@ -443,7 +510,9 @@ class ControlPanel(QMainWindow, Styles):
443
510
  self.ProcessEffectors.delete_tracks_btn.hide()
444
511
 
445
512
  self.view_stack_btn.setEnabled(False)
446
- elif self.well_list.currentText()=='*':
513
+
514
+ elif self.well_list.isMultipleSelection():
515
+
447
516
  self.ProcessTargets.view_tab_btn.setEnabled(True)
448
517
  self.ProcessEffectors.view_tab_btn.setEnabled(True)
449
518
  self.NeighPanel.view_tab_btn.setEnabled(True)
@@ -455,7 +524,9 @@ class ControlPanel(QMainWindow, Styles):
455
524
  self.ProcessTargets.delete_tracks_btn.hide()
456
525
  self.ProcessEffectors.delete_tracks_btn.hide()
457
526
  else:
458
- if not self.well_list.currentText()=="*":
527
+
528
+ if self.well_list.isAnySelected() and self.position_list.isAnySelected():
529
+
459
530
  self.locate_selected_position()
460
531
  self.view_stack_btn.setEnabled(True)
461
532
  # if os.path.exists(os.sep.join([self.pos,'labels_effectors', os.sep])):