celldetective 1.4.2__py3-none-any.whl → 1.5.0b0__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 (151) 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 +304 -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/measure_cells.py +565 -0
  81. celldetective/processes/segment_cells.py +760 -0
  82. celldetective/processes/track_cells.py +435 -0
  83. celldetective/processes/train_segmentation_model.py +694 -0
  84. celldetective/processes/train_signal_model.py +265 -0
  85. celldetective/processes/unified_process.py +292 -0
  86. celldetective/regionprops/_regionprops.py +358 -317
  87. celldetective/relative_measurements.py +987 -710
  88. celldetective/scripts/measure_cells.py +313 -212
  89. celldetective/scripts/measure_relative.py +90 -46
  90. celldetective/scripts/segment_cells.py +165 -104
  91. celldetective/scripts/segment_cells_thresholds.py +96 -68
  92. celldetective/scripts/track_cells.py +198 -149
  93. celldetective/scripts/train_segmentation_model.py +324 -201
  94. celldetective/scripts/train_signal_model.py +87 -45
  95. celldetective/segmentation.py +844 -749
  96. celldetective/signals.py +3514 -2861
  97. celldetective/tracking.py +30 -15
  98. celldetective/utils/__init__.py +0 -0
  99. celldetective/utils/cellpose_utils/__init__.py +133 -0
  100. celldetective/utils/color_mappings.py +42 -0
  101. celldetective/utils/data_cleaning.py +630 -0
  102. celldetective/utils/data_loaders.py +450 -0
  103. celldetective/utils/dataset_helpers.py +207 -0
  104. celldetective/utils/downloaders.py +197 -0
  105. celldetective/utils/event_detection/__init__.py +8 -0
  106. celldetective/utils/experiment.py +1782 -0
  107. celldetective/utils/image_augmenters.py +308 -0
  108. celldetective/utils/image_cleaning.py +74 -0
  109. celldetective/utils/image_loaders.py +926 -0
  110. celldetective/utils/image_transforms.py +335 -0
  111. celldetective/utils/io.py +62 -0
  112. celldetective/utils/mask_cleaning.py +348 -0
  113. celldetective/utils/mask_transforms.py +5 -0
  114. celldetective/utils/masks.py +184 -0
  115. celldetective/utils/maths.py +351 -0
  116. celldetective/utils/model_getters.py +325 -0
  117. celldetective/utils/model_loaders.py +296 -0
  118. celldetective/utils/normalization.py +380 -0
  119. celldetective/utils/parsing.py +465 -0
  120. celldetective/utils/plots/__init__.py +0 -0
  121. celldetective/utils/plots/regression.py +53 -0
  122. celldetective/utils/resources.py +34 -0
  123. celldetective/utils/stardist_utils/__init__.py +104 -0
  124. celldetective/utils/stats.py +90 -0
  125. celldetective/utils/types.py +21 -0
  126. {celldetective-1.4.2.dist-info → celldetective-1.5.0b0.dist-info}/METADATA +1 -1
  127. celldetective-1.5.0b0.dist-info/RECORD +187 -0
  128. {celldetective-1.4.2.dist-info → celldetective-1.5.0b0.dist-info}/WHEEL +1 -1
  129. tests/gui/test_new_project.py +129 -117
  130. tests/gui/test_project.py +127 -79
  131. tests/test_filters.py +39 -15
  132. tests/test_notebooks.py +8 -0
  133. tests/test_tracking.py +232 -13
  134. tests/test_utils.py +123 -77
  135. celldetective/gui/base_components.py +0 -23
  136. celldetective/gui/layouts.py +0 -1602
  137. celldetective/gui/processes/compute_neighborhood.py +0 -594
  138. celldetective/gui/processes/measure_cells.py +0 -360
  139. celldetective/gui/processes/segment_cells.py +0 -499
  140. celldetective/gui/processes/track_cells.py +0 -303
  141. celldetective/gui/processes/train_segmentation_model.py +0 -270
  142. celldetective/gui/processes/train_signal_model.py +0 -108
  143. celldetective/gui/table_ops/merge_groups.py +0 -118
  144. celldetective/gui/viewers.py +0 -1354
  145. celldetective/io.py +0 -3663
  146. celldetective/utils.py +0 -3108
  147. celldetective-1.4.2.dist-info/RECORD +0 -123
  148. /celldetective/{gui/processes → processes}/downloader.py +0 -0
  149. {celldetective-1.4.2.dist-info → celldetective-1.5.0b0.dist-info}/entry_points.txt +0 -0
  150. {celldetective-1.4.2.dist-info → celldetective-1.5.0b0.dist-info}/licenses/LICENSE +0 -0
  151. {celldetective-1.4.2.dist-info → celldetective-1.5.0b0.dist-info}/top_level.txt +0 -0
