small-fish-gui 1.3.5__py3-none-any.whl → 1.5.0__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 (35) hide show
  1. small_fish_gui/.readthedocs.yaml +21 -0
  2. small_fish_gui/README.md +2 -3
  3. small_fish_gui/__init__.py +1 -1
  4. small_fish_gui/batch/__init__.py +5 -0
  5. small_fish_gui/batch/input.py +62 -0
  6. small_fish_gui/batch/integrity.py +158 -0
  7. small_fish_gui/batch/output.py +0 -0
  8. small_fish_gui/batch/pipeline.py +218 -0
  9. small_fish_gui/batch/prompt.py +428 -0
  10. small_fish_gui/batch/test.py +10 -0
  11. small_fish_gui/batch/update.py +132 -0
  12. small_fish_gui/batch/utils.py +66 -0
  13. small_fish_gui/batch/values.py +3 -0
  14. small_fish_gui/batch/values.txt +65 -0
  15. small_fish_gui/docs/conf.py +1 -0
  16. small_fish_gui/gui/animation.py +24 -15
  17. small_fish_gui/gui/layout.py +28 -7
  18. small_fish_gui/gui/prompts.py +11 -9
  19. small_fish_gui/interface/output.py +8 -4
  20. small_fish_gui/pipeline/__init__.py +21 -0
  21. small_fish_gui/pipeline/_napari_wrapper.py +63 -90
  22. small_fish_gui/pipeline/_preprocess.py +86 -28
  23. small_fish_gui/pipeline/_segmentation.py +165 -16
  24. small_fish_gui/pipeline/actions.py +6 -1
  25. small_fish_gui/pipeline/detection.py +75 -16
  26. small_fish_gui/pipeline/main.py +12 -5
  27. small_fish_gui/pipeline/utils.py +16 -0
  28. small_fish_gui/utils.py +6 -1
  29. {small_fish_gui-1.3.5.dist-info → small_fish_gui-1.5.0.dist-info}/METADATA +1 -1
  30. small_fish_gui-1.5.0.dist-info/RECORD +52 -0
  31. small_fish_gui/gui/batch.py +0 -312
  32. small_fish_gui/gui/test.py +0 -5
  33. small_fish_gui-1.3.5.dist-info/RECORD +0 -39
  34. {small_fish_gui-1.3.5.dist-info → small_fish_gui-1.5.0.dist-info}/WHEEL +0 -0
  35. {small_fish_gui-1.3.5.dist-info → small_fish_gui-1.5.0.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,65 @@
1
+ List of keys for batch 'values' dict instance :
2
+
3
+ Batch_folder
4
+ 0
5
+ image path
6
+ 3D stack
7
+ multichannel
8
+ Dense regions deconvolution
9
+ Cluster computation
10
+ Segmentation
11
+ Napari correction
12
+ x
13
+ y
14
+ z
15
+ c
16
+ t
17
+ cyto_model_name
18
+ cytoplasm channel
19
+ cytoplasm diameter
20
+ nucleus_model_name
21
+ nucleus channel
22
+ nucleus diameter
23
+ Segment only nuclei
24
+ show segmentation
25
+ saving path
26
+ filename
27
+ threshold
28
+ threshold penalty
29
+ channel to compute
30
+ voxel_size_z
31
+ voxel_size_y
32
+ voxel_size_x
33
+ spot_size_z
34
+ spot_size_y
35
+ spot_size_x
36
+ log_kernel_size_z
37
+ log_kernel_size_y
38
+ log_kernel_size_x
39
+ minimum_distance_z
40
+ minimum_distance_y
41
+ minimum_distance_x
42
+ nucleus channel signal
43
+ alpha
44
+ beta
45
+ gamma
46
+ deconvolution_kernel_z
47
+ deconvolution_kernel_y
48
+ deconvolution_kernel_x
49
+ cluster size
50
+ min number of spots
51
+ Interactive threshold selector
52
+ spots_extraction_folder
53
+ spots_filename
54
+ do_spots_csv
55
+ do_spots_excel
56
+ do_spots_feather
57
+ output_folder
58
+ batch_name
59
+ save segmentation
60
+ save detection
61
+ extract spots
62
+ csv
63
+ xlsx
64
+ feather
65
+ 2
@@ -0,0 +1 @@
1
+ #init conf file
@@ -10,21 +10,30 @@ WAITING_TEXT = [
10
10
 
11
11
  def add_default_loading(funct) :
12
12
  def inner(*args,**kwargs) :
13
- random_text = np.random.randint(0,len(WAITING_TEXT))
14
- waiting_layout = [
15
- [sg.Text(WAITING_TEXT[random_text], font= '10')]
16
- ]
17
- window = sg.Window(
18
- title= 'small_fish',
19
- layout= waiting_layout,
20
- grab_anywhere= True,
21
- finalize=True
22
- )
23
-
24
- window.read(timeout= 30, close= False)
25
- try :
13
+
14
+ hide_loading = kwargs.get("hide_loading")
15
+ if 'hide_loading' in kwargs : del kwargs['hide_loading']
16
+
17
+ if not hide_loading :
18
+ random_text = np.random.randint(0,len(WAITING_TEXT))
19
+ waiting_layout = [
20
+ [sg.Text(WAITING_TEXT[random_text], font= '10')]
21
+ ]
22
+ window = sg.Window(
23
+ title= 'small_fish',
24
+ layout= waiting_layout,
25
+ grab_anywhere= True,
26
+ finalize=True
27
+ )
28
+
29
+ window.read(timeout= 30, close= False)
30
+ try :
31
+ return funct(*args, **kwargs)
32
+ finally :
33
+ window.close()
34
+
35
+ else :
26
36
  return funct(*args, **kwargs)
27
- finally :
28
- window.close()
37
+
29
38
  return inner
30
39
 
@@ -95,7 +95,7 @@ def path_layout(keys= [],look_for_dir = False, header=None, preset=os.getcwd())
95
95
 
96
96
  max_length = len(max(keys, key=len))
97
97
  layout = [
98
- [sg.Text(pad_right(name, max_length, ' ')), Browse(key= name, initial_folder= preset)] for name in keys
98
+ [sg.Text(pad_right(name, max_length, ' ')), Browse(key= name, target=(555666777,2), initial_folder= preset), sg.Text('')] for name in keys
99
99
  ]
100
100
  if isinstance(header, str) :
101
101
  layout = [add_header(header)] + layout
@@ -152,7 +152,20 @@ def radio_layout(values, header=None) :
152
152
  layout = [add_header(header)] + layout
153
153
  return layout
154
154
 
155
- def _segmentation_layout(multichannel, cytoplasm_model_preset= 'cyto2', nucleus_model_preset= 'nuclei', cytoplasm_channel_preset=0, nucleus_channel_preset=0, cyto_diameter_preset=30, nucleus_diameter_preset= 30, show_segmentation_preset= False, segment_only_nuclei_preset=False, saving_path_preset=os.getcwd(), filename_preset='cell_segmentation.png',) :
155
+ def _segmentation_layout(
156
+ multichannel,
157
+ cytoplasm_model_preset= 'cyto3',
158
+ nucleus_model_preset= 'nuclei',
159
+ cytoplasm_channel_preset=0,
160
+ nucleus_channel_preset=0,
161
+ other_nucleus_image_preset = None,
162
+ cyto_diameter_preset=30,
163
+ nucleus_diameter_preset= 30,
164
+ show_segmentation_preset= False,
165
+ segment_only_nuclei_preset=False,
166
+ saving_path_preset=os.getcwd(),
167
+ filename_preset='cell_segmentation.png',
168
+ ) :
156
169
 
157
170
  USE_GPU = use_gpu()
158
171
 
@@ -160,7 +173,9 @@ def _segmentation_layout(multichannel, cytoplasm_model_preset= 'cyto2', nucleus_
160
173
  if len(models_list) == 0 : models_list = ['no model found']
161
174
 
162
175
  #Header : GPU availabality
163
- layout = [[sg.Text("GPU is currently "), sg.Text('ON', text_color= 'green') if USE_GPU else sg.Text('OFF', text_color= 'red')]]
176
+ layout = [
177
+ [sg.Text("GPU is currently "), sg.Text('ON', text_color= 'green') if USE_GPU else sg.Text('OFF', text_color= 'red')]
178
+ ]
164
179
 
165
180
  #cytoplasm parameters
166
181
  layout += [
@@ -170,6 +185,8 @@ def _segmentation_layout(multichannel, cytoplasm_model_preset= 'cyto2', nucleus_
170
185
  ]
171
186
 
172
187
  if multichannel : layout += parameters_layout(['cytoplasm channel'],default_values= [cytoplasm_channel_preset])
188
+
189
+
173
190
  layout += parameters_layout(['cytoplasm diameter'], unit= "px", default_values= [cyto_diameter_preset])
174
191
  #Nucleus parameters
175
192
  layout += [
@@ -179,6 +196,7 @@ def _segmentation_layout(multichannel, cytoplasm_model_preset= 'cyto2', nucleus_
179
196
  ]
180
197
 
181
198
  if multichannel : layout += parameters_layout(['nucleus channel'], default_values= [nucleus_channel_preset])
199
+ layout += path_layout(['other_nucleus_image'], preset=other_nucleus_image_preset)
182
200
  layout += parameters_layout([ 'nucleus diameter'],unit= "px", default_values= [nucleus_diameter_preset])
183
201
  layout += bool_layout(["Segment only nuclei"], preset=segment_only_nuclei_preset)
184
202
 
@@ -246,7 +264,12 @@ def _detection_layout(
246
264
  unit = {'voxel_size' : 'nm', 'minimum_distance' : 'nm', 'spot_size' : 'radius(nm)', 'log_kernel_size' : 'px'}
247
265
 
248
266
  layout += tuple_layout(opt=opt, unit=unit, default_dict=default_dict, voxel_size= tuple_shape, spot_size= tuple_shape, log_kernel_size= tuple_shape, minimum_distance= tuple_shape)
249
-
267
+
268
+ if (do_segmentation and is_multichannel) or (is_multichannel and segmentation_done):
269
+ default_segmentation = [default_dict.setdefault('nucleus channel signal', default_dict.setdefault('nucleus channel',0))]
270
+ layout += [[sg.Text("nucleus channel signal "), sg.InputText(default_text=default_segmentation, key= "nucleus channel signal", size= 5, tooltip= "Channel from which signal will be measured for nucleus features, \nallowing you to measure signal from a different channel than the one used for segmentation.")]]
271
+ # layout += parameters_layout(['nucleus channel signal'], default_values=default_segmentation) + [[sg.Text("Channel from which signal will be measured for nucleus features, allowing you to measure signal from a different channel than the one used for segmentation.")]]
272
+
250
273
  #Deconvolution
251
274
  if do_dense_region_deconvolution :
252
275
  default_dense_regions_deconvolution = [default_dict.setdefault('alpha',0.5), default_dict.setdefault('beta',1)]
@@ -259,9 +282,7 @@ def _detection_layout(
259
282
  layout += parameters_layout(['cluster size'], unit="radius(nm)", default_values=[default_dict.setdefault('cluster size',400)])
260
283
  layout += parameters_layout(['min number of spots'], default_values=[default_dict.setdefault('min number of spots', 5)])
261
284
 
262
- if (do_segmentation and is_multichannel) or (is_multichannel and segmentation_done):
263
- default_segmentation = [default_dict.setdefault('nucleus channel signal', default_dict.setdefault('nucleus channel',0))]
264
- layout += parameters_layout(['nucleus channel signal'], default_values=default_segmentation) + [[sg.Text(" channel from which signal will be measured for nucleus features.")]]
285
+
265
286
 
266
287
  layout += bool_layout(['Interactive threshold selector'], preset=[False])
267
288
  layout += path_layout(
@@ -32,14 +32,14 @@ def prompt(layout, add_ok_cancel=True, timeout=None, timeout_key='TIMEOUT_KEY',
32
32
  window.close()
33
33
  return event, values
34
34
 
35
- def prompt_with_help(layout, help =None, add_scrollbar=True) :
35
+ def prompt_with_help(layout, help =None, add_scrollbar=True, vertical_scroll_only=True) :
36
36
  layout += [[]]
37
37
  layout += [[sg.Button('Help')]]
38
38
  layout += [[sg.Button('Ok'), sg.Button('Cancel')]]
39
39
 
40
40
  if add_scrollbar :
41
41
  size = (400,500)
42
- col_elmt = sg.Column(layout, scrollable=True, vertical_scroll_only=True, size=size)
42
+ col_elmt = sg.Column(layout, scrollable=True, vertical_scroll_only=vertical_scroll_only, size=size)
43
43
  layout = [[col_elmt]]
44
44
  else :
45
45
  size = (None,None)
@@ -280,11 +280,13 @@ def _warning_popup(warning:str) :
280
280
 
281
281
  def _sumup_df(results: pd.DataFrame) :
282
282
 
283
+ COLUMNS = ['acquisition_id','threshold', 'spot_number', 'cell_number', 'filename', 'channel to compute']
284
+
283
285
  if len(results) > 0 :
284
286
  if 'channel to compute' not in results : results['channel to compute'] = np.NaN
285
- res = results.loc[:,['acquisition_id', 'spot_number', 'cell_number', 'filename', 'channel to compute']]
287
+ res = results.loc[:,COLUMNS]
286
288
  else :
287
- res = pd.DataFrame(columns= ['acquisition_id', 'spot_number', 'cell_number', 'filename', 'channel to compute'])
289
+ res = pd.DataFrame(columns= COLUMNS)
288
290
 
289
291
  return res
290
292
 
@@ -293,14 +295,14 @@ def hub_prompt(fov_results, do_segmentation=False) :
293
295
  sumup_df = _sumup_df(fov_results)
294
296
 
295
297
  if do_segmentation :
296
- segmentation_object = sg.Text('Segmentation was performed', font='8', text_color= 'green')
298
+ segmentation_object = sg.Text('Segmentation in memory', font='8', text_color= 'green')
297
299
  else :
298
- segmentation_object = sg.Text('Segmentation was not performed', font='8', text_color= 'red')
300
+ segmentation_object = sg.Text('No segmentation in memory', font='8', text_color= 'red')
299
301
 
300
302
  layout = [
301
303
  [sg.Text('RESULTS', font= 'bold 13')],
302
304
  [sg.Table(values= list(sumup_df.values), headings= list(sumup_df.columns), row_height=20, num_rows= 5, vertical_scroll_only=False, key= "result_table"), segmentation_object],
303
- [sg.Button('Add detection'), sg.Button('Compute colocalisation')],#, sg.Button('Batch detection')],
305
+ [sg.Button('Add detection'), sg.Button('Compute colocalisation'), sg.Button('Batch detection')],
304
306
  [sg.Button('Save results', button_color= 'green'), sg.Button('Delete acquisitions',button_color= 'gray'), sg.Button('Reset segmentation',button_color= 'gray'), sg.Button('Reset results',button_color= 'gray')]
305
307
  # [sg.Button('Save results', button_color= 'green'), sg.Button('Reset results',button_color= 'gray')]
306
308
  ]
@@ -333,7 +335,7 @@ def ask_detection_confirmation(used_threshold) :
333
335
  [sg.Button("Ok"), sg.Button("Restart detection")]
334
336
  ]
335
337
 
336
- event, value = prompt(layout, add_ok_cancel=False)
338
+ event, value = prompt(layout, add_ok_cancel=False, add_scrollbar=False)
337
339
 
338
340
  if event == 'Restart detection' :
339
341
  return False
@@ -346,7 +348,7 @@ def ask_cancel_detection() :
346
348
  [sg.Button("Yes"), sg.Button("No")]
347
349
  ]
348
350
 
349
- event, value = prompt(layout, add_ok_cancel=False)
351
+ event, value = prompt(layout, add_ok_cancel=False, add_scrollbar=False)
350
352
 
351
353
  if event == 'No' :
352
354
  return False
@@ -10,9 +10,11 @@ def _cast_spot_to_tuple(spot) :
10
10
  def _cast_spots_to_tuple(spots) :
11
11
  return tuple(list(map(_cast_spot_to_tuple, spots)))
12
12
 
13
- def write_results(dataframe: pd.DataFrame, path:str, filename:str, do_excel= True, do_feather= False, do_csv=False) :
13
+ def write_results(dataframe: pd.DataFrame, path:str, filename:str, do_excel= True, do_feather= False, do_csv=False, overwrite=False) :
14
14
  check_parameter(dataframe= pd.DataFrame, path= str, filename = str, do_excel = bool, do_feather = bool)
15
15
 
16
+ dataframe.columns = dataframe.columns.astype(str) # assert columns header are string for feather
17
+
16
18
  if len(dataframe) == 0 : return True
17
19
  if not do_excel and not do_feather and not do_csv :
18
20
  return False
@@ -23,9 +25,11 @@ def write_results(dataframe: pd.DataFrame, path:str, filename:str, do_excel= Tru
23
25
 
24
26
  new_filename = filename
25
27
  i= 1
26
- while new_filename + '.xlsx' in os.listdir(path) or new_filename + '.feather' in os.listdir(path) or new_filename + '.csv' in os.listdir(path) :
27
- new_filename = filename + '_{0}'.format(i)
28
- i+=1
28
+
29
+ if not overwrite :
30
+ while new_filename + '.xlsx' in os.listdir(path) or new_filename + '.feather' in os.listdir(path) or new_filename + '.csv' in os.listdir(path) :
31
+ new_filename = filename + '_{0}'.format(i)
32
+ i+=1
29
33
 
30
34
  if 'image' in dataframe.columns :
31
35
  dataframe = dataframe.drop(['image'], axis=1)
@@ -0,0 +1,21 @@
1
+ """
2
+ Module containing main pipeline for user mode as well as calls for pipeline functions.
3
+ """
4
+
5
+ from ._preprocess import reorder_shape
6
+ from ._preprocess import reorder_image_stack
7
+ from ._preprocess import prepare_image_detection
8
+ from ._preprocess import convert_parameters_types
9
+
10
+ from ._segmentation import launch_segmentation
11
+ from ._segmentation import _cast_segmentation_parameters
12
+ from ._segmentation import cell_segmentation
13
+ from ._segmentation import plot_segmentation
14
+
15
+ from .detection import launch_detection
16
+ from .detection import launch_features_computation
17
+ from .detection import launch_cell_extraction
18
+ from .detection import get_nucleus_signal
19
+ from .detection import output_spot_tiffvisual
20
+
21
+ from .spots import launch_spots_extraction
@@ -2,59 +2,26 @@
2
2
  Contains Napari wrappers to visualise and correct spots/clusters.
3
3
  """
4
4
 
5
+ import napari.layers
6
+ import napari.types
5
7
  import numpy as np
6
- import scipy.ndimage as ndi
7
8
  import napari
8
9
 
9
- from napari.utils.events import Event
10
- from napari.layers import Points
11
10
  from bigfish.stack import check_parameter
12
11
  from ..utils import compute_anisotropy_coef
13
12
  from ._colocalisation import spots_multicolocalisation
14
13
 
15
- class Points_callback :
16
- """
17
- Custom class to handle points number evolution during Napari run.
18
- """
19
-
20
- def __init__(self, points, next_id) -> None:
21
- self.points = points
22
- self.next_id = next_id
23
- self._set_callback()
24
-
25
- def __str__(self) -> str:
26
- string = 'Points_callback object state :\ncurrent_points_number : {0}\ncurrnet_id : {1}'.format(self.current_points_number, self.next_id)
27
- return string
28
-
29
- def get_points(self) :
30
- return self.points
31
-
32
- def get_next_id(self) :
33
- return self.next_id
34
-
35
- def _set_callback(self) :
36
- def callback(event:Event) :
37
-
38
- old_points = self.get_points()
39
- new_points:Points = event.source.data
40
- features = event.source.features
41
-
42
- current_point_number = len(old_points)
43
- next_id = self.get_next_id()
44
- new_points_number = len(new_points)
45
-
46
- if new_points_number > current_point_number :
47
- features.at[new_points_number - 1, "id"] = next_id
48
- self.next_id += 1
49
-
50
- #preparing next callback
51
- self.points = new_points
52
- self._set_callback()
53
- self.callback = callback
54
-
55
14
  def _update_clusters(new_clusters: np.ndarray, spots: np.ndarray, voxel_size, cluster_size, min_spot_number, shape) :
56
15
  if len(new_clusters) == 0 : return new_clusters
57
16
  if len(spots) == 0 : return new_clusters
17
+
18
+ if len(new_clusters[0]) in [2,3] :
19
+ new_clusters = np.concatenate([
20
+ new_clusters,
21
+ np.zeros(shape=(len(new_clusters),1), dtype=int),
22
+ np.arange(len(new_clusters), dtype=int).reshape(len(new_clusters),1)
23
+ ],axis=1, dtype=int)
24
+
58
25
  assert len(new_clusters[0]) == 4 or len(new_clusters[0]) == 5, "Wrong number of coordinates for clusters should not happen."
59
26
 
60
27
  # Update spots clusters
@@ -93,45 +60,48 @@ def correct_spots(image, spots, voxel_size= (1,1,1), clusters= None, cluster_siz
93
60
  )
94
61
 
95
62
  scale = compute_anisotropy_coef(voxel_size)
96
- try :
97
- Viewer = napari.Viewer(ndisplay=2, title= 'Spot correction', axis_labels=['z','y','x'], show= False)
98
- Viewer.add_image(image, scale=scale, name= "rna signal", blending= 'additive', colormap='red', contrast_limits=[image.min(), image.max()])
99
- other_colors = ['green', 'blue', 'gray', 'cyan', 'bop orange', 'bop purple'] * ((len(other_images)-1 // 7) + 1)
100
- for im, color in zip(other_images, other_colors) :
101
- Viewer.add_image(im, scale=scale, blending='additive', visible=False, colormap=color, contrast_limits=[im.min(), im.max()])
102
- layer_offset = len(other_images)
103
-
104
- Viewer.add_points(spots, size = 5, scale=scale, face_color= 'green', opacity= 1, symbol= 'ring', name= 'single spots') # spots
105
- if type(clusters) != type(None) : Viewer.add_points(clusters[:,:dim], size = 10, scale=scale, face_color= 'blue', opacity= 0.7, symbol= 'diamond', name= 'foci', features= {"spot_number" : clusters[:,dim], "id" : clusters[:,dim+1]}, feature_defaults= {"spot_number" : 0, "id" : -1}) # cluster
106
- if type(cell_label) != type(None) and not np.array_equal(nucleus_label, cell_label) : Viewer.add_labels(cell_label, scale=scale, opacity= 0.2, blending= 'additive')
107
- if type(nucleus_label) != type(None) : Viewer.add_labels(nucleus_label, scale=scale, opacity= 0.2, blending= 'additive')
108
-
109
- #prepare cluster update
110
- if type(clusters) != type(None) :
111
- next_cluster_id = clusters[-1,-1] + 1 if len(clusters) > 0 else 1
112
- _callback = Points_callback(points=clusters[:dim], next_id=next_cluster_id)
113
- points_callback = Viewer.layers[2 + layer_offset].events.data.connect((_callback, 'callback'))
114
- Viewer.show(block=False)
115
- napari.run()
116
-
117
-
118
- new_spots = np.array(Viewer.layers[1 + layer_offset].data, dtype= int)
63
+ Viewer = napari.Viewer(ndisplay=2, title= 'Spot correction', axis_labels=['z','y','x'], show= False)
64
+ Viewer.add_image(image, scale=scale, name= "rna signal", blending= 'additive', colormap='red', contrast_limits=[image.min(), image.max()])
65
+ other_colors = ['green', 'blue', 'gray', 'cyan', 'bop orange', 'bop purple'] * ((len(other_images)-1 // 7) + 1)
66
+ for im, color in zip(other_images, other_colors) :
67
+ Viewer.add_image(im, scale=scale, blending='additive', visible=False, colormap=color, contrast_limits=[im.min(), im.max()])
68
+ layer_offset = len(other_images)
69
+
70
+ Viewer.add_points( # single molecule spots; this layer can be update by user.
71
+ spots,
72
+ size = 5,
73
+ scale=scale,
74
+ face_color= 'transparent',
75
+ opacity= 1,
76
+ symbol= 'disc',
77
+ name= 'single spots'
78
+ )
79
+
80
+ if type(clusters) != type(None) : Viewer.add_points( # cluster; this layer can be update by user.
81
+ clusters[:,:dim],
82
+ size = 10,
83
+ scale=scale,
84
+ face_color= 'blue',
85
+ opacity= 0.7,
86
+ symbol= 'diamond',
87
+ name= 'foci',
88
+ features= {"spot_number" : clusters[:,dim], "id" : clusters[:,dim+1]},
89
+ feature_defaults= {"spot_number" : 0, "id" : -1}
90
+ )
119
91
 
120
- if type(clusters) != type(None) :
121
- if len(clusters) > 0 :
122
- new_clusters = np.concatenate([
123
- np.array(Viewer.layers[2 + layer_offset].data, dtype= int),
124
- np.array(Viewer.layers[2 + layer_offset].features, dtype= int)
125
- ],
126
- axis= 1)
92
+ if type(cell_label) != type(None) and not np.array_equal(nucleus_label, cell_label) : Viewer.add_labels(cell_label, scale=scale, opacity= 0.2, blending= 'additive')
93
+ if type(nucleus_label) != type(None) : Viewer.add_labels(nucleus_label, scale=scale, opacity= 0.2, blending= 'additive')
94
+
95
+ Viewer.show(block=False)
96
+ napari.run()
127
97
 
128
- new_clusters = _update_clusters(new_clusters, new_spots, voxel_size=voxel_size, cluster_size=cluster_size, min_spot_number=min_spot_number, shape=image.shape)
129
- else : new_clusters = None
98
+ new_spots = np.array(Viewer.layers['single spots'].data, dtype= int)
130
99
 
131
- except Exception as error :
132
- new_spots = spots
133
- new_clusters = clusters
134
- raise error
100
+ if type(clusters) != type(None) :
101
+ if len(clusters) > 0 :
102
+ new_clusters = np.array(Viewer.layers['foci'].data, dtype= int)
103
+ new_clusters = _update_clusters(new_clusters, new_spots, voxel_size=voxel_size, cluster_size=cluster_size, min_spot_number=min_spot_number, shape=image.shape)
104
+ else : new_clusters = None
135
105
 
136
106
  return new_spots, new_clusters
137
107
 
@@ -168,25 +138,27 @@ def show_segmentation(
168
138
  Viewer = napari.Viewer(ndisplay=2, title= 'Show segmentation', axis_labels=['z','y','x'] if dim == 3 else ['y', 'x'], show= False)
169
139
 
170
140
  # Adding channels
171
- Viewer.add_image(nuc_image, name= "nucleus signal", blending= 'additive', colormap='blue', contrast_limits=[nuc_image.min(), nuc_image.max()])
172
- Viewer.add_labels(nuc_label, opacity= 0.5, blending= 'additive')
141
+ nuc_signal_layer = Viewer.add_image(nuc_image, name= "nucleus signal", blending= 'additive', colormap='blue', contrast_limits=[nuc_image.min(), nuc_image.max()])
142
+ nuc_label_layer = Viewer.add_labels(nuc_label, opacity= 0.5, blending= 'additive', name= 'nucleus_label',)
143
+ nuc_label_layer.preserve_labels = True
173
144
 
174
145
  #Adding labels
175
146
  if type(cyto_image) != type(None) : Viewer.add_image(cyto_image, name= "cytoplasm signal", blending= 'additive', colormap='red', contrast_limits=[cyto_image.min(), cyto_image.max()])
176
- if type(cyto_label) != type(None) and not np.array_equal(cyto_label, nuc_label): Viewer.add_labels(cyto_label, opacity= 0.4, blending= 'additive')
147
+ if (type(cyto_label) != type(None) and not np.array_equal(cyto_label, nuc_label) ) or (type(cyto_label) != type(None) and cyto_label.max() == 0):
148
+ cyto_label_layer = Viewer.add_labels(cyto_label, opacity= 0.4, blending= 'additive', name= 'cytoplasm_label')
149
+ cyto_label_layer.preserve_labels = True
177
150
 
178
151
  #Launch Napari
179
152
  Viewer.show(block=False)
180
153
  napari.run()
181
154
 
182
- new_nuc_label = Viewer.layers[1].data
183
- if type(cyto_label) != type(None) and not np.array_equal(cyto_label, nuc_label) : new_cyto_label = Viewer.layers[3].data
155
+
156
+ new_nuc_label = Viewer.layers['nucleus_label'].data
157
+ if type(cyto_label) != type(None) and not np.array_equal(cyto_label, nuc_label) : new_cyto_label = Viewer.layers['cytoplasm_label'].data
184
158
  else : new_cyto_label = new_nuc_label
185
159
 
186
160
  return new_nuc_label, new_cyto_label
187
161
 
188
-
189
-
190
162
  def threshold_selection(
191
163
  image : np.ndarray,
192
164
  filtered_image : np.ndarray,
@@ -195,7 +167,7 @@ def threshold_selection(
195
167
  ) :
196
168
 
197
169
  """
198
- To view code for spot selection please have a look at magicgui instance created with `detection._create_threshold_slider` which is then passed to this napari wrapper as 'threshold_slider' argument.
170
+ To view code for spot selection have a look at magicgui instance created with `detection._create_threshold_slider` which is then passed to this napari wrapper as 'threshold_slider' argument.
199
171
  """
200
172
 
201
173
  Viewer = napari.Viewer(title= "Small fish - Threshold selector", ndisplay=2, show=True)
@@ -218,12 +190,13 @@ def threshold_selection(
218
190
 
219
191
  Viewer.window.add_dock_widget(threshold_slider, name='threshold_selector')
220
192
  threshold_slider() #First occurence with auto or entered threshold.
193
+
221
194
  napari.run()
222
195
 
223
- spots = Viewer.layers[-1].data.astype(int)
196
+ spots = Viewer.layers['single spots'].data.astype(int)
224
197
  if len(spots) == 0 :
225
- threshold = filtered_image.max()
198
+ pass
226
199
  else :
227
- threshold = Viewer.layers[-1].properties.get('threshold')[0]
200
+ threshold = Viewer.layers['single spots'].properties.get('threshold')[0]
228
201
 
229
202
  return spots, threshold