small-fish-gui 2.1.1__py3-none-any.whl → 2.1.3__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.
@@ -137,7 +137,11 @@ def spots_colocalisation(
137
137
  voxel_size : (z,y,x) tuple
138
138
  """
139
139
 
140
+ #No cluster or no spots case
141
+ if spot_list1 is np.nan or spot_list2 is np.nan : return np.nan
140
142
  if len(spot_list1) == 0 or len(spot_list2) == 0 : return np.nan
143
+
144
+ #Dim check
141
145
  if len(spot_list1[0]) != len(spot_list2[0]) :
142
146
  raise MissMatchError("dimensionalities of spots 1 and spots 2 don't match.")
143
147
 
@@ -170,7 +174,10 @@ def initiate_colocalisation(
170
174
  ) :
171
175
 
172
176
  result_tables = result_tables.set_index('acquisition_id', drop=False)
173
- available_spots = dict(zip(result_tables['acquisition_id'].astype(str).str.cat(result_tables['name'],sep='-'), result_tables.index))
177
+ if len(result_tables) != 0 :
178
+ available_spots = dict(zip(result_tables['acquisition_id'].astype(str).str.cat(result_tables['name'],sep='-'), result_tables.index))
179
+ else :
180
+ available_spots = {}
174
181
  default_values = dict(get_settings())
175
182
 
176
183
  while True :
@@ -228,7 +235,7 @@ def _global_coloc(acquisition_id1,acquisition_id2, result_dataframe, colocalisat
228
235
  assert len(acquisition1) == 1
229
236
  assert len(acquisition2) == 1
230
237
 
231
- acquisition_couple = (acquisition_id1,acquisition_id2)
238
+ acquisition_couple = (int(acquisition_id1),int(acquisition_id2))
232
239
 
233
240
  voxel_size1 = acquisition1.iloc[0].at['voxel_size']
234
241
  voxel_size2 = acquisition2.iloc[0].at['voxel_size']
@@ -352,6 +359,7 @@ def _cell_coloc(
352
359
  pivot_values_columns = ['rna_coords', 'total_rna_number']
353
360
  if 'clusters' in acquisition2.columns or 'clusters' in acquisition1.columns:
354
361
  pivot_values_columns.extend(['clustered_spots_coords','clustered_spot_number'])
362
+ print(cell_dataframe.loc[:,["clustered_spots_coords"]])
355
363
  cell_dataframe.loc[:,['cell_id']] = cell_dataframe['cell_id'].astype(int)
356
364
  colocalisation_df = cell_dataframe.pivot(
357
365
  columns=['name', 'acquisition_id'],
@@ -380,7 +388,9 @@ def _cell_coloc(
380
388
  colocalisation_df[("spots_with_spots_fraction",coloc_name_backward,"backward")] = colocalisation_df[("spots_with_spots_count",coloc_name_backward,"backward")].astype(float) / colocalisation_df[('total_rna_number',acquisition_name_id2,acquisition_id2)].astype(float)
381
389
 
382
390
  if 'clusters' in acquisition2.columns:
383
- if len(acquisition2['clusters'].iat[0]) > 0 :
391
+ if len(acquisition2['clusters'].iat[0]) > 0 or len(acquisition2['clustered_spots_coords'][acquisition2['clustered_spots_coords'] != -1]) > 0 :
392
+
393
+ print("COLOCALISATION_DF\n", colocalisation_df.loc[:,('clustered_spots_coords',acquisition_name_id2,acquisition_id2)])
384
394
 
385
395
  #spots to clusters
386
396
  colocalisation_df[("spots_with_clustered_spots_count",coloc_name_forward,"forward")] = colocalisation_df.apply(
@@ -30,6 +30,7 @@ from ..hints import pipeline_parameters
30
30
  from ..__init__ import __wiki__
31
31
 
32
32
  import os
33
+ import traceback
33
34
  import pandas as pd
34
35
  import FreeSimpleGUI as sg
35
36
  import numpy as np
@@ -302,61 +303,74 @@ def compute_colocalisation(
302
303
  return global_coloc_df, cell_coloc_df, max_id
303
304
 
304
305
  if os.path.isfile(spots1_key) :
305
- Spots1 = load_spots(spots1_key)
306
- fake_acquisition = reconstruct_acquisition_data(
307
- Spots=Spots1,
308
- max_id=max_id,
309
- filename= os.path.basename(spots1_key),
310
- voxel_size = voxel_size
311
- )
312
- result_dataframe = pd.concat([
313
- result_dataframe,
314
- fake_acquisition
315
- ], axis=0)
316
-
317
- if not Spots1['cell_label'].isna().all() :
318
- fake_cells = reconstruct_cell_data(
306
+ try :
307
+ Spots1 = load_spots(spots1_key)
308
+ fake_acquisition = reconstruct_acquisition_data(
319
309
  Spots=Spots1,
320
310
  max_id=max_id,
311
+ filename= os.path.basename(spots1_key),
312
+ voxel_size = voxel_size
321
313
  )
322
-
323
- cell_result_dataframe = pd.concat([
324
- cell_result_dataframe,
325
- fake_cells
314
+ result_dataframe = pd.concat([
315
+ result_dataframe,
316
+ fake_acquisition
326
317
  ], axis=0)
327
318
 
328
- max_id +=1
329
- acquisition_id1 = fake_acquisition.iloc[0].at['acquisition_id']
319
+ if not Spots1['cell_label'].isna().all() :
320
+ fake_cells = reconstruct_cell_data(
321
+ Spots=Spots1,
322
+ max_id=max_id,
323
+ filename= os.path.basename(spots1_key)
324
+ )
325
+
326
+ cell_result_dataframe = pd.concat([
327
+ cell_result_dataframe,
328
+ fake_cells
329
+ ], axis=0)
330
+
331
+ max_id +=1
332
+ acquisition_id1 = fake_acquisition.iloc[0].at['acquisition_id']
333
+ except ValueError as e :
334
+ sg.popup("Could not reconstruct coordinates from selected file (Spots 1)")
335
+ traceback.print_exception(e)
336
+ return global_coloc_df, cell_coloc_df, max_id
337
+
330
338
 
331
339
  else :
332
340
  acquisition_id1 = spots1_key
333
341
 
334
342
  if os.path.isfile(spots2_key) :
335
- Spots2 = load_spots(spots2_key)
336
- fake_acquisition = reconstruct_acquisition_data(
337
- Spots=Spots2,
338
- max_id=max_id,
339
- filename= os.path.basename(spots2_key),
340
- voxel_size = voxel_size
341
- )
342
- result_dataframe = pd.concat([
343
- result_dataframe,
344
- fake_acquisition
345
- ], axis=0)
346
-
347
- if not Spots2['cell_label'].isna().all() :
348
- fake_cells = reconstruct_cell_data(
343
+ try :
344
+ Spots2 = load_spots(spots2_key)
345
+ fake_acquisition = reconstruct_acquisition_data(
349
346
  Spots=Spots2,
350
347
  max_id=max_id,
348
+ voxel_size = voxel_size,
349
+ filename= os.path.basename(spots2_key),
351
350
  )
352
-
353
- cell_result_dataframe = pd.concat([
354
- cell_result_dataframe,
355
- fake_cells
351
+ result_dataframe = pd.concat([
352
+ result_dataframe,
353
+ fake_acquisition
356
354
  ], axis=0)
357
355
 
358
- max_id +=1
359
- acquisition_id2 = fake_acquisition.iloc[0].at['acquisition_id']
356
+ if not Spots2['cell_label'].isna().all() :
357
+ fake_cells = reconstruct_cell_data(
358
+ Spots=Spots2,
359
+ max_id=max_id,
360
+ filename= os.path.basename(spots2_key)
361
+ )
362
+
363
+ cell_result_dataframe = pd.concat([
364
+ cell_result_dataframe,
365
+ fake_cells
366
+ ], axis=0)
367
+
368
+ max_id +=1
369
+ acquisition_id2 = fake_acquisition.iloc[0].at['acquisition_id']
370
+ except ValueError as e :
371
+ sg.popup("Could not reconstruct coordinates from selected file (Spots 2)")
372
+ traceback.print_exception(e)
373
+ return global_coloc_df, cell_coloc_df, max_id
360
374
 
361
375
  else :
362
376
  acquisition_id2 = spots2_key
@@ -50,8 +50,7 @@ def compute_Spots(
50
50
  if type(cluster_id) == type(None) : #When user doesn't select cluster
51
51
  cluster_id = [np.nan]*len(spots)
52
52
 
53
- index = list(zip(*spots))
54
- index = tuple(index)
53
+ index = tuple(spots.T.tolist())
55
54
  spot_intensities_list = list(image[index])
56
55
  if type(nucleus_label) != type(None) :
57
56
  if nucleus_label.ndim == 2 :
@@ -116,33 +115,26 @@ def reconstruct_acquisition_data(
116
115
  ) -> pd.DataFrame:
117
116
  """
118
117
  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
118
  """
130
-
119
+ max_id = int(max_id)
131
120
  spots = reconstruct_spots(Spots['coordinates'])
132
121
  has_clusters = not Spots['cluster_id'].isna().all()
133
122
  spot_number = len(spots)
134
123
 
135
124
  if has_clusters :
136
125
 
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()
126
+ clusters = np.empty(shape=(0,5), dtype=int)
127
+ spot_cluster_id = Spots['cluster_id'].to_numpy().astype(int)
128
+ clustered_spots = spots[spot_cluster_id != -1]
129
+ print("clustered_spots : ", clustered_spots)
139
130
 
140
131
  new_acquisition = pd.DataFrame({
141
132
  'acquisition_id' : [max_id + 1],
142
- 'name' : ["loaded_spots_{}".format(max_id + 1)],
133
+ 'name' : ["(loaded_spots)_{}".format(filename.split('.', maxsplit=1)[0])],
143
134
  'threshold' : [0],
144
135
  'spots' : [spots],
145
- 'clusters' : [clusters],
136
+ 'clusters' : [clusters.tolist()],
137
+ 'clustered_spots_coords' : [clustered_spots.tolist()],
146
138
  'spots_cluster_id' : [spot_cluster_id],
147
139
  'spot_number' : [spot_number],
148
140
  'filename' : [filename],
@@ -151,7 +143,7 @@ def reconstruct_acquisition_data(
151
143
  else :
152
144
  new_acquisition = pd.DataFrame({
153
145
  'acquisition_id' : [max_id + 1],
154
- 'name' : ["loaded_spots_{}".format(max_id + 1)],
146
+ 'name' : ["(loaded_spots)_{}".format(filename.split('.', maxsplit=1)[0])],
155
147
  'threshold' : [0],
156
148
  'spots' : [spots],
157
149
  'spot_number' : [spot_number],
@@ -159,6 +151,11 @@ def reconstruct_acquisition_data(
159
151
  'voxel_size' : [voxel_size],
160
152
  })
161
153
 
154
+ print("Reconstructed acquisition : \n", new_acquisition)
155
+ print("\n", new_acquisition.columns)
156
+ if 'clusters' in new_acquisition.columns :
157
+ print("\n", new_acquisition['clusters'])
158
+
162
159
  return new_acquisition
163
160
 
164
161
  def reconstruct_spots(
@@ -175,6 +172,7 @@ def reconstruct_spots(
175
172
  def reconstruct_cell_data(
176
173
  Spots : pd.DataFrame,
177
174
  max_id : int,
175
+ filename : str,
178
176
  ) :
179
177
 
180
178
  has_cluster = not Spots['cluster_id'].isna().all()
@@ -199,7 +197,7 @@ def reconstruct_cell_data(
199
197
  cell['clustered_spot_number'] = cell['clustered_spots_coords'].apply(len)
200
198
 
201
199
  cell['acquisition_id'] = max_id + 1
202
- cell['name'] = "loaded_spots_{}".format(max_id + 1)
200
+ cell['name'] = "(loaded_spots)_{}".format(filename.split('.', maxsplit=1)[0])
203
201
  cell = cell.rename(columns={"cell_label": "cell_id"})
204
202
 
205
203
  return cell
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: small_fish_gui
3
- Version: 2.1.1
3
+ Version: 2.1.3
4
4
  Summary: Small Fish is a python application for the analysis of smFish images. It provides a ready to use graphical interface to combine famous python packages for cell analysis without any need for coding.
5
5
  Project-URL: Homepage, https://github.com/SmallFishGUI/small_fish_gui
6
6
  Project-URL: Wiki, https://github.com/SmallFishGUI/small_fish_gui/wiki
@@ -131,4 +131,8 @@ You are all set! Try it yourself or check the [get started](https://github.com/2
131
131
 
132
132
  ## Developement
133
133
  Bugs to fix :
134
- * Use of load button during co-localization quantification yields wrongs results
134
+ * Use of load button during co-localization quantification yields diffrent results than when testing from memory :
135
+ --> Shown results are correct and consistent with results from memory
136
+ --> But background (i.e cell_id = 0) is treated as a cell instead of being filtered
137
+ --> But cells on edges are NOT removed from quantification (they are if test is performed from memory)
138
+ --> But Cluster related metrics are not computed when test is performed from save
@@ -1,8 +1,7 @@
1
- small_fish_gui/__init__.py,sha256=CeLyp2zV0AfjMKoP3uqVfIT1j05NhBfc90HKwtFJhCU,2163
1
+ small_fish_gui/__init__.py,sha256=LXbX5bfmwGeIZqpQAvwXrknqBfev-XlPYsJqXKB2Ch8,2163
2
2
  small_fish_gui/__main__.py,sha256=xwpFMDuo0kkYvPamyhlTHJ68bymDfbRpPzKy3SKwezY,1639
3
3
  small_fish_gui/hints.py,sha256=NEKqCbjXF3guHnc1dzq_LYYGlTxIV6z6wtdwVlmgHos,3349
4
4
  small_fish_gui/main_menu.py,sha256=z0ZlidWNGHLYYnBx2Z1i2IX_EGQr-HtIlsOQl-yTw4o,6273
5
- small_fish_gui/small_fish_gui.code-workspace,sha256=GbzU4Vx0xJV2o86UOa-FA83na5mGxSD6Efeb1QFBMlM,60
6
5
  small_fish_gui/utils.py,sha256=LM6QW2ono_LIRv7JXIIq7ZxxbDXqBtZ5uR9gjKJfwM8,1903
7
6
  small_fish_gui/batch/__init__.py,sha256=ku2_Yate-UG89Q0BmE2B9kFV4kOz-u9Lf2lj6VsdFXs,127
8
7
  small_fish_gui/batch/input.py,sha256=mqnP8LBhyNbtlcqjVlUiVeuHw4YxOX3GgzJbq03isKE,1477
@@ -13,12 +12,11 @@ small_fish_gui/batch/prompt.py,sha256=_WZB-O3oYp8rRdEuf3r8o-ML0EWQn6UTuJVaW2OgpT
13
12
  small_fish_gui/batch/test.py,sha256=FcoCngSeueociwVoG8V3C6lQO7rrRHUfIVA2hJKr4v4,213
14
13
  small_fish_gui/batch/update.py,sha256=Gv1805-xUtrJ3BK0HdflBSnSFAEB5RmnAPk6peAR9CA,6169
15
14
  small_fish_gui/batch/utils.py,sha256=apHxp72OdjTSUyj4ZwN75NYc12Am4m7N9Sw03TrjLMk,1870
16
- small_fish_gui/batch/values.txt,sha256=9QpmRfZ5AuDByZFzkHxTESKV6bnZMH5DtPIGbMmLsXY,999
17
15
  small_fish_gui/gui/__init__.py,sha256=idpRSg2FFawF0ydfc7Y8ep6gQ4_jhroL_jZURlRE_BM,920
18
16
  small_fish_gui/gui/_napari_widgets.py,sha256=9gfikNMLZmeWY9tosD19aGmw4Ulf-BMo8erehJ4KU1k,35321
19
17
  small_fish_gui/gui/animation.py,sha256=MnYsA1kxQZ72L_H0knxOs41lG0ZZv1re7gSgYNmZY00,983
20
- small_fish_gui/gui/layout.py,sha256=CkQNmAWkpaz7WsdG-dp-IOaIxAFrJWLmA7cty3BkQzc,30878
21
- small_fish_gui/gui/napari_visualiser.py,sha256=5Dk9wJbnmxgNZ3upiQtOrtAr2CT700qkvNQvGsHHdsw,14834
18
+ small_fish_gui/gui/layout.py,sha256=72RZI4Vt5WwZH9cx8SfOCWsZox0udG3Ck3YE_c-aiQ4,30927
19
+ small_fish_gui/gui/napari_visualiser.py,sha256=eU2kqp16EHA3NwbGFBZAiTOiAI_K4zbnMOCtbW4fNuM,14978
22
20
  small_fish_gui/gui/prompts.py,sha256=vWLLJZ7jdYIbjT71qHGiE1o9-pTrc607shnKW6EZi8I,18361
23
21
  small_fish_gui/gui/testing.ipynb,sha256=2E51kT3BcXvOvOSdmYIy4Cxbe-4HtnOjzPTZQHDZJJw,69148
24
22
  small_fish_gui/gui/theme.py,sha256=30nujS48ZRdD1HVbzdEBkiAWlhow1AGgXSQNZcGEsaQ,118
@@ -27,22 +25,22 @@ small_fish_gui/interface/__init__.py,sha256=nqMwHG-l1yMm8iaD6hhCdji5RiKImzNFQcbd
27
25
  small_fish_gui/interface/default_settings.py,sha256=vI4-Pl_MpAGuCp7SjWdnpYvWwde_3rfvm9Mb_smaDho,3442
28
26
  small_fish_gui/interface/image.py,sha256=0icuHuKFuSZ-YUTIskz-S2HcJ3wXtOrW37iPg8tknHg,3440
29
27
  small_fish_gui/interface/inoutput.py,sha256=toB2SNNZNiupZTT2-zQKJ6ewI-_DJTVrXIkdq8TMWXY,5793
30
- small_fish_gui/interface/settings.json,sha256=8-PCnEJLsoFdkhAeJvKtOiuhBjTcA7CXqnG_IsZAqhI,1402
28
+ small_fish_gui/interface/settings.json,sha256=WqMjgN1Ex01hXruJ1Kkho4nPi9PbEPpOIplT5IIkHxQ,1366
29
+ small_fish_gui/interface/testing.ipynb,sha256=I8iGdcYsds4iBxL417D_PXt7bZcEkHAjWAgXA9DNlSM,323719
31
30
  small_fish_gui/interface/testing.py,sha256=AUdqmFJ6kBvFTOLRfZZJBBe3nm1key2bGpUDXJRaueI,2561
32
31
  small_fish_gui/interface/user_settings.py,sha256=vMpj-s9tzMKQy1CdJ3SO-6yAknU-ZIMT0RZQs8WAGPY,2620
33
32
  small_fish_gui/pipeline/__init__.py,sha256=Oww6dcuvnktl5jFKLriz8ZXObKo9MkneE739A8C1reY,739
34
33
  small_fish_gui/pipeline/_bigfish_wrapers.py,sha256=WcIu5HLc4bUuU8qmsINP5snXef3Tx9zJDNKES-SiftA,9776
35
- small_fish_gui/pipeline/_colocalisation.py,sha256=m6wRgf_nESqvkvkD2RRyTj3ekKKvk43ehvXZ-sXYX84,21714
34
+ small_fish_gui/pipeline/_colocalisation.py,sha256=r96rrWS5lim5bPCcoQMs83DRApCGxJ3ADruFhhYHxN0,22228
36
35
  small_fish_gui/pipeline/_custom_errors.py,sha256=tQ-AUhgzIFpK30AZiQQrtHCHyGVRDdAoIjzL0Fk-1pA,43
37
36
  small_fish_gui/pipeline/_preprocess.py,sha256=zfwhNoAUkVv1TYlyffNQkSTitMXTDokADabBeHuB58U,15766
38
- small_fish_gui/pipeline/actions.py,sha256=lPKyX12qEJNnQ4ArYqCRkLrFzwzGgIEl1_HpSFtTMKo,20476
37
+ small_fish_gui/pipeline/actions.py,sha256=dtRCf_UKg-Y9uV1jCBeASeuR7-pZ8dHVEYHs7MW-0pg,21263
39
38
  small_fish_gui/pipeline/detection.py,sha256=IE0Wf9NaHcxkCv1cjrOdyfnQUzv8SlXilIT7KI8INP4,35988
40
39
  small_fish_gui/pipeline/segmentation.py,sha256=m9XW8XiWCSpGFdi6It6RkeDYTiKtNhfj30kUSBG8pNo,32023
41
- small_fish_gui/pipeline/spots.py,sha256=3kMe404RHOsNLRZQV6RdpxrHqaRRiGK4_qKSx6jesDM,6738
40
+ small_fish_gui/pipeline/spots.py,sha256=lG9hvn0MqnDWUr2VfSEm8LHoprSlGoDHQFuQGlJHaxM,6807
42
41
  small_fish_gui/pipeline/test.py,sha256=w4ZMGDmUDXxVgWTlZ2TKw19W8q5gcE9gLMKe0SWnRrw,2827
43
- small_fish_gui/pipeline/testing.ipynb,sha256=zIjnWwsqCBUqydvFx3n4R3_SlrBSwgWjDt50zn4SNgI,339174
44
42
  small_fish_gui/pipeline/utils.py,sha256=dYV7WAJ375xM5RdaljjxeKvBC1niQvBl1E55SeIiIYo,563
45
- small_fish_gui-2.1.1.dist-info/METADATA,sha256=796rUUMhbnBHdlSsaXT0lkq4aO14MR5j4iQWxyX8064,6166
46
- small_fish_gui-2.1.1.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
47
- small_fish_gui-2.1.1.dist-info/licenses/LICENSE,sha256=-iFy8VGBYs5VsHglKpk4D-hxqQ2jMJaqmfq_ulIzDks,1303
48
- small_fish_gui-2.1.1.dist-info/RECORD,,
43
+ small_fish_gui-2.1.3.dist-info/METADATA,sha256=pFbXtb_Zd3RskgJg-chYrG11YZL32xahnim4TpuTusk,6553
44
+ small_fish_gui-2.1.3.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
45
+ small_fish_gui-2.1.3.dist-info/licenses/LICENSE,sha256=-iFy8VGBYs5VsHglKpk4D-hxqQ2jMJaqmfq_ulIzDks,1303
46
+ small_fish_gui-2.1.3.dist-info/RECORD,,
@@ -1,65 +0,0 @@
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
- do_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
- show_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