@@ -5,10 +5,34 @@ Copright © 2022 Laboratoire Adhesion et Inflammation, Authored by Remy Torro.
5
5
  import argparse
6
6
  import os
7
7
  import json
8
- from celldetective.io import auto_load_number_of_frames, load_frames, fix_missing_labels, locate_labels, extract_position_name
9
- from celldetective.utils import extract_experiment_channels, config_section_to_dict, _get_img_num_per_channel, extract_experiment_channels
10
- from celldetective.utils import _remove_invalid_cols, remove_redundant_features, remove_trajectory_measurements, _extract_coordinates_from_features
11
- from celldetective.measure import drop_tonal_features, measure_features, measure_isotropic_intensity, center_of_mass_to_abs_coordinates, measure_radial_distance_to_center
8
+ from celldetective.utils.image_loaders import (
9
+ locate_labels,
10
+ auto_load_number_of_frames,
11
+ load_frames,
12
+ fix_missing_labels,
13
+ _get_img_num_per_channel,
14
+ )
15
+ from celldetective.utils.experiment import (
16
+ extract_position_name,
17
+ extract_experiment_channels,
18
+ )
19
+ from celldetective import (
20
+ extract_experiment_channels,
21
+ )
22
+ from celldetective.utils.parsing import config_section_to_dict
23
+ from celldetective.utils.data_cleaning import (
24
+ _remove_invalid_cols,
25
+ _extract_coordinates_from_features,
26
+ remove_redundant_features,
27
+ remove_trajectory_measurements,
28
+ )
29
+ from celldetective.measure import (
30
+ drop_tonal_features,
31
+ measure_features,
32
+ measure_isotropic_intensity,
33
+ center_of_mass_to_abs_coordinates,
34
+ measure_radial_distance_to_center,
35
+ )
12
36
  from pathlib import Path, PurePath
13
37
  from glob import glob
14
38
  from tqdm import tqdm
@@ -20,38 +44,54 @@ import datetime
20
44
 
21
45
  tprint("Measure")
22
46
 
23
- parser = argparse.ArgumentParser(description="Measure features and intensities in a multichannel timeseries.",
24
- formatter_class=argparse.ArgumentDefaultsHelpFormatter)
25
- parser.add_argument('-p',"--position", required=True, help="Path to the position")
26
- parser.add_argument("--mode", default="target", choices=["target","effector","targets","effectors"],help="Cell population of interest")
47
+ parser = argparse.ArgumentParser(
48
+ description="Measure features and intensities in a multichannel timeseries.",
49
+ formatter_class=argparse.ArgumentDefaultsHelpFormatter,
50
+ )
51
+ parser.add_argument("-p", "--position", required=True, help="Path to the position")
52
+ parser.add_argument(
53
+ "--mode",
54
+ default="target",
55
+ choices=["target", "effector", "targets", "effectors"],
56
+ help="Cell population of interest",
57
+ )
27
58
  parser.add_argument("--threads", default="1", help="Number of parallel threads")
28
59
 
