celldetective 1.3.3.post1__py3-none-any.whl → 1.3.4__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.
- celldetective/__main__.py +30 -4
- celldetective/_version.py +1 -1
- celldetective/extra_properties.py +21 -0
- celldetective/filters.py +15 -2
- celldetective/gui/InitWindow.py +28 -34
- celldetective/gui/analyze_block.py +3 -498
- celldetective/gui/classifier_widget.py +1 -1
- celldetective/gui/control_panel.py +98 -27
- celldetective/gui/generic_signal_plot.py +35 -18
- celldetective/gui/gui_utils.py +143 -2
- celldetective/gui/layouts.py +7 -6
- celldetective/gui/measurement_options.py +3 -11
- celldetective/gui/plot_measurements.py +5 -13
- celldetective/gui/plot_signals_ui.py +30 -30
- celldetective/gui/process_block.py +61 -103
- celldetective/gui/signal_annotator.py +50 -32
- celldetective/gui/signal_annotator2.py +7 -4
- celldetective/gui/styles.py +13 -0
- celldetective/gui/survival_ui.py +8 -21
- celldetective/gui/tableUI.py +1 -2
- celldetective/gui/thresholds_gui.py +0 -6
- celldetective/gui/viewers.py +1 -5
- celldetective/io.py +31 -4
- celldetective/measure.py +8 -5
- celldetective/neighborhood.py +0 -2
- celldetective/scripts/measure_cells.py +21 -9
- celldetective/signals.py +77 -66
- celldetective/tracking.py +19 -13
- {celldetective-1.3.3.post1.dist-info → celldetective-1.3.4.dist-info}/METADATA +2 -1
- {celldetective-1.3.3.post1.dist-info → celldetective-1.3.4.dist-info}/RECORD +35 -35
- tests/test_qt.py +5 -3
- {celldetective-1.3.3.post1.dist-info → celldetective-1.3.4.dist-info}/LICENSE +0 -0
- {celldetective-1.3.3.post1.dist-info → celldetective-1.3.4.dist-info}/WHEEL +0 -0
- {celldetective-1.3.3.post1.dist-info → celldetective-1.3.4.dist-info}/entry_points.txt +0 -0
- {celldetective-1.3.3.post1.dist-info → celldetective-1.3.4.dist-info}/top_level.txt +0 -0
celldetective/__main__.py
CHANGED
|
@@ -5,6 +5,7 @@ from PyQt5.QtGui import QPixmap
|
|
|
5
5
|
from os import sep
|
|
6
6
|
from celldetective.utils import get_software_location
|
|
7
7
|
from time import time, sleep
|
|
8
|
+
|
|
8
9
|
#os.environ['QT_DEBUG_PLUGINS'] = '1'
|
|
9
10
|
|
|
10
11
|
if __name__ == "__main__":
|
|
@@ -15,9 +16,11 @@ if __name__ == "__main__":
|
|
|
15
16
|
App = QApplication(sys.argv)
|
|
16
17
|
App.setStyle("Fusion")
|
|
17
18
|
|
|
19
|
+
software_location = get_software_location()
|
|
20
|
+
|
|
18
21
|
if splash:
|
|
19
22
|
start = time()
|
|
20
|
-
splash_pix = QPixmap(sep.join([
|
|
23
|
+
splash_pix = QPixmap(sep.join([software_location,'celldetective','icons','splash.png']))
|
|
21
24
|
splash = QSplashScreen(splash_pix)
|
|
22
25
|
splash.setMask(splash_pix.mask())
|
|
23
26
|
splash.show()
|
|
@@ -26,13 +29,36 @@ if __name__ == "__main__":
|
|
|
26
29
|
sleep(0.001)
|
|
27
30
|
App.processEvents()
|
|
28
31
|
|
|
29
|
-
|
|
30
|
-
|
|
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
|
+
|
|
31
57
|
from celldetective.gui.InitWindow import AppInitWindow
|
|
32
58
|
|
|
33
59
|
print('Libraries successfully loaded...')
|
|
34
60
|
|
|
35
|
-
window = AppInitWindow(App)
|
|
61
|
+
window = AppInitWindow(App, software_location=software_location)
|
|
36
62
|
|
|
37
63
|
if splash:
|
|
38
64
|
splash.finish(window)
|
celldetective/_version.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = "1.3.
|
|
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
|
|
celldetective/filters.py
CHANGED
|
@@ -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
|
-
|
|
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):
|
celldetective/gui/InitWindow.py
CHANGED
|
@@ -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
|
-
|
|
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
|
|
18
|
-
import
|
|
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,
|
|
36
|
+
self.n_threads = min([1,cpu_count()])
|
|
36
37
|
|
|
37
38
|
try:
|
|
38
|
-
|
|
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 =
|
|
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
|
-
|
|
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
|
|
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...")
|