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
celldetective/tracking.py CHANGED
@@ -7,8 +7,9 @@ from btrack.io.utils import localizations_to_objects
7
7
  from btrack import BayesianTracker
8
8
 
9
9
  from celldetective.measure import measure_features
10
- from celldetective.utils import rename_intensity_column, velocity_per_track
11
- from celldetective.io import interpret_tracking_configuration
10
+ from celldetective.utils.maths import velocity_per_track
11
+ from celldetective.utils.data_cleaning import rename_intensity_column
12
+ from celldetective.utils.data_loaders import interpret_tracking_configuration
12
13
 
13
14
  import os
14
15
  import subprocess
@@ -95,6 +96,7 @@ def track(
95
96
 
96
97
  Examples
97
98
  --------
99
+
98
100
  >>> labels = np.array([[1, 1, 2, 2, 0, 0],
99
101
  [1, 1, 1, 2, 2, 0],
100
102
  [0, 0, 1, 2, 0, 0]])
@@ -473,16 +475,11 @@ def clean_trajectories(
473
475
 
474
476
  """
475
477
 
476
- trajectories.reset_index
478
+ trajectories.reset_index(drop=True, inplace=True)
477
479
  trajectories.sort_values(
478
480
  by=[column_labels["track"], column_labels["time"]], inplace=True
479
481
  )
480
482
 
481
- if minimum_tracklength > 0:
482
- trajectories = filter_by_tracklength(
483
- trajectories.copy(), minimum_tracklength, track_label=column_labels["track"]
484
- )
485
-
486
483
  if np.any([remove_not_in_first, remove_not_in_last]):
487
484
  trajectories = filter_by_endpoints(
488
485
  trajectories.copy(),
@@ -503,11 +500,19 @@ def clean_trajectories(
503
500
  trajectories = interpolate_time_gaps(
504
501
  trajectories.copy(), column_labels=column_labels
505
502
  )
503
+ # interpolate_time_gaps might leave TRACK_ID in index of some rows or overall
504
+ trajectories.reset_index(drop=True, inplace=True)
506
505
 
507
506
  if interpolate_na:
508
507
  trajectories = interpolate_nan_properties(
509
508
  trajectories.copy(), track_label=column_labels["track"]
510
509
  )
510
+ trajectories.reset_index(drop=True, inplace=True)
511
+
512
+ if minimum_tracklength > 0:
513
+ trajectories = filter_by_tracklength(
514
+ trajectories.copy(), minimum_tracklength, track_label=column_labels["track"]
515
+ )
511
516
 
512
517
  trajectories = trajectories.sort_values(
513
518
  by=[column_labels["track"], column_labels["time"]]
@@ -600,10 +605,15 @@ def interpolate_nan_properties(trajectories, track_label="TRACK_ID"):
600
605
 
601
606
  """
602
607
 
603
- trajectories = trajectories.groupby(track_label, group_keys=False).apply(
608
+ trajectories = trajectories.groupby(track_label, group_keys=True).apply(
604
609
  interpolate_per_track
605
610
  )
606
611
 
612
+ if track_label in trajectories.index.names:
613
+ trajectories = trajectories.reset_index(
614
+ level=0, drop=track_label in trajectories.columns
615
+ )
616
+
607
617
  return trajectories
608
618
 
609
619
 
@@ -840,11 +850,9 @@ def interpolate_time_gaps(
840
850
  lambda x: x.interpolate(method="linear")
841
851
  )
842
852
  trajectories.reset_index(drop=True, inplace=True)
843
- trajectories[column_labels["time"]] = np.round(
844
- (trajectories[column_labels["time"]] - pd.Timestamp("1970-01-01"))
845
- / pd.Timedelta("1s"),
846
- 9,
847
- )
853
+ trajectories[column_labels["time"]] = (
854
+ trajectories[column_labels["time"]] - pd.Timestamp("1970-01-01")
855
+ ).dt.total_seconds()
848
856
  # trajectories[column_labels['time']] = trajectories[column_labels['time']].astype('int64')
849
857
  trajectories.sort_values(
850
858
  by=[column_labels["track"], column_labels["time"]], inplace=True
@@ -998,7 +1006,14 @@ def extrapolate_tracks(
998
1006
  [column_labels["track"], column_labels["time"]], inplace=True
999
1007
  )
1000
1008
 
1001
- return trajectories
1009
+ return trajectories[
1010
+ [column_labels["track"], column_labels["time"]]
1011
+ + [
1012
+ col
1013
+ for col in trajectories.columns
1014
+ if col not in [column_labels["track"], column_labels["time"]]
1015
+ ]
1016
+ ]
1002
1017
 
1003
1018
 
1004
1019
  def compute_instantaneous_velocity(
File without changes
@@ -0,0 +1,133 @@
1
+ from pathlib import Path
2
+ from typing import Union, Optional
3
+
4
+ import numpy as np
5
+
6
+
7
+ def _segment_image_with_cellpose_model(
8
+ img,
9
+ model=None,
10
+ diameter=None,
11
+ cellprob_threshold=None,
12
+ flow_threshold=None,
13
+ channel_axis=-1,
14
+ ):
15
+ """
16
+ Segments an input image using a Cellpose model.
17
+
18
+ This function applies a preloaded Cellpose model to segment an input image and returns the resulting labeled mask.
19
+ The image is rearranged into the format expected by the Cellpose model, with the specified channel axis moved to the first dimension.
20
+
21
+ Parameters
22
+ ----------
23
+ img : ndarray
24
+ The input image to be segmented. It is expected to have a channel axis specified by `channel_axis`.
25
+ model : CellposeModel, optional
26
+ A preloaded Cellpose model instance used for segmentation.
27
+ diameter : float, optional
28
+ The diameter of objects to segment. If `None`, the model's default diameter is used.
29
+ cellprob_threshold : float, optional
30
+ The threshold for the probability of cells used during segmentation. If `None`, the default threshold is used.
31
+ flow_threshold : float, optional
32
+ The threshold for flow error during segmentation. If `None`, the default threshold is used.
33
+ channel_axis : int, optional
34
+ The axis of the input image that represents the channels. Default is `-1` (channel-last format).
35
+
36
+ Returns
37
+ -------
38
+ ndarray
39
+ A labeled mask of the same spatial dimensions as the input image, with segmented regions assigned unique
40
+ integer labels. The dtype of the mask is `uint16`.
41
+
42
+ Notes
43
+ -----
44
+ - The `img` array is internally rearranged to move the specified `channel_axis` to the first dimension to comply
45
+ with the Cellpose model's input requirements.
46
+ - Ensure the provided `model` is a properly initialized Cellpose model instance.
47
+ - Parameters `diameter`, `cellprob_threshold`, and `flow_threshold` allow fine-tuning of the segmentation process.
48
+ """
49
+
50
+ img = np.moveaxis(img, channel_axis, 0)
51
+ lbl, _, _ = model.eval(
52
+ img,
53
+ diameter=diameter,
54
+ cellprob_threshold=cellprob_threshold,
55
+ flow_threshold=flow_threshold,
56
+ channels=None,
57
+ normalize=False,
58
+ model_loaded=True,
59
+ )
60
+
61
+ return lbl.astype(np.uint16)
62
+
63
+
64
+ def _prep_cellpose_model(
65
+ model_name: str,
66
+ path: Union[str, Path],
67
+ use_gpu: bool = False,
68
+ n_channels: int = 2,
69
+ scale: Optional[float] = None,
70
+ ):
71
+ """
72
+ Prepares and loads a Cellpose model for segmentation tasks.
73
+
74
+ This function initializes a Cellpose model with the specified parameters, configures GPU usage if available,
75
+ and calculates or applies a scaling factor for the model based on image resolution.
76
+
77
+ Parameters
78
+ ----------
79
+ model_name : str
80
+ The name of the pretrained Cellpose model to load.
81
+ path : str
82
+ The directory where the model is stored.
83
+ use_gpu : bool, optional
84
+ If `True`, the model will use GPU acceleration for computations. Default is `False`.
85
+ n_channels : int, optional
86
+ The number of input channels expected by the model. Default is `2`.
87
+ scale : float, optional
88
+ A scaling factor to adjust the model's output to match the image resolution. If not provided, the scale is
89
+ automatically calculated based on the model's diameter parameters.
90
+
91
+ Returns
92
+ -------
93
+ tuple
94
+ - model : CellposeModel
95
+ The loaded Cellpose model configured with the specified parameters.
96
+ - scale_model : float
97
+ The scaling factor applied to the model, calculated or provided.
98
+
99
+ Notes
100
+ -----
101
+ - Ensure the Cellpose package is installed and the model files are correctly stored in the provided path.
102
+ - GPU support depends on the availability of compatible hardware and software setup.
103
+ - The scale is calculated as `(diam_mean / diam_labels)` if `scale` is not provided, where `diam_mean` and
104
+ `diam_labels` are attributes of the model.
105
+ """
106
+
107
+ import torch
108
+
109
+ if not use_gpu:
110
+ device = torch.device("cpu")
111
+ else:
112
+ device = torch.device("cuda")
113
+
114
+ from cellpose.models import CellposeModel
115
+
116
+ model = CellposeModel(
117
+ gpu=use_gpu,
118
+ device=device,
119
+ pretrained_model=path + model_name,
120
+ model_type=None,
121
+ nchan=n_channels,
122
+ ) # diam_mean=30.0,
123
+ if scale is None:
124
+ scale_model = model.diam_mean / model.diam_labels
125
+ else:
126
+ scale_model = scale * model.diam_mean / model.diam_labels
127
+
128
+ print(f"Cell size in model: {model.diam_mean} pixels...")
129
+ print(f"Cell size in training set: {model.diam_labels} pixels...")
130
+ print(f"Rescaling factor to apply: {scale_model}...")
131
+
132
+ print(f"Cellpose model {model_name} successfully loaded...")
133
+ return model, scale_model
@@ -0,0 +1,42 @@
1
+ def color_from_status(status, recently_modified=False):
2
+
3
+ if not recently_modified:
4
+ if status == 0:
5
+ return "tab:blue"
6
+ elif status == 1:
7
+ return "tab:red"
8
+ elif status == 2:
9
+ return "yellow"
10
+ else:
11
+ return "k"
12
+ else:
13
+ if status == 0:
14
+ return "tab:cyan"
15
+ elif status == 1:
16
+ return "tab:orange"
17
+ elif status == 2:
18
+ return "tab:olive"
19
+ else:
20
+ return "k"
21
+
22
+
23
+ def color_from_class(cclass, recently_modified=False):
24
+
25
+ if not recently_modified:
26
+ if cclass == 0:
27
+ return "tab:red"
28
+ elif cclass == 1:
29
+ return "tab:blue"
30
+ elif cclass == 2:
31
+ return "yellow"
32
+ else:
33
+ return "k"
34
+ else:
35
+ if cclass == 0:
36
+ return "tab:orange"
37
+ elif cclass == 1:
38
+ return "tab:cyan"
39
+ elif cclass == 2:
40
+ return "tab:olive"
41
+ else:
42
+ return "k"