29
60
  args = parser.parse_args()
30
61
  process_arguments = vars(args)
31
- pos = str(process_arguments['position'])
32
- mode = str(process_arguments['mode'])
33
- n_threads = int(process_arguments['threads'])
34
-
35
- column_labels = {'track': "TRACK_ID", 'time': 'FRAME', 'x': 'POSITION_X', 'y': 'POSITION_Y'}
36
-
37
- if mode.lower()=="target" or mode.lower()=="targets":
38
- label_folder = "labels_targets"
39
- table_name = "trajectories_targets.csv"
40
- instruction_file = os.sep.join(["configs","measurement_instructions_targets.json"])
41
-
42
- elif mode.lower()=="effector" or mode.lower()=="effectors":
43
- label_folder = "labels_effectors"
44
- table_name = "trajectories_effectors.csv"
45
- instruction_file = os.sep.join(["configs","measurement_instructions_effectors.json"])
62
+ pos = str(process_arguments["position"])
63
+ mode = str(process_arguments["mode"])
64
+ n_threads = int(process_arguments["threads"])
65
+
66
+ column_labels = {
67
+ "track": "TRACK_ID",
68
+ "time": "FRAME",
69
+ "x": "POSITION_X",
70
+ "y": "POSITION_Y",
71
+ }
72
+
73
+ if mode.lower() == "target" or mode.lower() == "targets":
74
+ label_folder = "labels_targets"
75
+ table_name = "trajectories_targets.csv"
76
+ instruction_file = os.sep.join(["configs", "measurement_instructions_targets.json"])
77
+
78
+ elif mode.lower() == "effector" or mode.lower() == "effectors":
79
+ label_folder = "labels_effectors"
80
+ table_name = "trajectories_effectors.csv"
81
+ instruction_file = os.sep.join(
82
+ ["configs", "measurement_instructions_effectors.json"]
83
+ )
46
84
 
47
85
  # Locate experiment config
48
86
  parent1 = Path(pos).parent
49
87
  expfolder = parent1.parent
50
- config = PurePath(expfolder,Path("config.ini"))
51
- assert os.path.exists(config),'The configuration file for the experiment could not be located. Abort.'
88
+ config = PurePath(expfolder, Path("config.ini"))
89
+ assert os.path.exists(
90
+ config
91
+ ), "The configuration file for the experiment could not be located. Abort."
52
92
 
53
93
  print(f"Position: {extract_position_name(pos)}...")
54
- print("Configuration file: ",config)
94
+ print("Configuration file: ", config)
55
95
  print(f"Population: {mode}...")
56
96
 
57
97
  # from exp config fetch spatial calib, channel names
@@ -63,139 +103,147 @@ channel_names, channel_indices = extract_experiment_channels(expfolder)
63
103
  nbr_channels = len(channel_names)
64
104
 
65
105
  # from tracking instructions, fetch btrack config, features, haralick, clean_traj, idea: fetch custom timeline?
66
- instr_path = PurePath(expfolder,Path(f"{instruction_file}"))
67
- print('Looking for measurement instruction file...')
106
+ instr_path = PurePath(expfolder, Path(f"{instruction_file}"))
107
+ print("Looking for measurement instruction file...")
68
108
 
69
109
  if os.path.exists(instr_path):
70
110
 
