small-fish-gui 1.10.4__py3-none-any.whl → 2.0.1__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 (39) hide show
  1. small_fish_gui/README.md +42 -70
  2. small_fish_gui/__init__.py +1 -1
  3. small_fish_gui/__main__.py +1 -1
  4. small_fish_gui/batch/integrity.py +8 -1
  5. small_fish_gui/batch/output.py +16 -0
  6. small_fish_gui/batch/pipeline.py +43 -24
  7. small_fish_gui/batch/prompt.py +44 -26
  8. small_fish_gui/batch/update.py +19 -3
  9. small_fish_gui/batch/utils.py +2 -0
  10. small_fish_gui/batch/values.txt +5 -5
  11. small_fish_gui/default_values.py +51 -0
  12. small_fish_gui/gui/__init__.py +3 -1
  13. small_fish_gui/gui/_napari_widgets.py +15 -4
  14. small_fish_gui/gui/layout.py +123 -54
  15. small_fish_gui/gui/napari_visualiser.py +12 -8
  16. small_fish_gui/gui/prompts.py +61 -74
  17. small_fish_gui/gui/tooltips.py +15 -0
  18. small_fish_gui/hints.py +23 -4
  19. small_fish_gui/illustrations/DetectionVitrine_filtre.png +0 -0
  20. small_fish_gui/illustrations/DetectionVitrine_signal.png +0 -0
  21. small_fish_gui/illustrations/FocciVitrine.png +0 -0
  22. small_fish_gui/illustrations/FocciVitrine_no_spots.png +0 -0
  23. small_fish_gui/illustrations/Segmentation2D.png +0 -0
  24. small_fish_gui/illustrations/Segmentation2D_with_labels.png +0 -0
  25. small_fish_gui/logo.png +0 -0
  26. small_fish_gui/{pipeline/main.py → main_menu.py} +16 -15
  27. small_fish_gui/pipeline/_colocalisation.py +60 -41
  28. small_fish_gui/pipeline/_preprocess.py +13 -12
  29. small_fish_gui/pipeline/actions.py +102 -14
  30. small_fish_gui/pipeline/detection.py +5 -1
  31. small_fish_gui/pipeline/segmentation.py +206 -73
  32. small_fish_gui/pipeline/spots.py +129 -5
  33. small_fish_gui/pipeline/testing.ipynb +1571 -2
  34. small_fish_gui/requirements.txt +4 -4
  35. {small_fish_gui-1.10.4.dist-info → small_fish_gui-2.0.1.dist-info}/METADATA +14 -16
  36. small_fish_gui-2.0.1.dist-info/RECORD +59 -0
  37. small_fish_gui-1.10.4.dist-info/RECORD +0 -49
  38. {small_fish_gui-1.10.4.dist-info → small_fish_gui-2.0.1.dist-info}/WHEEL +0 -0
  39. {small_fish_gui-1.10.4.dist-info → small_fish_gui-2.0.1.dist-info}/licenses/LICENSE +0 -0
@@ -14,6 +14,8 @@ from ._preprocess import ask_input_parameters
14
14
  from ._preprocess import map_channels, reorder_shape, reorder_image_stack
15
15
  from matplotlib.colors import ListedColormap
16
16
 
17
+ import small_fish_gui.default_values as default
18
+
17
19
  import matplotlib as mpl
18
20
  import cellpose.models as models
19
21
  import numpy as np
