celldetective 1.4.2__py3-none-any.whl → 1.5.0b1__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/__init__.py +25 -0
- celldetective/__main__.py +62 -43
- celldetective/_version.py +1 -1
- celldetective/extra_properties.py +477 -399
- celldetective/filters.py +192 -97
- celldetective/gui/InitWindow.py +541 -411
- celldetective/gui/__init__.py +0 -15
- celldetective/gui/about.py +44 -39
- celldetective/gui/analyze_block.py +120 -84
- celldetective/gui/base/__init__.py +0 -0
- celldetective/gui/base/channel_norm_generator.py +335 -0
- celldetective/gui/base/components.py +249 -0
- celldetective/gui/base/feature_choice.py +92 -0
- celldetective/gui/base/figure_canvas.py +52 -0
- celldetective/gui/base/list_widget.py +133 -0
- celldetective/gui/{styles.py → base/styles.py} +92 -36
- celldetective/gui/base/utils.py +33 -0
- celldetective/gui/base_annotator.py +900 -767
- celldetective/gui/classifier_widget.py +6 -22
- celldetective/gui/configure_new_exp.py +777 -671
- celldetective/gui/control_panel.py +635 -524
- celldetective/gui/dynamic_progress.py +449 -0
- celldetective/gui/event_annotator.py +2023 -1662
- celldetective/gui/generic_signal_plot.py +1292 -944
- celldetective/gui/gui_utils.py +899 -1289
- celldetective/gui/interactions_block.py +658 -0
- celldetective/gui/interactive_timeseries_viewer.py +447 -0
- celldetective/gui/json_readers.py +48 -15
- celldetective/gui/layouts/__init__.py +5 -0
- celldetective/gui/layouts/background_model_free_layout.py +537 -0
- celldetective/gui/layouts/channel_offset_layout.py +134 -0
- celldetective/gui/layouts/local_correction_layout.py +91 -0
- celldetective/gui/layouts/model_fit_layout.py +372 -0
- celldetective/gui/layouts/operation_layout.py +68 -0
- celldetective/gui/layouts/protocol_designer_layout.py +96 -0
- celldetective/gui/pair_event_annotator.py +3130 -2435
- celldetective/gui/plot_measurements.py +586 -267
- celldetective/gui/plot_signals_ui.py +724 -506
- celldetective/gui/preprocessing_block.py +395 -0
- celldetective/gui/process_block.py +1678 -1831
- celldetective/gui/seg_model_loader.py +580 -473
- celldetective/gui/settings/__init__.py +0 -7
- celldetective/gui/settings/_cellpose_model_params.py +181 -0
- celldetective/gui/settings/_event_detection_model_params.py +95 -0
- celldetective/gui/settings/_segmentation_model_params.py +159 -0
- celldetective/gui/settings/_settings_base.py +77 -65
- celldetective/gui/settings/_settings_event_model_training.py +752 -526
- celldetective/gui/settings/_settings_measurements.py +1133 -964
- celldetective/gui/settings/_settings_neighborhood.py +574 -488
- celldetective/gui/settings/_settings_segmentation_model_training.py +779 -564
- celldetective/gui/settings/_settings_signal_annotator.py +329 -305
- celldetective/gui/settings/_settings_tracking.py +1304 -1094
- celldetective/gui/settings/_stardist_model_params.py +98 -0
- celldetective/gui/survival_ui.py +422 -312
- celldetective/gui/tableUI.py +1665 -1701
- celldetective/gui/table_ops/_maths.py +295 -0
- celldetective/gui/table_ops/_merge_groups.py +140 -0
- celldetective/gui/table_ops/_merge_one_hot.py +95 -0
- celldetective/gui/table_ops/_query_table.py +43 -0
- celldetective/gui/table_ops/_rename_col.py +44 -0
- celldetective/gui/thresholds_gui.py +382 -179
- celldetective/gui/viewers/__init__.py +0 -0
- celldetective/gui/viewers/base_viewer.py +700 -0
- celldetective/gui/viewers/channel_offset_viewer.py +331 -0
- celldetective/gui/viewers/contour_viewer.py +394 -0
- celldetective/gui/viewers/size_viewer.py +153 -0
- celldetective/gui/viewers/spot_detection_viewer.py +341 -0
- celldetective/gui/viewers/threshold_viewer.py +309 -0
- celldetective/gui/workers.py +403 -126
- celldetective/log_manager.py +92 -0
- celldetective/measure.py +1895 -1478
- celldetective/napari/__init__.py +0 -0
- celldetective/napari/utils.py +1025 -0
- celldetective/neighborhood.py +1914 -1448
- celldetective/preprocessing.py +1620 -1220
- celldetective/processes/__init__.py +0 -0
- celldetective/processes/background_correction.py +271 -0
- celldetective/processes/compute_neighborhood.py +894 -0
- celldetective/processes/detect_events.py +246 -0
- celldetective/processes/downloader.py +137 -0
- celldetective/processes/measure_cells.py +565 -0
- celldetective/processes/segment_cells.py +760 -0
- celldetective/processes/track_cells.py +435 -0
- celldetective/processes/train_segmentation_model.py +694 -0
- celldetective/processes/train_signal_model.py +265 -0
- celldetective/processes/unified_process.py +292 -0
- celldetective/regionprops/_regionprops.py +358 -317
- celldetective/relative_measurements.py +987 -710
- celldetective/scripts/measure_cells.py +313 -212
- celldetective/scripts/measure_relative.py +90 -46
- celldetective/scripts/segment_cells.py +165 -104
- celldetective/scripts/segment_cells_thresholds.py +96 -68
- celldetective/scripts/track_cells.py +198 -149
- celldetective/scripts/train_segmentation_model.py +324 -201
- celldetective/scripts/train_signal_model.py +87 -45
- celldetective/segmentation.py +844 -749
- celldetective/signals.py +3514 -2861
- celldetective/tracking.py +30 -15
- celldetective/utils/__init__.py +0 -0
- celldetective/utils/cellpose_utils/__init__.py +133 -0
- celldetective/utils/color_mappings.py +42 -0
- celldetective/utils/data_cleaning.py +630 -0
- celldetective/utils/data_loaders.py +450 -0
- celldetective/utils/dataset_helpers.py +207 -0
- celldetective/utils/downloaders.py +235 -0
- celldetective/utils/event_detection/__init__.py +8 -0
- celldetective/utils/experiment.py +1782 -0
- celldetective/utils/image_augmenters.py +308 -0
- celldetective/utils/image_cleaning.py +74 -0
- celldetective/utils/image_loaders.py +926 -0
- celldetective/utils/image_transforms.py +335 -0
- celldetective/utils/io.py +62 -0
- celldetective/utils/mask_cleaning.py +348 -0
- celldetective/utils/mask_transforms.py +5 -0
- celldetective/utils/masks.py +184 -0
- celldetective/utils/maths.py +351 -0
- celldetective/utils/model_getters.py +325 -0
- celldetective/utils/model_loaders.py +296 -0
- celldetective/utils/normalization.py +380 -0
- celldetective/utils/parsing.py +465 -0
- celldetective/utils/plots/__init__.py +0 -0
- celldetective/utils/plots/regression.py +53 -0
- celldetective/utils/resources.py +34 -0
- celldetective/utils/stardist_utils/__init__.py +104 -0
- celldetective/utils/stats.py +90 -0
- celldetective/utils/types.py +21 -0
- {celldetective-1.4.2.dist-info → celldetective-1.5.0b1.dist-info}/METADATA +1 -1
- celldetective-1.5.0b1.dist-info/RECORD +187 -0
- {celldetective-1.4.2.dist-info → celldetective-1.5.0b1.dist-info}/WHEEL +1 -1
- tests/gui/test_new_project.py +129 -117
- tests/gui/test_project.py +127 -79
- tests/test_filters.py +39 -15
- tests/test_notebooks.py +8 -0
- tests/test_tracking.py +232 -13
- tests/test_utils.py +123 -77
- celldetective/gui/base_components.py +0 -23
- celldetective/gui/layouts.py +0 -1602
- celldetective/gui/processes/compute_neighborhood.py +0 -594
- celldetective/gui/processes/downloader.py +0 -111
- celldetective/gui/processes/measure_cells.py +0 -360
- celldetective/gui/processes/segment_cells.py +0 -499
- celldetective/gui/processes/track_cells.py +0 -303
- celldetective/gui/processes/train_segmentation_model.py +0 -270
- celldetective/gui/processes/train_signal_model.py +0 -108
- celldetective/gui/table_ops/merge_groups.py +0 -118
- celldetective/gui/viewers.py +0 -1354
- celldetective/io.py +0 -3663
- celldetective/utils.py +0 -3108
- celldetective-1.4.2.dist-info/RECORD +0 -123
- {celldetective-1.4.2.dist-info → celldetective-1.5.0b1.dist-info}/entry_points.txt +0 -0
- {celldetective-1.4.2.dist-info → celldetective-1.5.0b1.dist-info}/licenses/LICENSE +0 -0
- {celldetective-1.4.2.dist-info → celldetective-1.5.0b1.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import os
|
|
3
|
+
import shutil
|
|
4
|
+
import tempfile
|
|
5
|
+
import zipfile
|
|
6
|
+
from glob import glob
|
|
7
|
+
from urllib.request import urlopen
|
|
8
|
+
|
|
9
|
+
import numpy as np
|
|
10
|
+
from tqdm import tqdm
|
|
11
|
+
|
|
12
|
+
from celldetective.utils.io import remove_file_if_exists
|
|
13
|
+
from celldetective import get_logger
|
|
14
|
+
|
|
15
|
+
logger = get_logger()
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def get_zenodo_files(cat=None):
|
|
19
|
+
|
|
20
|
+
zenodo_json = os.sep.join(
|
|
21
|
+
[
|
|
22
|
+
os.path.split(os.path.dirname(os.path.realpath(__file__)))[0],
|
|
23
|
+
# "celldetective",
|
|
24
|
+
"links",
|
|
25
|
+
"zenodo.json",
|
|
26
|
+
]
|
|
27
|
+
)
|
|
28
|
+
with open(zenodo_json, "r") as f:
|
|
29
|
+
zenodo_json = json.load(f)
|
|
30
|
+
all_files = list(zenodo_json["files"]["entries"].keys())
|
|
31
|
+
all_files_short = [f.replace(".zip", "") for f in all_files]
|
|
32
|
+
|
|
33
|
+
categories = []
|
|
34
|
+
for f in all_files_short:
|
|
35
|
+
if f.startswith("CP") or f.startswith("SD"):
|
|
36
|
+
category = os.sep.join(["models", "segmentation_generic"])
|
|
37
|
+
elif f.startswith("MCF7") or f.startswith("mcf7"):
|
|
38
|
+
category = os.sep.join(["models", "segmentation_targets"])
|
|
39
|
+
elif f.startswith("primNK") or f.startswith("lymphocytes"):
|
|
40
|
+
category = os.sep.join(["models", "segmentation_effectors"])
|
|
41
|
+
elif f.startswith("demo"):
|
|
42
|
+
category = "demos"
|
|
43
|
+
elif f.startswith("db-si"):
|
|
44
|
+
category = os.sep.join(["datasets", "signal_annotations"])
|
|
45
|
+
elif f.startswith("db"):
|
|
46
|
+
category = os.sep.join(["datasets", "segmentation_annotations"])
|
|
47
|
+
else:
|
|
48
|
+
category = os.sep.join(["models", "signal_detection"])
|
|
49
|
+
categories.append(category)
|
|
50
|
+
|
|
51
|
+
if cat is not None:
|
|
52
|
+
if cat in [
|
|
53
|
+
os.sep.join(["models", "segmentation_generic"]),
|
|
54
|
+
os.sep.join(["models", "segmentation_targets"]),
|
|
55
|
+
os.sep.join(["models", "segmentation_effectors"]),
|
|
56
|
+
"demos",
|
|
57
|
+
os.sep.join(["datasets", "signal_annotations"]),
|
|
58
|
+
os.sep.join(["datasets", "segmentation_annotations"]),
|
|
59
|
+
os.sep.join(["models", "signal_detection"]),
|
|
60
|
+
]:
|
|
61
|
+
categories = np.array(categories)
|
|
62
|
+
all_files_short = np.array(all_files_short)
|
|
63
|
+
return list(all_files_short[np.where(categories == cat)[0]])
|
|
64
|
+
else:
|
|
65
|
+
return []
|
|
66
|
+
else:
|
|
67
|
+
return all_files_short, categories
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def download_url_to_file(url, dst, progress=True):
|
|
71
|
+
r"""Download object at the given URL to a local path.
|
|
72
|
+
Thanks to torch, slightly modified, from Cellpose
|
|
73
|
+
Args:
|
|
74
|
+
url (string): URL of the object to download
|
|
75
|
+
dst (string): Full path where object will be saved, e.g. `/tmp/temporary_file`
|
|
76
|
+
progress (bool, optional): whether to display a progress bar to stderr
|
|
77
|
+
Default: True
|
|
78
|
+
|
|
79
|
+
"""
|
|
80
|
+
file_size = None
|
|
81
|
+
import ssl
|
|
82
|
+
|
|
83
|
+
ssl._create_default_https_context = ssl._create_unverified_context
|
|
84
|
+
u = urlopen(url)
|
|
85
|
+
meta = u.info()
|
|
86
|
+
if hasattr(meta, "getheaders"):
|
|
87
|
+
content_length = meta.getheaders("Content-Length")
|
|
88
|
+
else:
|
|
89
|
+
content_length = meta.get_all("Content-Length")
|
|
90
|
+
if content_length is not None and len(content_length) > 0:
|
|
91
|
+
file_size = int(content_length[0])
|
|
92
|
+
# We deliberately save it in a temp file and move it after
|
|
93
|
+
dst = os.path.expanduser(dst)
|
|
94
|
+
dst_dir = os.path.dirname(dst)
|
|
95
|
+
f = tempfile.NamedTemporaryFile(delete=False, dir=dst_dir)
|
|
96
|
+
|
|
97
|
+
# GUI Check
|
|
98
|
+
try:
|
|
99
|
+
from PyQt5.QtWidgets import QApplication, QProgressDialog
|
|
100
|
+
from PyQt5.QtCore import Qt
|
|
101
|
+
|
|
102
|
+
app = QApplication.instance()
|
|
103
|
+
use_gui = app is not None
|
|
104
|
+
except ImportError:
|
|
105
|
+
use_gui = False
|
|
106
|
+
|
|
107
|
+
try:
|
|
108
|
+
if use_gui and progress:
|
|
109
|
+
# Setup QProgressDialog
|
|
110
|
+
pd = QProgressDialog("Downloading...", "Cancel", 0, 100)
|
|
111
|
+
pd.setWindowTitle("Downloading content")
|
|
112
|
+
pd.setWindowModality(Qt.WindowModal)
|
|
113
|
+
pd.setMinimumDuration(0)
|
|
114
|
+
pd.setValue(0)
|
|
115
|
+
|
|
116
|
+
downloaded = 0
|
|
117
|
+
while True:
|
|
118
|
+
buffer = u.read(8192)
|
|
119
|
+
if len(buffer) == 0:
|
|
120
|
+
break
|
|
121
|
+
f.write(buffer)
|
|
122
|
+
downloaded += len(buffer)
|
|
123
|
+
if file_size:
|
|
124
|
+
perc = int(downloaded * 100 / file_size)
|
|
125
|
+
pd.setValue(perc)
|
|
126
|
+
pd.setLabelText(
|
|
127
|
+
f"Downloading... {downloaded/1024/1024:.1f}/{file_size/1024/1024:.1f} MB"
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
QApplication.processEvents()
|
|
131
|
+
if pd.wasCanceled():
|
|
132
|
+
print("Download cancelled by user.")
|
|
133
|
+
break
|
|
134
|
+
pd.close()
|
|
135
|
+
|
|
136
|
+
else:
|
|
137
|
+
# Console / TQDM fallback
|
|
138
|
+
with tqdm(
|
|
139
|
+
total=file_size,
|
|
140
|
+
disable=not progress,
|
|
141
|
+
unit="B",
|
|
142
|
+
unit_scale=True,
|
|
143
|
+
unit_divisor=1024,
|
|
144
|
+
) as pbar:
|
|
145
|
+
while True:
|
|
146
|
+
buffer = u.read(8192) # 8192
|
|
147
|
+
if len(buffer) == 0:
|
|
148
|
+
break
|
|
149
|
+
f.write(buffer)
|
|
150
|
+
pbar.update(len(buffer))
|
|
151
|
+
|
|
152
|
+
f.close()
|
|
153
|
+
shutil.move(f.name, dst)
|
|
154
|
+
finally:
|
|
155
|
+
f.close()
|
|
156
|
+
remove_file_if_exists(f.name)
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
def download_zenodo_file(file, output_dir):
|
|
160
|
+
|
|
161
|
+
logger.info(f"{file=} {output_dir=}")
|
|
162
|
+
|
|
163
|
+
# GUI Check
|
|
164
|
+
try:
|
|
165
|
+
from PyQt5.QtWidgets import QApplication, QDialog
|
|
166
|
+
|
|
167
|
+
app = QApplication.instance()
|
|
168
|
+
use_gui = app is not None
|
|
169
|
+
except ImportError:
|
|
170
|
+
use_gui = False
|
|
171
|
+
|
|
172
|
+
if use_gui:
|
|
173
|
+
try:
|
|
174
|
+
from celldetective.gui.workers import GenericProgressWindow
|
|
175
|
+
from celldetective.processes.downloader import DownloadProcess
|
|
176
|
+
|
|
177
|
+
# Find parent window if possible, else None is fine for a dialog
|
|
178
|
+
parent = app.activeWindow()
|
|
179
|
+
|
|
180
|
+
process_args = {"output_dir": output_dir, "file": file}
|
|
181
|
+
job = GenericProgressWindow(
|
|
182
|
+
DownloadProcess,
|
|
183
|
+
parent_window=parent,
|
|
184
|
+
title="Download",
|
|
185
|
+
process_args=process_args,
|
|
186
|
+
label_text=f"Downloading {file}...",
|
|
187
|
+
)
|
|
188
|
+
result = job.exec_()
|
|
189
|
+
if result == QDialog.Accepted:
|
|
190
|
+
return # DownloadProcess handles the file operations
|
|
191
|
+
else:
|
|
192
|
+
logger.info("Download cancelled or failed.")
|
|
193
|
+
return
|
|
194
|
+
|
|
195
|
+
except Exception as e:
|
|
196
|
+
logger.error(f"Failed to use GUI downloader: {e}. Falling back to console.")
|
|
197
|
+
# Fallback to console implementation below if GUI fails
|
|
198
|
+
|
|
199
|
+
# Console Implementation
|
|
200
|
+
zenodo_json = os.sep.join(
|
|
201
|
+
[
|
|
202
|
+
os.path.split(os.path.dirname(os.path.realpath(__file__)))[0],
|
|
203
|
+
# "celldetective",
|
|
204
|
+
"links",
|
|
205
|
+
"zenodo.json",
|
|
206
|
+
]
|
|
207
|
+
)
|
|
208
|
+
logger.info(f"{zenodo_json=}")
|
|
209
|
+
with open(zenodo_json, "r") as f:
|
|
210
|
+
zenodo_json = json.load(f)
|
|
211
|
+
all_files = list(zenodo_json["files"]["entries"].keys())
|
|
212
|
+
all_files_short = [f.replace(".zip", "") for f in all_files]
|
|
213
|
+
zenodo_url = zenodo_json["links"]["files"].replace("api/", "")
|
|
214
|
+
full_links = ["/".join([zenodo_url, f]) for f in all_files]
|
|
215
|
+
index = all_files_short.index(file)
|
|
216
|
+
zip_url = full_links[index]
|
|
217
|
+
|
|
218
|
+
path_to_zip_file = os.sep.join([output_dir, "temp.zip"])
|
|
219
|
+
download_url_to_file(rf"{zip_url}", path_to_zip_file)
|
|
220
|
+
with zipfile.ZipFile(path_to_zip_file, "r") as zip_ref:
|
|
221
|
+
zip_ref.extractall(output_dir)
|
|
222
|
+
|
|
223
|
+
file_to_rename = glob(
|
|
224
|
+
os.sep.join(
|
|
225
|
+
[output_dir, file, "*[!.json][!.png][!.h5][!.csv][!.npy][!.tif][!.ini]"]
|
|
226
|
+
)
|
|
227
|
+
)
|
|
228
|
+
if (
|
|
229
|
+
len(file_to_rename) > 0
|
|
230
|
+
and not file_to_rename[0].endswith(os.sep)
|
|
231
|
+
and not file.startswith("demo")
|
|
232
|
+
):
|
|
233
|
+
os.rename(file_to_rename[0], os.sep.join([output_dir, file, file]))
|
|
234
|
+
|
|
235
|
+
os.remove(path_to_zip_file)
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
from celldetective.signals import SignalDetectionModel
|
|
2
|
+
from celldetective.utils.model_loaders import locate_signal_model
|
|
3
|
+
|
|
4
|
+
def _prep_event_detection_model(model_name=None, use_gpu=True):
|
|
5
|
+
model_path = locate_signal_model(model_name)
|
|
6
|
+
signal_model = SignalDetectionModel(pretrained=model_path)
|
|
7
|
+
return signal_model
|
|
8
|
+
|