71
- with open(instr_path, 'r') as f:
72
- instructions = json.load(f)
73
- print(f"Measurement instruction file successfully loaded...")
74
- print(f"Instructions: {instructions}...")
75
-
76
- if 'background_correction' in instructions:
77
- background_correction = instructions['background_correction']
78
- else:
79
- background_correction = None
80
-
81
- if 'features' in instructions:
82
- features = instructions['features']
83
- else:
84
- features = None
85
-
86
- if 'border_distances' in instructions:
87
- border_distances = instructions['border_distances']
88
- else:
89
- border_distances = None
90
-
91
- if 'spot_detection' in instructions:
92
- spot_detection = instructions['spot_detection']
93
- else:
94
- spot_detection = None
95
-
96
- if 'haralick_options' in instructions:
97
- haralick_options = instructions['haralick_options']
98
- else:
99
- haralick_options = None
100
-
101
- if 'intensity_measurement_radii' in instructions:
102
- intensity_measurement_radii = instructions['intensity_measurement_radii']
103
- else:
104
- intensity_measurement_radii = None
105
-
106
- if 'isotropic_operations' in instructions:
107
- isotropic_operations = instructions['isotropic_operations']
108
- else:
109
- isotropic_operations = None
110
-
111
- if 'clear_previous' in instructions:
112
- clear_previous = instructions['clear_previous']
113
- else:
114
- clear_previous = True
111
+ with open(instr_path, "r") as f:
112
+ instructions = json.load(f)
113
+ print(f"Measurement instruction file successfully loaded...")
114
+ print(f"Instructions: {instructions}...")
115
+
116
+ if "background_correction" in instructions:
117
+ background_correction = instructions["background_correction"]
118
+ else:
119
+ background_correction = None
120
+
121
+ if "features" in instructions:
122
+ features = instructions["features"]
123
+ else:
124
+ features = None
125
+
126
+ if "border_distances" in instructions:
127
+ border_distances = instructions["border_distances"]
128
+ else:
129
+ border_distances = None
130
+
131
+ if "spot_detection" in instructions:
132
+ spot_detection = instructions["spot_detection"]
133
+ else:
134
+ spot_detection = None
135
+
136
+ if "haralick_options" in instructions:
137
+ haralick_options = instructions["haralick_options"]
138
+ else:
139
+ haralick_options = None
140
+
141
+ if "intensity_measurement_radii" in instructions:
142
+ intensity_measurement_radii = instructions["intensity_measurement_radii"]
143
+ else:
144
+ intensity_measurement_radii = None
145
+
146
+ if "isotropic_operations" in instructions:
147
+ isotropic_operations = instructions["isotropic_operations"]
148
+ else:
149
+ isotropic_operations = None
150
+
151
+ if "clear_previous" in instructions:
152
+ clear_previous = instructions["clear_previous"]
153
+ else:
154
+ clear_previous = True
115
155
 
116
156
  else:
117
- print('No measurement instructions found. Use default measurements.')
118
- features = ['area', 'intensity_mean']
119
- border_distances = None
120
- haralick_options = None
121
- clear_previous = False
122
- background_correction = None
123
- spot_detection = None
124
- intensity_measurement_radii = 10
125
- isotropic_operations = ['mean']
157
+ print("No measurement instructions found. Use default measurements.")
158
+ features = ["area", "intensity_mean"]
159
+ border_distances = None
160
+ haralick_options = None
161
+ clear_previous = False
162
+ background_correction = None
163
+ spot_detection = None
164
+ intensity_measurement_radii = 10
165
+ isotropic_operations = ["mean"]
126
166
 
127
167
  if features is None:
128
- features = []
168
+ features = []
129
169
 
130
170
  # from pos fetch labels
131
- label_path = natsorted(glob(os.sep.join([pos, label_folder, '*.tif'])))
132
- if len(label_path)>0:
133
- print(f"Found {len(label_path)} segmented frames...")
171
+ label_path = natsorted(glob(os.sep.join([pos, label_folder, "*.tif"])))
172
+ if len(label_path) > 0:
173
+ print(f"Found {len(label_path)} segmented frames...")
134
174
  else:
135
- print(f"No segmented frames have been found. Please run segmentation first, skipping... Features cannot be computed.")
136
- features = None
137
- haralick_options = None
138
- border_distances = None
139
- label_path = None
175
+ print(
176
+ f"No segmented frames have been found. Please run segmentation first, skipping... Features cannot be computed."
177
+ )
178
+ features = None
179
+ haralick_options = None
180
+ border_distances = None
181
+ label_path = None
140
182
 