@@ -55,19 +57,26 @@ def launch_segmentation(user_parameters: pipeline_parameters, nucleus_label, cyt
55
57
 
56
58
  while True : # Loop if show_segmentation
57
59
  #Default parameters
58
- cyto_model_name = segmentation_parameters.setdefault('cyto_model_name', 'cyto3')
59
- cyto_size = segmentation_parameters.setdefault('cytoplasm diameter', 180)
60
- cytoplasm_channel = segmentation_parameters.setdefault('cytoplasm channel', 0)
61
- nucleus_model_name = segmentation_parameters.setdefault('nucleus_model_name', 'nuclei')
62
- nucleus_size = segmentation_parameters.setdefault('nucleus diameter', 130)
63
- nucleus_channel = segmentation_parameters.setdefault('nucleus channel', 0)
60
+ cyto_model_name = segmentation_parameters.setdefault('cyto_model_name', default.CYTO_MODEL)
61
+ cyto_size = segmentation_parameters.setdefault('cytoplasm_diameter', default.CYTO_DIAMETER)
62
+ cytoplasm_channel = segmentation_parameters.setdefault('cytoplasm_channel', default.CHANNEL)
63
+ nucleus_model_name = segmentation_parameters.setdefault('nucleus_model_name', default.NUC_MODEL)
64
+ nucleus_size = segmentation_parameters.setdefault('nucleus_diameter', default.NUC_DIAMETER)
65
+ nucleus_channel = segmentation_parameters.setdefault('nucleus_channel', default.CHANNEL)
64
66
  other_nucleus_image = segmentation_parameters.setdefault('other_nucleus_image',None)
65
67
  path = os.getcwd()
66
- show_segmentation = segmentation_parameters.setdefault('show segmentation', False)
67
- segment_only_nuclei = segmentation_parameters.setdefault('Segment only nuclei', False)
68
+ show_segmentation = segmentation_parameters.setdefault('show_segmentation', default.SHOW_SEGMENTATION)
69
+ save_segmentation_visual = segmentation_parameters.setdefault('save_segmentation_visual', default.SAVE_SEGMENTATION_VISUAL)
70
+ segment_only_nuclei = segmentation_parameters.setdefault('segment_only_nuclei', default.SEGMENT_ONLY_NUCLEI)
71
+ multichannel = segmentation_parameters.setdefault('is_multichannel', default.IS_MULTICHANNEL)
72
+ is_3D_stack = segmentation_parameters.setdefault('is_3D_stack', default.IS_3D_STACK)
73
+ anisotropy = segmentation_parameters.setdefault('anisotropy', default.ANISOTROPY)
74
+ cytoplasm_segmentation_3D = segmentation_parameters.setdefault('cytoplasm_segmentation_3D', default.DO_3D_SEMGENTATION)
75
+ nucleus_segmentation_3D = segmentation_parameters.setdefault('nucleus_segmentation_3D', default.DO_3D_SEMGENTATION)
76
+ flow_threshold = segmentation_parameters.setdefault("flow_threshold",0.4)
77
+ cellprob_threshold = segmentation_parameters.setdefault("cellprob_threshold",0)
68
78
  filename = segmentation_parameters['filename']
69
79
  available_channels = list(range(image.shape[0]))
70
- multichannel = segmentation_parameters.get('is_multichannel')
71
80
 
72
81
 
73
82
  #Ask user for parameters
@@ -82,10 +91,17 @@ def launch_segmentation(user_parameters: pipeline_parameters, nucleus_label, cyt
82
91
  nucleus_diameter_preset= nucleus_size,
83
92
  other_nucleus_image_preset=other_nucleus_image,
84
93
  saving_path_preset= path,
94
+ save_segmentation_visual_preset=save_segmentation_visual,
85
95
  show_segmentation_preset=show_segmentation,
86
96
  segment_only_nuclei_preset=segment_only_nuclei,
87
97
  filename_preset=filename,
88
98
  multichannel=multichannel,
99
+ is_3D_stack=is_3D_stack,
100
+ cytoplasm_segmentation_3D=cytoplasm_segmentation_3D,
101
+ nucleus_segmentation_3D=nucleus_segmentation_3D,
102
+ anisotropy=anisotropy,
103
+ flow_threshold=flow_threshold,
104
+ cellprob_threshold=cellprob_threshold,
89
105
  )
90
106
 
91
107
  event, values = prompt(layout)
@@ -98,56 +114,98 @@ def launch_segmentation(user_parameters: pipeline_parameters, nucleus_label, cyt
98
114
  continue
99
115
 
100
116
  #Extract parameters
101
- values = _cast_segmentation_parameters(values)
102
- do_only_nuc = values['Segment only nuclei']
117
+ values : pipeline_parameters = _cast_segmentation_parameters(values)
118
+ do_only_nuc = values['segment_only_nuclei']
103
119
  cyto_model_name = values['cyto_model_name']
104
- cyto_size = values['cytoplasm diameter']
105
- cytoplasm_channel = values['cytoplasm channel']
120
+ cyto_size = values['cytoplasm_diameter']
121
+ cytoplasm_channel = values['cytoplasm_channel']
106
122
  nucleus_model_name = values['nucleus_model_name']
107
- nucleus_size = values['nucleus diameter']
108
- nucleus_channel = values['nucleus channel']
123
+ nucleus_size = values['nucleus_diameter']
124
+ nucleus_channel = values['nucleus_channel']
109
125
  other_nucleus_image = values['other_nucleus_image']
110
126
  path = values['saving path'] if values['saving path'] != '' else None
111
- show_segmentation = values['show segmentation']
127
+ save_segmentation_visual = values['save_segmentation_visual']
128
+ show_segmentation = values['show_segmentation']
112
129
  filename = values['filename'] if type(path) != type(None) else None
113
130
  channels = [cytoplasm_channel, nucleus_channel] if multichannel else [...,...]
131
+ nucleus_segmentation_3D = values['nucleus_segmentation_3D']
132
+ cytoplasm_segmentation_3D = values['cytoplasm_segmentation_3D']
133
+ anisotropy = values['anisotropy']
134
+ cellprob_threshold_cyto = values['cellprob_threshold_cyto']
135
+ cellprob_threshold_nuc = values['cellprob_threshold_nuc']
136
+ flow_threshold_cyto = values['flow_threshold_cyto']
137
+ flow_threshold_nuc = values['flow_threshold_nuc']
114
138
 
115
139
  relaunch= False
116
140
  #Checking integrity of parameters
141
+
142
+ #flow thresholds
143
+ if type(flow_threshold_nuc) != float :
144
+ sg.popup('Invalid value for flow threshold in nuc parameters, must be a float between 0 and 1.')
145
+ values['flow_threshold_nuc'] = user_parameters.setdefault('flow_threshold_nuc',default.FLOW_THRESHOLD)
146
+ relaunch= True
147
+ if type(flow_threshold_cyto) != float :
148
+ sg.popup('Invalid value for flow threshold in cyto parameters, must be a float between 0 and 1.')
149
+ values['flow_threshold_cyto'] = user_parameters.setdefault('flow_threshold_cyto',default.FLOW_THRESHOLD)
150
+ relaunch= True
151
+
152
+ #cellprob thresholds
153
+ if type(flow_threshold_nuc) != float :
154
+ sg.popup('Invalid value for cellprob threshold in nuc parameters, must be a float between -3 and +3.')
155
+ values['flow_threshold_nuc'] = user_parameters.setdefault('flow_threshold_nuc',default.FLOW_THRESHOLD)
156
+ relaunch= True
157
+ if type(flow_threshold_cyto) != float :
158
+ sg.popup('Invalid value for cellprob threshold in cyto parameters, must be a float between -3 and +3.')
159
+ values['flow_threshold_cyto'] = user_parameters.setdefault('flow_threshold_cyto',default.FLOW_THRESHOLD)
160
+ relaunch= True
161
+
162
+
163
+ #Models
117
164
  if type(cyto_model_name) != str and not do_only_nuc:
118
165
  sg.popup('Invalid cytoplasm model name.')
119
- values['cyto_model_name'] = user_parameters.setdefault('cyto_model_name', 'cyto2')
166
+ values['cyto_model_name'] = user_parameters.setdefault('cyto_model_name', default.CYTO_MODEL)
120
167
  relaunch= True
121
168
  if multichannel :
122
169
  if cytoplasm_channel not in available_channels and not do_only_nuc:
123
- sg.popup('For given input image please select channel in {0}\ncytoplasm channel : {1}'.format(available_channels, cytoplasm_channel))
170
+ sg.popup('For given input image please select channel in {0}\ncytoplasm_channel : {1}'.format(available_channels, cytoplasm_channel))
124
171
  relaunch= True
125
- values['cytoplasm channel'] = user_parameters.setdefault('cytoplasm channel',0)
172
+ values['cytoplasm_channel'] = user_parameters.setdefault('cytoplasm_channel',default.CHANNEL)
126
173
  else :
127
174
  cytoplasm_channel = ...
128
175
 
176
+ if is_3D_stack :
177
+ try :
178
+ float(anisotropy)
179
+ if anisotropy <0 : raise ValueError()
180
+
181
+ except ValueError :
182
+ sg.popup("Anisotropy must be a positive float.")
183
+ relaunch = True
184
+ values['anisotropy'] = user_parameters.setdefault('anisotropy', default.ANISOTROPY)
185
+
129
186
  if type(cyto_size) not in [int, float] and not do_only_nuc:
130
187
  sg.popup("Incorrect cytoplasm size.")
131
188
  relaunch= True
132
- values['cytoplasm diameter'] = user_parameters.setdefault('diameter', 30)
189
+ values['cytoplasm_diameter'] = user_parameters.setdefault('cytoplasm_diameter', default.CYTO_DIAMETER)
133
190
 
134
191
  if type(nucleus_model_name) != str :
135
192
  sg.popup('Invalid nucleus model name.')
136
- values['nucleus_model_name'] = user_parameters.setdefault('nucleus_model_name', 'nuclei')
193
+ values['nucleus_model_name'] = user_parameters.setdefault('nucleus_model_name', default.NUC_MODEL)
137
194
  relaunch= True
138
195
 
139
196
  if multichannel :
140
197
  if nucleus_channel not in available_channels :
141
198
  sg.popup('For given input image please select channel in {0}\nnucleus channel : {1}'.format(available_channels, nucleus_channel))
142
199
  relaunch= True
143
- values['nucleus channel'] = user_parameters.setdefault('nucleus_channel', 0)
200
+ values['nucleus_channel'] = user_parameters.setdefault('nucleus_channel', default.CHANNEL)
144
201
  else :
145
202
  nucleus_channel = ...
146
203
 
147
204
  if type(nucleus_size) not in [int, float] :
148
205
  sg.popup("Incorrect nucleus size.")
149
206
  relaunch= True
150
- values['nucleus diameter'] = user_parameters.setdefault('nucleus diameter', 30)
207
+ values['nucleus_diameter'] = user_parameters.setdefault('nucleus_diameter', default.NUC_DIAMETER)
208
+
151
209
  if other_nucleus_image != '' :
152
210
  if not os.path.isfile(other_nucleus_image) :
153
211
  sg.popup("Nucleus image is not a file.")
@@ -202,7 +260,6 @@ def launch_segmentation(user_parameters: pipeline_parameters, nucleus_label, cyt
202
260
  nuc_path = None
203
261
  cyto_path = None
204
262
 
205
-
206
263
  cytoplasm_label, nucleus_label = cell_segmentation(
207
264
  image,
208
265
  cyto_model_name= cyto_model_name,
@@ -212,6 +269,14 @@ def launch_segmentation(user_parameters: pipeline_parameters, nucleus_label, cyt
212
269
  channels=channels,
213
270
  do_only_nuc=do_only_nuc,
214
271
  external_nucleus_image = nucleus_image,
272
+ anisotropy=anisotropy,
273
+ nucleus_3D_segmentation=nucleus_segmentation_3D,
274
+ cyto_3D_segmentation=cytoplasm_segmentation_3D,
275
+ cellprob_threshold_cyto=cellprob_threshold_cyto,
276
+ cellprob_threshold_nuc=cellprob_threshold_nuc,
277
+ flow_threshold_cyto=flow_threshold_cyto,
278
+ flow_threshold_nuc=flow_threshold_nuc,
279
+
215
280
  )
216
281
 
217
282
  finally : window.close()
@@ -222,6 +287,7 @@ def launch_segmentation(user_parameters: pipeline_parameters, nucleus_label, cyt
222
287
  nuc_label= nucleus_label,
223
288
  cyto_image=image[cytoplasm_channel],
224
289
  cyto_label=cytoplasm_label,
290
+ anisotrpy=anisotropy,
225
291
  )
226
292
 
227
293
  if nucleus_label.ndim == 3 : nucleus_label = np.max(nucleus_label, axis=0)
@@ -236,20 +302,29 @@ def launch_segmentation(user_parameters: pipeline_parameters, nucleus_label, cyt
236
302
  if event == "No" :
237
303
  continue
238
304
 
239
- if type(output_path) != type(None) :
305
+ if type(output_path) != type(None) and save_segmentation_visual:
240
306
 
241
307
  #Get backgrounds
242
308
  nuc_proj = image[nucleus_channel]
243
309
  im_proj = image[cytoplasm_channel]
244
310
  if im_proj.ndim == 3 :
245
- im_proj = stack.maximum_projection(im_proj)
311
+ im_proj = stack.mean_projection(im_proj)
246
312
  if nuc_proj.ndim == 3 :
247
- nuc_proj = stack.maximum_projection(nuc_proj)
313
+ nuc_proj = stack.mean_projection(nuc_proj)
314
+ if nucleus_label.ndim == 3 :
315
+ nucleus_label_proj = np.max(nucleus_channel,axis=0)
316
+ else :
317
+ nucleus_label_proj = nucleus_label
318
+ if cytoplasm_label.ndim == 3 :
319
+ cytoplasm_label_proj = np.max(cytoplasm_label,axis=0)
320
+ else :
321
+ cytoplasm_label_proj = cytoplasm_label
322
+
248
323
 
249
324
  #Call plots
250
- plot.plot_segmentation_boundary(nuc_proj, cytoplasm_label, nucleus_label, boundary_size=2, contrast=True, show=False, path_output=nuc_path, title= "Nucleus segmentation (blue)", remove_frame=True,)
325
+ plot.plot_segmentation_boundary(nuc_proj, cytoplasm_label_proj, nucleus_label_proj, boundary_size=2, contrast=True, show=False, path_output=nuc_path, title= "Nucleus segmentation (blue)", remove_frame=True,)
251
326
  if not do_only_nuc :
252
- plot.plot_segmentation_boundary(im_proj, cytoplasm_label, nucleus_label, boundary_size=2, contrast=True, show=False, path_output=cyto_path, title="Cytoplasm Segmentation (red)", remove_frame=True)
327
+ plot.plot_segmentation_boundary(im_proj, cytoplasm_label_proj, nucleus_label_proj, boundary_size=2, contrast=True, show=False, path_output=cyto_path, title="Cytoplasm Segmentation (red)", remove_frame=True)
253
328
  plot_labels(
254
329
  nucleus_label,
255
330
  path_output=output_path + "_nucleus_label_map.png",
@@ -257,7 +332,7 @@ def launch_segmentation(user_parameters: pipeline_parameters, nucleus_label, cyt
257
332
  )
258
333
  if not do_only_nuc :
259
334
  plot_labels(
260
- cytoplasm_label,
335
+ cytoplasm_label_proj,
261
336
  path_output=output_path + "_cytoplasm_label_map.png",
262
337
  show=False
263
338
  )
@@ -284,91 +359,140 @@ def cell_segmentation(
284
359
  image, cyto_model_name,
285
360
  nucleus_model_name,
286
361
  channels, cyto_diameter,
287
- nucleus_diameter,
362
+ nucleus_diameter,
363
+ nucleus_3D_segmentation=False,
364
+ cyto_3D_segmentation=False,
365
+ anisotropy = 1,
366
+ flow_threshold_nuc = 0.4,
367
+ flow_threshold_cyto = 0.4,
368
+ cellprob_threshold_nuc = 0.,
369
+ cellprob_threshold_cyto = 0.,
288
370
  do_only_nuc=False,
289
371
  external_nucleus_image = None,
290
372
  ) :
291
373
 
292
374
  nuc_channel = channels[1]
293
- if not do_only_nuc :
294
- cyto_channel = channels[0]
295
- if image[cyto_channel].ndim >= 3 :
296
- cyto = stack.maximum_projection(image[cyto_channel])
297
- else :
298
- cyto = image[cyto_channel]
375
+
299
376
 
300
377
  if type(external_nucleus_image) != type(None) :
301
378
  nuc = external_nucleus_image
302
379
  else :
303
380
  nuc = image[nuc_channel]
304
381
 
305
- if nuc.ndim >= 3 :
306
- nuc = stack.maximum_projection(nuc)
382
+ if nuc.ndim >= 3 and not nucleus_3D_segmentation:
383
+ nuc = stack.mean_projection(nuc)
384
+ nuc_label = _segmentate_object(
385
+ nuc,
386
+ nucleus_model_name,
387
+ nucleus_diameter,
388
+ do_3D=nucleus_3D_segmentation,
389
+ anisotropy=anisotropy,
390
+ flow_threshold= flow_threshold_nuc,
391
+ cellprob_threshold=cellprob_threshold_nuc
392
+ )
307
393
 
308
- if not do_only_nuc :
394
+ if not do_only_nuc :
395
+ cyto_channel = channels[0]
396
+ nuc = image[nuc_channel] if type(external_nucleus_image) == type(None) else external_nucleus_image
397
+
398
+ if image[cyto_channel].ndim >= 3 and not cyto_3D_segmentation:
399
+ cyto = stack.mean_projection(image[cyto_channel])
400
+ else :
401
+ cyto = image[cyto_channel]
402
+ if nuc.ndim >= 3 and not cyto_3D_segmentation:
403
+ nuc = stack.mean_projection(nuc)
404
+
309
405
  image = np.zeros(shape=(2,) + cyto.shape)
310
406
  image[0] = cyto
311
407
  image[1] = nuc
312
- image = np.moveaxis(image, source=(0,1,2), destination=(2,0,1))
408
+ source = list(range(image.ndim))
409
+ dest = source[-1:] + source[:-1]
410
+ image = np.moveaxis(image, source=range(image.ndim), destination= dest)
411
+
412
+ cytoplasm_label = _segmentate_object(
413
+ image,
414
+ cyto_model_name,
415
+ cyto_diameter,
416
+ do_3D=cyto_3D_segmentation,
417
+ anisotropy=anisotropy,
418
+ flow_threshold=flow_threshold_cyto,
419
+ cellprob_threshold=cellprob_threshold_cyto,
420
+ )
421
+
422
+ if cytoplasm_label.ndim == 3 and nuc_label.ndim == 2 :
423
+ nuc_label = np.repeat(nuc_label[np.newaxis], len(cytoplasm_label), axis= 0)
424
+ if nuc_label.ndim == 3 and cytoplasm_label.ndim == 2 :
425
+ cytoplasm_label = np.repeat(cytoplasm_label[np.newaxis], len(nuc_label), axis= 0)
313
426
 
314
- nuc_label = _segmentate_object(nuc, nucleus_model_name, nucleus_diameter, [0,0])
315
- if not do_only_nuc :
316
- cytoplasm_label = _segmentate_object(image, cyto_model_name, cyto_diameter, [1,2])
317
427
  nuc_label, cytoplasm_label = multistack.match_nuc_cell(nuc_label=nuc_label, cell_label=cytoplasm_label, single_nuc=True, cell_alone=False)
318
428
  else :
319
429
  cytoplasm_label = nuc_label
320
430
 
321
431
  return cytoplasm_label, nuc_label
322
432
 
323
- def _segmentate_object(im, model_name, object_size_px, channels = [0,0]) :
433
+ def _segmentate_object(
434
+ im : np.ndarray,
435
+ model_name : str,
436
+ object_size_px : int,
437
+ do_3D = False,
438
+ anisotropy : float = 1.0,
439
+ flow_threshold : float = 0.4,
440
+ cellprob_threshold : float = 0,
441
+ ) :
324
442
 
325
443
  model = models.CellposeModel(
326
444
  gpu= use_gpu(),
327
- model_type= model_name,
445
+ pretrained_model= model_name,
328
446
  )
329
447
 
330
- label = model.eval(
448
+ label, flow, style = model.eval(
331
449
  im,
332
450
  diameter= object_size_px,
333
- channels= channels,
334
- do_3D= False,
335
- )[0]
451
+ do_3D= do_3D,
452
+ z_axis=0 if do_3D else None,
453
+ channel_axis= im.ndim -1 if im.ndim == 3+ do_3D else None,
454
+ anisotropy=anisotropy,
455
+ flow_threshold=flow_threshold,
456
+ cellprob_threshold=cellprob_threshold,
457
+ )
458
+
336
459
  label = np.array(label, dtype= np.int64)
337
- label = remove_disjoint(label)
460
+ if not do_3D : label = remove_disjoint(label) # Too much time consuming in 3D
461
+ else : pass #TODO : filter too litle regions
338
462
 
339
463
  return label
340
464
 
341
465
  def _cast_segmentation_parameters(values:dict) :
342
466
 
343
- values.setdefault('cytoplasm channel',0)
344
- values.setdefault('nucleus channel',0)
467
+ values.setdefault('cytoplasm_channel',0)
468
+ values.setdefault('nucleus_channel',0)
345
469
 
470
+ cast_rules = {
471
+ 'cytoplasm_diameter' : int,
472
+ 'nucleus_diameter' : int,
473
+ 'cytoplasm_channel' : int,
474
+ 'nucleus_channel' : int,
475
+ 'anisotropy' : float,
476
+ 'flow_threshold_cyto' : float,
477
+ 'cellprob_threshold_cyto' : float,
478
+ 'flow_threshold_nuc' : float,
479
+ 'cellprob_threshold_nuc' : float,
480
+
481
+ }
482
+
483
+ for key, constructor in cast_rules.items() :
484
+ try :
485
+ if key in values.keys() : values[key] = constructor(values[key])
486
+ except ValueError :
487
+ pass
488
+
489
+ #None if default
346
490
  if values['cyto_model_name'] == '' :
347
491
  values['cyto_model_name'] = None
348
492
 
349
493
  if values['nucleus_model_name'] == '' :
350
494
  values['nucleus_model_name'] = None
351
495
 
352
- try : #cytoplasm channel
353
- values['cytoplasm channel'] = int(values['cytoplasm channel'])
354
- except ValueError :
355
- pass
356
-
357
- try : #nucleus channel
358
- values['nucleus channel'] = int(values['nucleus channel'])
359
- except ValueError :
360
- pass
361
-
362
- try : #object size
363
- values['cytoplasm diameter'] = float(values['cytoplasm diameter'])
364
- except ValueError :
365
- pass
366
-
367
- try : #object size
368
- values['nucleus diameter'] = float(values['nucleus diameter'])
369
- except ValueError :
370
- pass
371
-
372
496
  return values
373
497
 
374
498
  def remove_disjoint(image):
@@ -450,6 +574,15 @@ def plot_segmentation(
450
574
  if nuc_image.ndim == 3 :
451
575
  nuc_image = np.max(nuc_image,axis=0)
452
576
 
577
+ if cyto_label.ndim == 3 :
578
+ cyto_label = np.max(cyto_label,axis=0)
579
+
580
+ if nuc_label.ndim == 3 :
581
+ nuc_label = np.max(nuc_label,axis=0)
582
+
583
+ if cyto_image.ndim == 3 :
584
+ cyto_image = np.max(cyto_image,axis=0)
585
+
453
586
  plot.plot_segmentation_boundary(
454
587
  image=nuc_image,
455
588
  nuc_label= nuc_label,
@@ -31,7 +31,6 @@ def launch_spots_extraction(
31
31
  filename= user_parameters['spots_filename'],
32
32
  do_excel=user_parameters['do_spots_excel'],
33
33
  do_csv=user_parameters['do_spots_csv'],
34
- do_feather=user_parameters['do_spots_feather'],
35
34
  )
36
35
 
37
36
  if did_output : print("Individual spots extracted at {0}".format(user_parameters['spots_extraction_folder']))
@@ -41,8 +40,8 @@ def compute_Spots(
41
40
  image : np.ndarray,
42
41
  spots : np.ndarray,
43
42
  cluster_id : np.ndarray,
44
- nucleus_label = None,
45
- cell_label = None,
43
+ nucleus_label : np.ndarray = None,
44
+ cell_label : np.ndarray = None,
46
45
  ) :
47
46
 
48
47
  if len(spots) == 0 :
@@ -55,11 +54,17 @@ def compute_Spots(
55
54
  index = tuple(index)
56
55
  spot_intensities_list = list(image[index])
57
56
  if type(nucleus_label) != type(None) :
58
- in_nuc_list = list(nucleus_label.astype(bool)[index[-2:]]) #Only plane coordinates
57
+ if nucleus_label.ndim == 2 :
58
+ in_nuc_list = list(nucleus_label.astype(bool)[index[-2:]]) #Only plane coordinates
59
+ else :
60
+ in_nuc_list = list(nucleus_label.astype(bool)[index])
59
61
  else :
60
62
  in_nuc_list = np.NaN
61
63
  if type(cell_label) != type(None) :
62
- cell_label_list = list(cell_label[index[-2:]]) #Only plane coordinates
64
+ if cell_label.ndim == 3 :
65
+ cell_label_list = list(cell_label[index])
66
+ else :
67
+ cell_label_list = list(cell_label[index[-2:]]) #Only plane coordinates
63
68
  else :
64
69
  cell_label_list = np.NaN
65
70
  id_list = np.arange(len(spots))
@@ -78,4 +83,123 @@ def compute_Spots(
78
83
 
79
84
  return Spots
80
85
 
86
+ def load_spots(
87
+ table_path : str
88
+ ) -> pd.DataFrame :
89
+
90
+ if table_path.endswith('.csv') :
91
+ Spots = pd.read_csv(table_path, sep= ";")
92
+ elif table_path.endswith('.xlsx') or table_path.endswith('.xls') :
93
+ Spots = pd.read_excel(table_path)
94
+ elif table_path.endswith('.feather') :
95
+ Spots = pd.read_feather(table_path)
96
+ else :
97
+ raise ValueError("Table format not recognized. Please use .csv, .xlsx or .feather files.")
98
+
99
+ if "coordinates" in Spots.columns :
100
+ pass
101
+ elif "y" in Spots.columns and "x" in Spots.columns :
102
+ if "z" in Spots.columns :
103
+ pass
104
+ else :
105
+ pass
106
+ else :
107
+ raise ValueError("Coordinates information not found in table. Please provide a 'coordinates' column with tuples (z,y,x) or (y,x) or 'y' and 'x' columns.")
108
+
109
+ return Spots
110
+
111
+ def reconstruct_acquisition_data(
112
+ Spots : pd.DataFrame,
113
+ max_id : int,
114
+ filename : str,
115
+ voxel_size : 'tuple[int]'
116
+ ) -> pd.DataFrame:
117
+ """
118
+ Aim : creating a acquisition to add to result_dataframe from loaded spots for co-localization use
119
+
120
+ **Needed keys for colocalization**
121
+ * acquisition_id
122
+ * name
123
+ * spots : np.ndarray[int] (nb_spots, nb_coordinates)
124
+ * clusters : np.ndarray[int] (nb_cluster, nb_coordinate + 2)
125
+ * spots_cluster_id : list[int]
126
+ * voxel_size : tuple[int]
127
+ * shape : tuple[int]
128
+ * filename : str
129
+ """
130
+
131
+ spots = reconstruct_spots(Spots['coordinates'])
132
+ has_clusters = not Spots['cluster_id'].isna().all()
133
+ spot_number = len(spots)
134
+
135
+ if has_clusters :
136
+
137
+ clusters = np.empty(shape=(0,5), dtype=int) #useless for coloc only needded in columns to enable coloc on clusters
138
+ spot_cluster_id = Spots['cluster_id'].to_numpy().astype(int).tolist()
139
+
140
+ new_acquisition = pd.DataFrame({
141
+ 'acquisition_id' : [max_id + 1],
142
+ 'name' : ["loaded_spots_{}".format(max_id + 1)],
143
+ 'threshold' : [0],
144
+ 'spots' : [spots],
145
+ 'clusters' : [clusters],
146
+ 'spots_cluster_id' : [spot_cluster_id],
147
+ 'spot_number' : [spot_number],
148
+ 'filename' : [filename],
149
+ 'voxel_size' : [voxel_size],
150
+ })
151
+ else :
152
+ new_acquisition = pd.DataFrame({
153
+ 'acquisition_id' : [max_id + 1],
154
+ 'name' : ["loaded_spots_{}".format(max_id + 1)],
155
+ 'threshold' : [0],
156
+ 'spots' : [spots],
157
+ 'spot_number' : [spot_number],
158
+ 'filename' : [filename],
159
+ 'voxel_size' : [voxel_size],
160
+ })
161
+
162
+ return new_acquisition
163
+
164
+ def reconstruct_spots(
165
+ coordinates_serie : pd.Series
166
+ ) :
167
+ spots = coordinates_serie.str.replace('(','').str.replace(')','')
168
+ spots = spots.str.split(',')
169
+ spots = spots.apply(np.array)
170
+ spots = np.array(spots.to_list()).astype(int)
171
+
172
+ return spots
173
+
174
+
175
+ def reconstruct_cell_data(
176
+ Spots : pd.DataFrame,
177
+ max_id : int,
178
+ ) :
179
+
180
+ has_cluster = not Spots['cluster_id'].isna().all()
181
+ coordinates = reconstruct_spots(Spots['coordinates'])
182
+ Spots['coordinates'] = pd.Series(coordinates.tolist(), dtype=object, index= Spots.index)
183
+
184
+ cell = Spots.groupby('cell_label')['coordinates'].apply(np.array).rename("rna_coords").reset_index(drop=False)
185
+
186
+ #Handle cells with no spots
187
+ na_mask =cell[cell['rna_coords'].isna()].index
188
+ cell.loc[na_mask, ['rna_coords']] = pd.Series([np.empty(shape=(0,3))]*len(na_mask), dtype= object, index=na_mask)
189
+
190
+ cell['total_rna_number'] = cell['rna_coords'].apply(len)
191
+
192
+ if has_cluster :
193
+ cell['clustered_spots_coords'] = Spots[Spots['cluster_id'] !=-1].groupby('cell_label')['coordinates'].apply(np.array).rename("clustered_spots_coords")
194
+
195
+ #Handle cells with no clusters
196
+ na_mask =cell[cell['clustered_spots_coords'].isna()].index
197
+ cell.loc[na_mask, ['clustered_spots_coords']] = pd.Series([np.empty(shape=(0,3))]*len(na_mask), dtype= object, index=na_mask)
198
+
199
+ cell['clustered_spot_number'] = cell['clustered_spots_coords'].apply(len)
200
+
201
+ cell['acquisition_id'] = max_id + 1
202
+ cell['name'] = "loaded_spots_{}".format(max_id + 1)
203
+ cell = cell.rename(columns={"cell_label": "cell_id"})
81
204
 
205
+ return cell