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.
Files changed (152) hide show
  1. celldetective/__init__.py +25 -0
  2. celldetective/__main__.py +62 -43
  3. celldetective/_version.py +1 -1
  4. celldetective/extra_properties.py +477 -399
  5. celldetective/filters.py +192 -97
  6. celldetective/gui/InitWindow.py +541 -411
  7. celldetective/gui/__init__.py +0 -15
  8. celldetective/gui/about.py +44 -39
  9. celldetective/gui/analyze_block.py +120 -84
  10. celldetective/gui/base/__init__.py +0 -0
  11. celldetective/gui/base/channel_norm_generator.py +335 -0
  12. celldetective/gui/base/components.py +249 -0
  13. celldetective/gui/base/feature_choice.py +92 -0
  14. celldetective/gui/base/figure_canvas.py +52 -0
  15. celldetective/gui/base/list_widget.py +133 -0
  16. celldetective/gui/{styles.py → base/styles.py} +92 -36
  17. celldetective/gui/base/utils.py +33 -0
  18. celldetective/gui/base_annotator.py +900 -767
  19. celldetective/gui/classifier_widget.py +6 -22
  20. celldetective/gui/configure_new_exp.py +777 -671
  21. celldetective/gui/control_panel.py +635 -524
  22. celldetective/gui/dynamic_progress.py +449 -0
  23. celldetective/gui/event_annotator.py +2023 -1662
  24. celldetective/gui/generic_signal_plot.py +1292 -944
  25. celldetective/gui/gui_utils.py +899 -1289
  26. celldetective/gui/interactions_block.py +658 -0
  27. celldetective/gui/interactive_timeseries_viewer.py +447 -0
  28. celldetective/gui/json_readers.py +48 -15
  29. celldetective/gui/layouts/__init__.py +5 -0
  30. celldetective/gui/layouts/background_model_free_layout.py +537 -0
  31. celldetective/gui/layouts/channel_offset_layout.py +134 -0
  32. celldetective/gui/layouts/local_correction_layout.py +91 -0
  33. celldetective/gui/layouts/model_fit_layout.py +372 -0
  34. celldetective/gui/layouts/operation_layout.py +68 -0
  35. celldetective/gui/layouts/protocol_designer_layout.py +96 -0
  36. celldetective/gui/pair_event_annotator.py +3130 -2435
  37. celldetective/gui/plot_measurements.py +586 -267
  38. celldetective/gui/plot_signals_ui.py +724 -506
  39. celldetective/gui/preprocessing_block.py +395 -0
  40. celldetective/gui/process_block.py +1678 -1831
  41. celldetective/gui/seg_model_loader.py +580 -473
  42. celldetective/gui/settings/__init__.py +0 -7
  43. celldetective/gui/settings/_cellpose_model_params.py +181 -0
  44. celldetective/gui/settings/_event_detection_model_params.py +95 -0
  45. celldetective/gui/settings/_segmentation_model_params.py +159 -0
  46. celldetective/gui/settings/_settings_base.py +77 -65
  47. celldetective/gui/settings/_settings_event_model_training.py +752 -526
  48. celldetective/gui/settings/_settings_measurements.py +1133 -964
  49. celldetective/gui/settings/_settings_neighborhood.py +574 -488
  50. celldetective/gui/settings/_settings_segmentation_model_training.py +779 -564
  51. celldetective/gui/settings/_settings_signal_annotator.py +329 -305
  52. celldetective/gui/settings/_settings_tracking.py +1304 -1094
  53. celldetective/gui/settings/_stardist_model_params.py +98 -0
  54. celldetective/gui/survival_ui.py +422 -312
  55. celldetective/gui/tableUI.py +1665 -1701
  56. celldetective/gui/table_ops/_maths.py +295 -0
  57. celldetective/gui/table_ops/_merge_groups.py +140 -0
  58. celldetective/gui/table_ops/_merge_one_hot.py +95 -0
  59. celldetective/gui/table_ops/_query_table.py +43 -0
  60. celldetective/gui/table_ops/_rename_col.py +44 -0
  61. celldetective/gui/thresholds_gui.py +382 -179
  62. celldetective/gui/viewers/__init__.py +0 -0
  63. celldetective/gui/viewers/base_viewer.py +700 -0
  64. celldetective/gui/viewers/channel_offset_viewer.py +331 -0
  65. celldetective/gui/viewers/contour_viewer.py +394 -0
  66. celldetective/gui/viewers/size_viewer.py +153 -0
  67. celldetective/gui/viewers/spot_detection_viewer.py +341 -0
  68. celldetective/gui/viewers/threshold_viewer.py +309 -0
  69. celldetective/gui/workers.py +403 -126
  70. celldetective/log_manager.py +92 -0
  71. celldetective/measure.py +1895 -1478
  72. celldetective/napari/__init__.py +0 -0
  73. celldetective/napari/utils.py +1025 -0
  74. celldetective/neighborhood.py +1914 -1448
  75. celldetective/preprocessing.py +1620 -1220
  76. celldetective/processes/__init__.py +0 -0
  77. celldetective/processes/background_correction.py +271 -0
  78. celldetective/processes/compute_neighborhood.py +894 -0
  79. celldetective/processes/detect_events.py +246 -0
  80. celldetective/processes/downloader.py +137 -0
  81. celldetective/processes/measure_cells.py +565 -0
  82. celldetective/processes/segment_cells.py +760 -0
  83. celldetective/processes/track_cells.py +435 -0
  84. celldetective/processes/train_segmentation_model.py +694 -0
  85. celldetective/processes/train_signal_model.py +265 -0
  86. celldetective/processes/unified_process.py +292 -0
  87. celldetective/regionprops/_regionprops.py +358 -317
  88. celldetective/relative_measurements.py +987 -710
  89. celldetective/scripts/measure_cells.py +313 -212
  90. celldetective/scripts/measure_relative.py +90 -46
  91. celldetective/scripts/segment_cells.py +165 -104
  92. celldetective/scripts/segment_cells_thresholds.py +96 -68
  93. celldetective/scripts/track_cells.py +198 -149
  94. celldetective/scripts/train_segmentation_model.py +324 -201
  95. celldetective/scripts/train_signal_model.py +87 -45
  96. celldetective/segmentation.py +844 -749
  97. celldetective/signals.py +3514 -2861
  98. celldetective/tracking.py +30 -15
  99. celldetective/utils/__init__.py +0 -0
  100. celldetective/utils/cellpose_utils/__init__.py +133 -0
  101. celldetective/utils/color_mappings.py +42 -0
  102. celldetective/utils/data_cleaning.py +630 -0
  103. celldetective/utils/data_loaders.py +450 -0
  104. celldetective/utils/dataset_helpers.py +207 -0
  105. celldetective/utils/downloaders.py +235 -0
  106. celldetective/utils/event_detection/__init__.py +8 -0
  107. celldetective/utils/experiment.py +1782 -0
  108. celldetective/utils/image_augmenters.py +308 -0
  109. celldetective/utils/image_cleaning.py +74 -0
  110. celldetective/utils/image_loaders.py +926 -0
  111. celldetective/utils/image_transforms.py +335 -0
  112. celldetective/utils/io.py +62 -0
  113. celldetective/utils/mask_cleaning.py +348 -0
  114. celldetective/utils/mask_transforms.py +5 -0
  115. celldetective/utils/masks.py +184 -0
  116. celldetective/utils/maths.py +351 -0
  117. celldetective/utils/model_getters.py +325 -0
  118. celldetective/utils/model_loaders.py +296 -0
  119. celldetective/utils/normalization.py +380 -0
  120. celldetective/utils/parsing.py +465 -0
  121. celldetective/utils/plots/__init__.py +0 -0
  122. celldetective/utils/plots/regression.py +53 -0
  123. celldetective/utils/resources.py +34 -0
  124. celldetective/utils/stardist_utils/__init__.py +104 -0
  125. celldetective/utils/stats.py +90 -0
  126. celldetective/utils/types.py +21 -0
  127. {celldetective-1.4.2.dist-info → celldetective-1.5.0b1.dist-info}/METADATA +1 -1
  128. celldetective-1.5.0b1.dist-info/RECORD +187 -0
  129. {celldetective-1.4.2.dist-info → celldetective-1.5.0b1.dist-info}/WHEEL +1 -1
  130. tests/gui/test_new_project.py +129 -117
  131. tests/gui/test_project.py +127 -79
  132. tests/test_filters.py +39 -15
  133. tests/test_notebooks.py +8 -0
  134. tests/test_tracking.py +232 -13
  135. tests/test_utils.py +123 -77
  136. celldetective/gui/base_components.py +0 -23
  137. celldetective/gui/layouts.py +0 -1602
  138. celldetective/gui/processes/compute_neighborhood.py +0 -594
  139. celldetective/gui/processes/downloader.py +0 -111
  140. celldetective/gui/processes/measure_cells.py +0 -360
  141. celldetective/gui/processes/segment_cells.py +0 -499
  142. celldetective/gui/processes/track_cells.py +0 -303
  143. celldetective/gui/processes/train_segmentation_model.py +0 -270
  144. celldetective/gui/processes/train_signal_model.py +0 -108
  145. celldetective/gui/table_ops/merge_groups.py +0 -118
  146. celldetective/gui/viewers.py +0 -1354
  147. celldetective/io.py +0 -3663
  148. celldetective/utils.py +0 -3108
  149. celldetective-1.4.2.dist-info/RECORD +0 -123
  150. {celldetective-1.4.2.dist-info → celldetective-1.5.0b1.dist-info}/entry_points.txt +0 -0
  151. {celldetective-1.4.2.dist-info → celldetective-1.5.0b1.dist-info}/licenses/LICENSE +0 -0
  152. {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
+