141
183
  # Do this if features or Haralick is not None, else don't need stack
142
184
  try:
143
- file = glob(pos+os.sep.join(["movie", f"{movie_prefix}*.tif"]))[0]
185
+ file = glob(pos + os.sep.join(["movie", f"{movie_prefix}*.tif"]))[0]
144
186
  except IndexError:
145
- print('Movie could not be found. Check the prefix. If you intended to measure texture or tone, this will not be performed.')
146
- file = None
147
- haralick_option = None
148
- features = drop_tonal_features(features)
187
+ print(
188
+ "Movie could not be found. Check the prefix. If you intended to measure texture or tone, this will not be performed."
189
+ )
190
+ file = None
191
+ haralick_option = None
192
+ features = drop_tonal_features(features)
149
193
 
150
194
  # Load trajectories, add centroid if not in trajectory
151
- trajectories = pos+os.sep.join(['output','tables', table_name])
195
+ trajectories = pos + os.sep.join(["output", "tables", table_name])
152
196
  if os.path.exists(trajectories):
153
- print('A trajectory table was found...')
154
- trajectories = pd.read_csv(trajectories)
155
- if 'TRACK_ID' not in list(trajectories.columns):
156
- do_iso_intensities = False
157
- intensity_measurement_radii = None
158
- if clear_previous:
159
- print('No TRACK_ID... Clear previous measurements...')
160
- trajectories = None #remove_trajectory_measurements(trajectories, column_labels)
161
- do_features = True
162
- features += ['centroid']
163
- else:
164
- if clear_previous:
165
- print('TRACK_ID found... Clear previous measurements...')
166
- trajectories = remove_trajectory_measurements(trajectories, column_labels)
197
+ print("A trajectory table was found...")
198
+ trajectories = pd.read_csv(trajectories)
199
+ if "TRACK_ID" not in list(trajectories.columns):
200
+ do_iso_intensities = False
201
+ intensity_measurement_radii = None
202
+ if clear_previous:
203
+ print("No TRACK_ID... Clear previous measurements...")
204
+ trajectories = (
205
+ None # remove_trajectory_measurements(trajectories, column_labels)
206
+ )
207
+ do_features = True
208
+ features += ["centroid"]
209
+ else:
210
+ if clear_previous:
211
+ print("TRACK_ID found... Clear previous measurements...")
212
+ trajectories = remove_trajectory_measurements(trajectories, column_labels)
167
213
  else:
168
- trajectories = None
169
- do_features = True
170
- features += ['centroid']
171
- do_iso_intensities = False
214
+ trajectories = None
215
+ do_features = True
216
+ features += ["centroid"]
217
+ do_iso_intensities = False
172
218
 
173
219
 
174
220
  len_movie_auto = auto_load_number_of_frames(file)
175
221
  if len_movie_auto is not None:
176
- len_movie = len_movie_auto
222
+ len_movie = len_movie_auto
177
223
 
178
224
  if label_path is not None and file is not None:
179
- test = len(label_path)==len_movie
180
- if not test:
181
- fix_missing_labels(pos, population=mode, prefix=movie_prefix)
182
- label_path = natsorted(glob(os.sep.join([pos, label_folder, '*.tif'])))
225
+ test = len(label_path) == len_movie
226
+ if not test:
227
+ fix_missing_labels(pos, population=mode, prefix=movie_prefix)
228
+ label_path = natsorted(glob(os.sep.join([pos, label_folder, "*.tif"])))
183
229
 
184
230
  img_num_channels = _get_img_num_per_channel(channel_indices, len_movie, nbr_channels)
185
231
 
186
232
 
187
233
  # Test what to do
188
234
  if (file is None) or (intensity_measurement_radii is None):
189
- do_iso_intensities = False
190
- print('Either no image, no positions or no radii were provided... Isotropic intensities will not be computed...')
235
+ do_iso_intensities = False
236
+ print(
237
+ "Either no image, no positions or no radii were provided... Isotropic intensities will not be computed..."
238
+ )
191
239
  else:
192
- do_iso_intensities = True
240
+ do_iso_intensities = True
193
241
 
194
242
  if label_path is None:
195
- do_features = False
196
- print('No labels were provided... Features will not be computed...')
243
+ do_features = False
244
+ print("No labels were provided... Features will not be computed...")
197
245
  else:
198
- do_features = True
246
+ do_features = True
199
247
 
200
248
 
201
249
  #######################################
@@ -204,76 +252,127 @@ else:
204
252
 
205
253
  timestep_dataframes = []
206
254
  if trajectories is None:
207
- print('Use features as a substitute for the trajectory table.')
208
- if 'label' not in features:
209
- features.append('label')
255
+ print("Use features as a substitute for the trajectory table.")
256
+ if "label" not in features:
257
+ features.append("label")
210
258
 
211
259
  if label_path is not None:
212
- label_names = [os.path.split(lbl)[-1] for lbl in label_path]
213
-
214
-
215
- features_log=f'features: {features}'
216
- border_distances_log=f'border_distances: {border_distances}'
217
- haralick_options_log=f'haralick_options: {haralick_options}'
218
- background_correction_log=f'background_correction: {background_correction}'
219
- spot_detection_log=f'spot_detection: {spot_detection}'
220
- intensity_measurement_radii_log=f'intensity_measurement_radii: {intensity_measurement_radii}'
221
- isotropic_options_log=f'isotropic_operations: {isotropic_operations} \n'
222
- log='\n'.join([features_log,border_distances_log,haralick_options_log,background_correction_log,spot_detection_log,intensity_measurement_radii_log,isotropic_options_log])
223
- with open(pos + f'log_{mode}.json', 'a') as f:
224
- f.write(f'{datetime.datetime.now()} MEASURE \n')
225
- f.write(log+'\n')
260
+ label_names = [os.path.split(lbl)[-1] for lbl in label_path]
261
+
262
+
263
+ features_log = f"features: {features}"
264
+ border_distances_log = f"border_distances: {border_distances}"
265
+ haralick_options_log = f"haralick_options: {haralick_options}"
266
+ background_correction_log = f"background_correction: {background_correction}"
267
+ spot_detection_log = f"spot_detection: {spot_detection}"
268
+ intensity_measurement_radii_log = (
269
+ f"intensity_measurement_radii: {intensity_measurement_radii}"
270
+ )
271
+ isotropic_options_log = f"isotropic_operations: {isotropic_operations} \n"
272
+ log = "\n".join(
273
+ [
274
+ features_log,
275
+ border_distances_log,
276
+ haralick_options_log,
277
+ background_correction_log,
278
+ spot_detection_log,
279
+ intensity_measurement_radii_log,
280
+ isotropic_options_log,
281
+ ]
282
+ )
283
+ with open(pos + f"log_{mode}.json", "a") as f:
284
+ f.write(f"{datetime.datetime.now()} MEASURE \n")
285
+ f.write(log + "\n")
226
286
 
227
287
 
228
288
  def measure_index(indices):
229
289
 
230
- #global column_labels
231
-
232
- for t in tqdm(indices,desc="frame"):
233
-
234
- if file is not None:
235
- img = load_frames(img_num_channels[:,t], file, scale=None, normalize_input=False)
236
-
237
- if label_path is not None:
238
-
239
- lbl = locate_labels(pos, population=mode, frames=t)
240
- if lbl is None:
241
- continue
242
-
243
- if trajectories is not None:
244
-
245
- positions_at_t = trajectories.loc[trajectories[column_labels['time']]==t].copy()
246
-
247
- if do_features:
248
- feature_table = measure_features(img, lbl, features=features, border_dist=border_distances,
249
- channels=channel_names, haralick_options=haralick_options, verbose=False,
250
- normalisation_list=background_correction, spot_detection=spot_detection)
251
- if trajectories is None:
252
- positions_at_t = _extract_coordinates_from_features(feature_table, timepoint=t)
253
- column_labels = {'track': "ID", 'time': column_labels['time'], 'x': column_labels['x'],
254
- 'y': column_labels['y']}
255
- feature_table.rename(columns={'centroid-1': 'POSITION_X', 'centroid-0': 'POSITION_Y'}, inplace=True)
256
-
257
- if do_iso_intensities and not trajectories is None:
258
- iso_table = measure_isotropic_intensity(positions_at_t, img, channels=channel_names, intensity_measurement_radii=intensity_measurement_radii, column_labels=column_labels, operations=isotropic_operations, verbose=False)
259
-
260
- if do_iso_intensities and do_features and not trajectories is None:
261
- measurements_at_t = iso_table.merge(feature_table, how='outer', on='class_id',suffixes=('_delme', ''))
262
- measurements_at_t = measurements_at_t[[c for c in measurements_at_t.columns if not c.endswith('_delme')]]
263
- elif do_iso_intensities * (not do_features) * (not trajectories is None):
264
- measurements_at_t = iso_table
265
- elif do_features:
266
- measurements_at_t = positions_at_t.merge(feature_table, how='outer', on='class_id',suffixes=('_delme', ''))
267
- measurements_at_t = measurements_at_t[[c for c in measurements_at_t.columns if not c.endswith('_delme')]]
268
-
269
- measurements_at_t = center_of_mass_to_abs_coordinates(measurements_at_t)
270
- measurements_at_t = measure_radial_distance_to_center(measurements_at_t, volume=img.shape, column_labels=column_labels)
271
-
272
- if measurements_at_t is not None:
273
- measurements_at_t[column_labels['time']] = t
274
- timestep_dataframes.append(measurements_at_t)
275
-
276
- return
290
+ # global column_labels
291
+
292
+ for t in tqdm(indices, desc="frame"):
293
+
294
+ if file is not None:
295
+ img = load_frames(
296
+ img_num_channels[:, t], file, scale=None, normalize_input=False
297
+ )
298
+
299
+ if label_path is not None:
300
+
301
+ lbl = locate_labels(pos, population=mode, frames=t)
302
+ if lbl is None:
303
+ continue
304
+
305
+ if trajectories is not None:
306
+
307
+ positions_at_t = trajectories.loc[
308
+ trajectories[column_labels["time"]] == t
309
+ ].copy()
310
+
311
+ if do_features:
312
+ feature_table = measure_features(
313
+ img,
314
+ lbl,
315
+ features=features,
316
+ border_dist=border_distances,
317
+ channels=channel_names,
318
+ haralick_options=haralick_options,
319
+ verbose=False,
320
+ normalisation_list=background_correction,
321
+ spot_detection=spot_detection,
322
+ )
323
+ if trajectories is None:
324
+ positions_at_t = _extract_coordinates_from_features(
325
+ feature_table, timepoint=t
326
+ )
327
+ column_labels = {
328
+ "track": "ID",
329
+ "time": column_labels["time"],
330
+ "x": column_labels["x"],
331
+ "y": column_labels["y"],
332
+ }
333
+ feature_table.rename(
334
+ columns={"centroid-1": "POSITION_X", "centroid-0": "POSITION_Y"},
335
+ inplace=True,
336
+ )
337
+
338
+ if do_iso_intensities and not trajectories is None:
339
+ iso_table = measure_isotropic_intensity(
340
+ positions_at_t,
341
+ img,
342
+ channels=channel_names,
343
+ intensity_measurement_radii=intensity_measurement_radii,
344
+ column_labels=column_labels,
345
+ operations=isotropic_operations,
346
+ verbose=False,
347
+ )
348
+
349
+ if do_iso_intensities and do_features and not trajectories is None:
350
+ measurements_at_t = iso_table.merge(
351
+ feature_table, how="outer", on="class_id", suffixes=("_delme", "")
352
+ )
353
+ measurements_at_t = measurements_at_t[
354
+ [c for c in measurements_at_t.columns if not c.endswith("_delme")]
355
+ ]
356
+ elif do_iso_intensities * (not do_features) * (not trajectories is None):
357
+ measurements_at_t = iso_table
358
+ elif do_features:
359
+ measurements_at_t = positions_at_t.merge(
360
+ feature_table, how="outer", on="class_id", suffixes=("_delme", "")
361
+ )
362
+ measurements_at_t = measurements_at_t[
363
+ [c for c in measurements_at_t.columns if not c.endswith("_delme")]
364
+ ]
365
+
366
+ measurements_at_t = center_of_mass_to_abs_coordinates(measurements_at_t)
367
+ measurements_at_t = measure_radial_distance_to_center(
368
+ measurements_at_t, volume=img.shape, column_labels=column_labels
369
+ )
370
+
371
+ if measurements_at_t is not None:
372
+ measurements_at_t[column_labels["time"]] = t
373
+ timestep_dataframes.append(measurements_at_t)
374
+
375
+ return
277
376
 
278
377
 
279
378
  print(f"Starting the measurements with {n_threads} thread(s)...")
@@ -285,33 +384,35 @@ indices = list(range(img_num_channels.shape[1]))
285
384
  chunks = np.array_split(indices, n_threads)
286
385
 
287
386
  with concurrent.futures.ThreadPoolExecutor() as executor:
288
- results = executor.map(measure_index, chunks)
289
- try:
290
- for i,return_value in enumerate(results):
291
- print(f"Thread {i} output check: ",return_value)
292
- except Exception as e:
293
- print("Exception: ", e)
387
+ results = executor.map(measure_index, chunks)
388
+ try:
389
+ for i, return_value in enumerate(results):
390
+ print(f"Thread {i} output check: ", return_value)
391
+ except Exception as e:
392
+ print("Exception: ", e)
393
+
394
+ print("Done.")
294
395
 
295
- print('Done.')
296
396
 
397
+ if len(timestep_dataframes) > 0:
297
398
 
298
- if len(timestep_dataframes)>0:
299
-
300
- df = pd.concat(timestep_dataframes)
399
+ df = pd.concat(timestep_dataframes)
301
400
 
302
- if trajectories is not None:
303
- df = df.sort_values(by=[column_labels['track'],column_labels['time']])
304
- df = df.dropna(subset=[column_labels['track']])
305
- else:
306
- df['ID'] = np.arange(len(df))
307
- df = df.sort_values(by=[column_labels['time'], 'ID'])
401
+ if trajectories is not None:
402
+ df = df.sort_values(by=[column_labels["track"], column_labels["time"]])
403
+ df = df.dropna(subset=[column_labels["track"]])
404
+ else:
405
+ df["ID"] = np.arange(len(df))
406
+ df = df.sort_values(by=[column_labels["time"], "ID"])
308
407
 
309
- df = df.reset_index(drop=True)
310
- df = _remove_invalid_cols(df)
408
+ df = df.reset_index(drop=True)
409
+ df = _remove_invalid_cols(df)
311
410
 
312
- df.to_csv(pos+os.sep.join(["output", "tables", table_name]), index=False)
313
- print(f'Measurement table successfully exported in {os.sep.join(["output", "tables"])}...')
314
- print('Done.')
411
+ df.to_csv(pos + os.sep.join(["output", "tables", table_name]), index=False)
412
+ print(
413
+ f'Measurement table successfully exported in {os.sep.join(["output", "tables"])}...'
414
+ )
415
+ print("Done.")
315
416
  else:
316
- print('No measurement could be performed. Check your inputs.')
317
- print('Done.')
417
+ print("No measurement could be performed. Check your inputs.")
418
+ print("Done.")