small-fish-gui 2.0.1__py3-none-any.whl → 2.0.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.
Files changed (51) hide show
  1. small_fish_gui/__init__.py +9 -3
  2. small_fish_gui/batch/integrity.py +2 -2
  3. small_fish_gui/batch/pipeline.py +46 -11
  4. small_fish_gui/batch/prompt.py +102 -41
  5. small_fish_gui/batch/update.py +26 -13
  6. small_fish_gui/batch/utils.py +1 -1
  7. small_fish_gui/gui/__init__.py +1 -0
  8. small_fish_gui/gui/_napari_widgets.py +418 -6
  9. small_fish_gui/gui/layout.py +332 -112
  10. small_fish_gui/gui/napari_visualiser.py +107 -22
  11. small_fish_gui/gui/prompts.py +161 -48
  12. small_fish_gui/gui/testing.ipynb +231 -24
  13. small_fish_gui/gui/tooltips.py +7 -1
  14. small_fish_gui/hints.py +23 -7
  15. small_fish_gui/interface/__init__.py +7 -1
  16. small_fish_gui/interface/default_settings.py +118 -0
  17. small_fish_gui/interface/image.py +43 -11
  18. small_fish_gui/interface/settings.json +50 -0
  19. small_fish_gui/interface/testing.ipynb +4354 -0
  20. small_fish_gui/interface/user_settings.py +96 -0
  21. small_fish_gui/main_menu.py +13 -1
  22. small_fish_gui/pipeline/{_signaltonoise.py → _bigfish_wrapers.py} +59 -7
  23. small_fish_gui/pipeline/_colocalisation.py +23 -24
  24. small_fish_gui/pipeline/_preprocess.py +46 -32
  25. small_fish_gui/pipeline/actions.py +48 -5
  26. small_fish_gui/pipeline/detection.py +71 -141
  27. small_fish_gui/pipeline/segmentation.py +360 -268
  28. small_fish_gui/pipeline/spots.py +3 -3
  29. small_fish_gui/pipeline/utils.py +5 -1
  30. small_fish_gui/README.md → small_fish_gui-2.0.3.dist-info/METADATA +50 -2
  31. small_fish_gui-2.0.3.dist-info/RECORD +46 -0
  32. {small_fish_gui-2.0.1.dist-info → small_fish_gui-2.0.3.dist-info}/WHEEL +1 -1
  33. small_fish_gui/.github/workflows/python-publish.yml +0 -39
  34. small_fish_gui/LICENSE +0 -24
  35. small_fish_gui/batch/values.txt +0 -65
  36. small_fish_gui/default_values.py +0 -51
  37. small_fish_gui/gui/screenshot/general_help_screenshot.png +0 -0
  38. small_fish_gui/gui/screenshot/mapping_help_screenshot.png +0 -0
  39. small_fish_gui/gui/screenshot/segmentation_help_screenshot.png +0 -0
  40. small_fish_gui/illustrations/DetectionVitrine_filtre.png +0 -0
  41. small_fish_gui/illustrations/DetectionVitrine_signal.png +0 -0
  42. small_fish_gui/illustrations/FocciVitrine.png +0 -0
  43. small_fish_gui/illustrations/FocciVitrine_no_spots.png +0 -0
  44. small_fish_gui/illustrations/Segmentation2D.png +0 -0
  45. small_fish_gui/illustrations/Segmentation2D_with_labels.png +0 -0
  46. small_fish_gui/logo.png +0 -0
  47. small_fish_gui/pipeline/testing.ipynb +0 -3636
  48. small_fish_gui/requirements.txt +0 -19
  49. small_fish_gui-2.0.1.dist-info/METADATA +0 -75
  50. small_fish_gui-2.0.1.dist-info/RECORD +0 -59
  51. {small_fish_gui-2.0.1.dist-info → small_fish_gui-2.0.3.dist-info}/licenses/LICENSE +0 -0
@@ -1,15 +1,18 @@
1
1
  import FreeSimpleGUI as sg
2
2
  import os
3
+ import numpy as np
3
4
  import cellpose.models as models
4
- import small_fish_gui.default_values as default
5
5
  from typing import Optional, Union
6
6
 
7
7
  from cellpose.core import use_gpu
8
- from .tooltips import FLOW_THRESHOLD_TOOLTIP,CELLPROB_TOOLTIP
8
+ from .tooltips import FLOW_THRESHOLD_TOOLTIP,CELLPROB_TOOLTIP, MIN_SIZE_TOOLTIP
9
9
  from ..hints import pipeline_parameters
10
10
  from ..utils import check_parameter
11
+ from ..interface import SettingsDict, get_default_settings, get_settings
11
12
 
12
13
 
14
+ settings = get_settings()
15
+
13
16
  def add_header(header_text) :
14
17
  """Returns [elmnt] not layout"""
15
18
  header = [sg.Text('\n{0}'.format(header_text), size= (len(header_text),3), font= 'bold 15')]
@@ -66,9 +69,14 @@ def parameters_layout(
66
69
  ] for parameter, option in zip(parameters, opt)
67
70
  ]
68
71
 
69
- if type(unit) == str :
72
+ if isinstance(unit, str):
70
73
  for line_id, line in enumerate(layout) :
71
74
  layout[line_id] += [sg.Text('{0}'.format(unit))]
75
+ elif isinstance(unit, list) :
76
+ if len(unit) != len(parameters) : raise ValueError(f"unit list and parameters must have same length : {len(unit)} , {len(parameters)}")
77
+
78
+ for line_id, unit_txt in zip(range(len(parameters)), unit) :
79
+ layout[line_id] += [sg.Text('{0}'.format(unit_txt))]
72
80
 
73
81
  if isinstance(header, str) :
74
82
  layout = [add_header(header)] + layout
@@ -103,13 +111,14 @@ def tuple_layout(opt=None, default_dict={}, unit:dict={}, names : dict = {}, **t
103
111
 
104
112
  return layout
105
113
 
106
- def path_layout(keys= [],look_for_dir = False, header=None, preset=os.getcwd()) :
114
+ def path_layout(keys= [],look_for_dir = False, header=None, preset=settings.working_directory) :
107
115
  """
108
116
  If not look for dir then looks for file.
109
117
  """
110
118
  if len(keys) == 0 : return []
111
119
  check_parameter(keys= list, header = (str, type(None)))
112
120
  for key in keys : check_parameter(key = str)
121
+
113
122
  if look_for_dir : Browse = sg.FolderBrowse
114
123
  else : Browse = sg.FileBrowse
115
124
 
@@ -185,105 +194,197 @@ def radio_layout(values, header=None, key=None) :
185
194
  return layout
186
195
 
187
196
  def _segmentation_layout(
188
- multichannel : bool,
197
+ is_multichannel : bool,
189
198
  is_3D_stack : bool,
190
- cytoplasm_model_preset= default.CYTO_MODEL,
191
- nucleus_model_preset= default.NUC_MODEL,
192
- cytoplasm_channel_preset=default.CHANNEL,
193
- nucleus_channel_preset=default.NUC_CHANNEL,
194
- other_nucleus_image_preset = None,
195
- cyto_diameter_preset=default.CYTO_DIAMETER,
196
- nucleus_diameter_preset= default.NUC_DIAMETER,
197
- show_segmentation_preset= default.SHOW_SEGMENTATION,
198
- save_segmentation_visual_preset = default.SAVE_SEGMENTATION_VISUAL,
199
- segment_only_nuclei_preset=default.SEGMENT_ONLY_NUCLEI,
200
- saving_path_preset=default.VISUAL_PATH,
201
- filename_preset='cell_segmentation.png',
202
- cytoplasm_segmentation_3D = default.DO_3D_SEMGENTATION,
203
- nucleus_segmentation_3D = default.DO_3D_SEMGENTATION,
204
- cellprob_threshold = default.CELLPROB_THRESHOD,
205
- flow_threshold = default.FLOW_THRESHOLD,
206
- anisotropy= default.ANISOTROPY,
199
+ cytoplasm_model,
200
+ nucleus_model,
201
+ cytoplasm_channel,
202
+ nucleus_channel,
203
+ other_nucleus_image,
204
+ cytoplasm_diameter,
205
+ nucleus_diameter,
206
+ show_segmentation,
207
+ save_segmentation_visuals,
208
+ segment_only_nuclei,
209
+ saving_path,
210
+ filename,
211
+ cytoplasm_segmentation_3D ,
212
+ nucleus_segmentation_3D ,
213
+ cellprob_threshold ,
214
+ flow_threshold ,
215
+ anisotropy,
216
+ cytoplasm_min_size : int,
217
+ nucleus_min_size : int,
218
+ reordered_shape : tuple,
219
+ **kwargs
207
220
  ) :
208
221
 
209
222
  USE_GPU = use_gpu()
210
-
211
- models_list = models.get_user_models() + models.MODEL_NAMES
212
- if len(models_list) == 0 : models_list = ['no model found']
223
+ event_dict = dict()
213
224
 
214
225
  #Header : GPU availabality
215
- layout = [
216
- [sg.Text("GPU is currently "), sg.Text('ON', text_color= 'green') if USE_GPU else sg.Text('OFF', text_color= 'red')]
217
- ]
226
+ layout = [[sg.Text("Cell Segmentation", font="bold 20", pad=(0,20))]]
227
+ layout += [[sg.Text("GPU is currently "), sg.Text('ON', text_color= 'green') if USE_GPU else sg.Text('OFF', text_color= 'red')]]
228
+ layout += bool_layout(['Interactive segmentation'],keys=['show_segmentation'], preset= show_segmentation)
229
+
230
+ segment_only_nuclei_checkbox = sg.Checkbox("Segment only nuclei", default=segment_only_nuclei, key= "segment_only_nuclei", enable_events=True)
231
+ layout += [[segment_only_nuclei_checkbox]]
232
+ event_dict['segment_only_nuclei'] = segment_only_nuclei_checkbox
218
233
 
219
- #cytoplasm parameters
220
- layout += [
221
- add_header("Cytoplasm Segmentation"),
222
- [sg.Text("Choose parameters for cytoplasm segmentation: \n")],
223
- ]
224
-
225
- if is_3D_stack : layout += bool_layout(['3D segmentation'], preset=[cytoplasm_segmentation_3D], keys=['cytoplasm_segmentation_3D'],)
226
- if multichannel : layout += parameters_layout(['Cytoplasm channel'],default_values= [cytoplasm_channel_preset], keys = ["cytoplasm_channel"])
227
-
228
- layout += [[sg.Text("Cellpose model : ")] + combo_elmt(models_list, key='cyto_model_name', default_value= cytoplasm_model_preset)]
229
- layout += parameters_layout(['Cytoplasm diameter'], unit= "px", default_values= [cyto_diameter_preset], keys=['cytoplasm_diameter'])
230
- layout += parameters_layout(
231
- ["Flow threshold", "Cellprob threshold"],
232
- default_values=[flow_threshold, cellprob_threshold],
233
- keys=["flow_threshold_cyto","cellprob_threshold_cyto"],
234
- tooltips= [FLOW_THRESHOLD_TOOLTIP, CELLPROB_TOOLTIP]
235
- )
236
-
237
234
  #Nucleus parameters
238
- layout += [
239
- add_header("Nuclei segmentation"),
240
- [sg.Text("Choose parameters for nuclei segmentation: \n")],
235
+ nucleus_key = "nucleus"
236
+ layout += [[sg.Text("Nucleus parameters", font="bold 15", pad=(0,10))]]
237
+ nucleus_parameters_col, nucleus_event_dict = _segmentate_object_layout(
238
+ reordered_shape = reordered_shape,
239
+ anisotropy=anisotropy,
240
+ cellprob_threshold=cellprob_threshold,
241
+ channel=nucleus_channel,
242
+ diameter=nucleus_diameter,
243
+ flow_threshold=flow_threshold,
244
+ is_3D_stack=is_3D_stack,
245
+ model=nucleus_model,
246
+ is_multichannel=is_multichannel,
247
+ object_key=nucleus_key,
248
+ segmentation_3D=nucleus_segmentation_3D,
249
+ min_size=nucleus_min_size
250
+ )
251
+ layout += path_layout(keys=["other_nucleus_image"], look_for_dir=False, preset=other_nucleus_image)
252
+ layout += [[nucleus_parameters_col]]
253
+ event_dict.update(nucleus_event_dict)
254
+ event_dict[nucleus_key + "_column"] = nucleus_parameters_col
255
+
256
+
257
+ #Cytoplasm parameters
258
+ layout += [[sg.Text("Cytoplasm parameters", font="bold 15", pad=(0,10))]]
259
+ cytoplasm_key = "cytoplasm"
260
+ cytoplasm_parameters_col, cytoplasm_event_dict = _segmentate_object_layout(
261
+ reordered_shape = reordered_shape,
262
+ anisotropy=anisotropy,
263
+ cellprob_threshold=cellprob_threshold,
264
+ channel=cytoplasm_channel,
265
+ diameter=cytoplasm_diameter,
266
+ flow_threshold=flow_threshold,
267
+ is_3D_stack=is_3D_stack,
268
+ model=cytoplasm_model,
269
+ is_multichannel=is_multichannel,
270
+ object_key=cytoplasm_key,
271
+ segmentation_3D=cytoplasm_segmentation_3D,
272
+ min_size=cytoplasm_min_size
273
+ )
274
+ layout += [[cytoplasm_parameters_col]]
275
+ event_dict.update(cytoplasm_event_dict)
276
+ event_dict[cytoplasm_key + "_column"] = cytoplasm_parameters_col
277
+
278
+ #Control plots
279
+ layout += [[sg.Text("Control plots", font="bold 15", pad=(0,10))]]
280
+ layout += bool_layout(['Save png control'], preset= save_segmentation_visuals, keys=['save_segmentation_visuals'])
281
+ layout += path_layout(keys=['seg_control_saving_path'], look_for_dir=True, preset=saving_path)
282
+ layout += parameters_layout(['Filename'], default_values=[filename], size= 25, keys=['filename'])
283
+
284
+ return layout, event_dict
285
+
286
+ def _segmentate_object_layout(
287
+ reordered_shape : tuple | None,
288
+ object_key : str,
289
+ is_multichannel : bool,
290
+ is_3D_stack : bool,
291
+ model : str,
292
+ channel : int,
293
+ diameter : int,
294
+ segmentation_3D : bool ,
295
+ cellprob_threshold : float ,
296
+ flow_threshold : float,
297
+ anisotropy : float,
298
+ min_size : int,
299
+ **kwargs
300
+ ) -> sg.Column :
301
+
302
+ models_list = models.get_user_models() + models.MODEL_NAMES
303
+ if len(models_list) == 0 : models_list = ['no model found']
304
+
305
+ key_2D = object_key + "_radio_2D"
306
+ options_2D = list()
307
+ key_3D = object_key + "_radio_3D"
308
+ options_3D = list()
309
+ layout = []
310
+
311
+ if is_3D_stack :
312
+ radio_2D_seg = sg.Radio("2D segmentation", group_id=object_key+"_seg_dim", default=not segmentation_3D, visible = True, enable_events=True, key=key_2D)
313
+ radio_max_proj = sg.Radio("max proj", group_id=object_key+"_2D_proj", default=False, disabled= segmentation_3D, key= object_key+"_max_proj")
314
+ radio_mean_proj = sg.Radio("mean proj", group_id=object_key+"_2D_proj", default=True, disabled= segmentation_3D, key = object_key + "_mean_proj")
315
+ radio_slice_proj = sg.Radio("select slice", group_id=object_key+"_2D_proj", default=False, disabled= segmentation_3D, key=object_key + "_select_slice")
316
+
317
+ slice_number = reordered_shape[0 + is_multichannel] if not reordered_shape is None else 999
318
+ int_slice_proj = sg.Spin(list(range(slice_number)), size= (5,1), disabled= segmentation_3D, key=object_key+"_selected_slice")
319
+
320
+ options_2D += [
321
+ radio_max_proj,
322
+ radio_mean_proj,
323
+ radio_slice_proj,
324
+ int_slice_proj
325
+ ]
326
+
327
+ layout += [
328
+ [radio_2D_seg],
329
+ [sg.Column([[radio_max_proj, radio_mean_proj, radio_slice_proj, int_slice_proj]], pad= (15,0,0,5))]
241
330
  ]
242
-
243
- layout += path_layout(['other_nucleus_image'], preset=other_nucleus_image_preset)
244
- if is_3D_stack : layout += bool_layout(['3D segmentation'], preset=[nucleus_segmentation_3D], keys=['nucleus_segmentation_3D'],)
245
- if multichannel : layout += parameters_layout(['nucleus_channel'], default_values= [nucleus_channel_preset])
246
- layout += bool_layout(["Segment only nuclei"], preset=segment_only_nuclei_preset, keys=["segment_only_nuclei"])
247
-
248
- layout += [[sg.Text("Cellpose model : ")] + combo_elmt(models_list, key='nucleus_model_name', default_value= nucleus_model_preset)]
249
- layout += parameters_layout(['Nucleus diameter'],unit= "px", default_values= [nucleus_diameter_preset], keys=['nucleus_diameter'])
331
+
332
+ radio_3D_seg = sg.Radio("3D segmentation", group_id=object_key+"_seg_dim", default=segmentation_3D, visible = True, enable_events=True, key= key_3D)
333
+ anisotropy = sg.Input(default_text = 1, key = object_key + "_anisotropy",size=5, disabled=not segmentation_3D)
334
+
335
+ layout += [
336
+ [radio_3D_seg],
337
+ [sg.Column([[sg.Text("anisotropy"), anisotropy]], pad=(15,0,0,5))]
338
+ ]
339
+
340
+ options_3D += [
341
+ anisotropy
342
+ ]
343
+
344
+ if is_multichannel :
345
+ channel_elmt = sg.Input(channel, key=object_key + "_channel", size=5)
346
+ layout += [[sg.Text(f'{object_key.capitalize()} channel'), channel_elmt]]
347
+
348
+ layout += [[sg.Text("Cellpose model : ")] + combo_elmt(models_list, key=object_key +'_model_name', default_value= model)]
349
+ layout += parameters_layout([f'{object_key.capitalize()} diameter'], unit= "px", default_values= [diameter], keys=[object_key+'_diameter'])
250
350
  layout += parameters_layout(
251
- ["Flow threshold", "Cellprob threshold"],
252
- default_values=[flow_threshold, cellprob_threshold],
253
- keys=["flow_threshold_nuc","cellprob_threshold_nuc"],
254
- tooltips= [FLOW_THRESHOLD_TOOLTIP, CELLPROB_TOOLTIP]
255
- )
256
- if is_3D_stack : layout += parameters_layout(
257
- ['anisotropy'],
258
- header = "Model parameters",
259
- default_values = [anisotropy]
351
+ ["Flow threshold", "Cellprob threshold", "Min. size"],
352
+ unit=["","","px"],
353
+ default_values=[flow_threshold, cellprob_threshold, min_size],
354
+ keys=[object_key + "_flow_threshold",object_key + "_cellprob_threshold", object_key + "_min_size"],
355
+ tooltips= [FLOW_THRESHOLD_TOOLTIP, CELLPROB_TOOLTIP, MIN_SIZE_TOOLTIP]
260
356
  )
261
357
 
262
- #Control plots
263
- layout += bool_layout(['Show_segmentation'],keys=['show_segmentation'], header= 'Segmentation plots', preset= show_segmentation_preset)
264
- layout += bool_layout(['Save segmentation visual'], preset= save_segmentation_visual_preset, keys=['save_segmentation_visual'])
265
- layout += path_layout(keys=['saving path'], look_for_dir=True, preset=saving_path_preset)
266
- layout += parameters_layout(['filename'], default_values=[filename_preset], size= 25)
358
+ object_col = sg.Column(layout)
267
359
 
268
- return layout
360
+ #Reference dict
361
+ event_dict = {
362
+ key_2D : options_2D,
363
+ key_3D : options_3D,
364
+ object_key + "_radio_2D_seg" : radio_2D_seg,
365
+ object_key + "_radio_3D_seg" : radio_3D_seg,
366
+ object_key + "_channel" : channel_elmt, # For batch mode layout update
367
+ }
368
+
369
+ return object_col, event_dict
370
+
269
371
 
270
372
  def _input_parameters_layout(
271
- ask_for_segmentation,
272
- is_3D_stack_preset,
273
- time_stack_preset,
274
- multichannel_preset,
275
- do_dense_regions_deconvolution_preset,
276
- do_clustering_preset,
277
- do_segmentation_preset,
278
- do_Napari_correction
279
-
280
- ) :
373
+ ask_for_segmentation : bool,
374
+ is_3D_stack_preset : bool,
375
+ time_stack_preset : bool,
376
+ multichannel_preset : bool,
377
+ do_dense_regions_deconvolution_preset : bool,
378
+ do_clustering_preset : bool,
379
+ do_segmentation_preset : bool,
380
+ do_Napari_correction : bool
381
+ ) :
281
382
  layout_image_path = path_layout(['image_path'], header= "Image")
282
383
  layout_image_path += bool_layout(['3D stack', 'Multichannel stack'], keys=['is_3D_stack', 'is_multichannel'], preset= [is_3D_stack_preset, multichannel_preset])
283
384
 
284
385
  layout_image_path += bool_layout(
285
386
  ['Dense regions deconvolution', 'Compute clusters', 'Cell segmentation', 'Open Napari corrector'],
286
- keys= ['do_dense_regions_deconvolution', 'do_cluster_computation', 'do_segmentation', 'show_napari_corrector'],
387
+ keys= ['do_dense_regions_deconvolution', 'do_cluster_computation', 'do_segmentation','show_napari_corrector' ],
287
388
  preset= [do_dense_regions_deconvolution_preset, do_clustering_preset, do_segmentation_preset, do_Napari_correction],
288
389
  header= "Pipeline settings")
289
390
 
@@ -298,21 +399,24 @@ def _detection_layout(
298
399
  do_segmentation,
299
400
  segmentation_done=False,
300
401
  default_dict : pipeline_parameters={},
301
- ) :
402
+ ) :
302
403
  if is_3D_stack : dim = 3
303
404
  else : dim = 2
405
+ default = get_settings()
304
406
 
305
407
  #Detection
306
408
  detection_parameters = ['threshold', 'threshold penalty']
307
- default_detection = [default_dict.setdefault('threshold',default.THRESHOLD), default_dict.setdefault('threshold penalty', default.THRESHOLD_PENALTY)]
409
+ default_detection = [default_dict.setdefault('threshold',default.threshold), default_dict.setdefault('threshold penalty', default.threshold_penalty)]
308
410
  opt= [True, True]
411
+ parameters_keys = ['threshold', 'threshold_penalty']
309
412
  if is_multichannel :
310
- detection_parameters += ['channel_to_compute']
413
+ detection_parameters += ['channel to compute']
311
414
  opt += [False]
312
- default_detection += [default_dict.setdefault('channel_to_compute', '')]
415
+ parameters_keys += ['channel_to_compute']
416
+ default_detection += [default_dict.setdefault('channel_to_compute', default.detection_channel)]
313
417
 
314
418
  layout = [[sg.Text("Green parameters", text_color= 'green'), sg.Text(" are optional parameters.")]]
315
- layout += parameters_layout(detection_parameters, header= 'Detection', opt=opt, default_values=default_detection)
419
+ layout += parameters_layout(detection_parameters, header= 'Detection', opt=opt, default_values=default_detection, keys= parameters_keys)
316
420
 
317
421
  if dim == 2 : tuple_shape = ('y','x')
318
422
  else : tuple_shape = ('z','y','x')
@@ -323,26 +427,26 @@ def _detection_layout(
323
427
  layout += tuple_layout(opt=opt, unit=unit, default_dict=default_dict, names=names, voxel_size= tuple_shape, spot_size= tuple_shape, log_kernel_size= tuple_shape, minimum_distance= tuple_shape)
324
428
 
325
429
  if (do_segmentation and is_multichannel) or (is_multichannel and segmentation_done):
326
- layout += [[sg.Text("nucleus channel signal "), sg.InputText(default_text=default_dict.setdefault('nucleus_channel',default.NUC_CHANNEL), 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.")]]
430
+ layout += [[sg.Text("nucleus channel signal "), sg.InputText(default_text=default_dict.setdefault('nucleus_channel',default.nucleus_channel), 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.")]]
327
431
 
328
432
  #Deconvolution
329
433
  if do_dense_region_deconvolution :
330
- default_dense_regions_deconvolution = [default_dict.setdefault('alpha',default.ALPHA), default_dict.setdefault('beta',default.BETA)]
434
+ default_dense_regions_deconvolution = [default_dict.setdefault('alpha',default.alpha), default_dict.setdefault('beta',default.beta)]
331
435
  layout += parameters_layout(['alpha', 'beta',], default_values= default_dense_regions_deconvolution, header= 'do_dense_regions_deconvolution')
332
- layout += parameters_layout(['gamma'], unit= 'px', default_values= [default_dict.setdefault('gamma',default.GAMMA)])
436
+ layout += parameters_layout(['gamma'], unit= 'px', default_values= [default_dict.setdefault('gamma',default.gamma)])
333
437
  layout += tuple_layout(opt= {"deconvolution_kernel" : True}, unit= {"deconvolution_kernel" : 'px'}, default_dict=default_dict, deconvolution_kernel = tuple_shape)
334
438
 
335
439
  #Clustering
336
440
  if do_clustering :
337
- layout += parameters_layout(['Cluster radius'],keys=['cluster_size'], unit="radius(nm)", default_values=[default_dict.setdefault('cluster_size',default.CLUSTER_SIZE)])
338
- layout += parameters_layout(['Min nb spots per cluster'],keys=['min_number_of_spots'], default_values=[default_dict.setdefault('min_number_of_spots', default.MIN_NUMBER_SPOTS)])
441
+ layout += parameters_layout(['Cluster radius'],keys=['cluster_size'], unit="radius(nm)", default_values=[default_dict.setdefault('cluster_size',default.cluster_size)])
442
+ layout += parameters_layout(['Min nb spots per cluster'],keys=['min_number_of_spots'], default_values=[default_dict.setdefault('min_number_of_spots', default.min_spot)])
339
443
 
340
- layout += bool_layout(['Interactive threshold selector'],keys = ['show_interactive_threshold_selector'], preset=[default.INTERACTIVE_THRESHOLD])
444
+ layout += bool_layout(['Interactive threshold selector'],keys = ['show_interactive_threshold_selector'], preset=[default.interactive_threshold_selector])
341
445
  layout += path_layout(
342
446
  keys=['spots_extraction_folder'],
343
447
  look_for_dir=True,
344
448
  header= "Individual spot extraction",
345
- preset= default_dict.setdefault('spots_extraction_folder', default.SPOT_EXTRACTION_FOLDER)
449
+ preset= default_dict.setdefault('spots_extraction_folder', default.spot_extraction_folder)
346
450
  )
347
451
  default_filename = default_dict.setdefault("filename","") + "_spot_extraction"
348
452
  layout += parameters_layout(
@@ -353,39 +457,155 @@ def _detection_layout(
353
457
  layout += bool_layout(
354
458
  ['.csv','.excel',],
355
459
  keys= ['do_spots_csv', 'do_spots_excel'],
356
- preset= [default_dict.setdefault('do_spots_csv',default.DO_CSV), default_dict.setdefault('do_spots_excel',default.DO_EXCEL),]
460
+ preset= [default_dict.setdefault('do_spots_csv',default.do_csv), default_dict.setdefault('do_spots_excel',default.do_excel),]
357
461
  )
358
462
 
359
463
  return layout
360
464
 
361
- def colocalization_layout(spot_list : list) :
362
- layout = [
363
- [sg.Push(), sg.Text("Co-localization", size=25, font="bold"), sg.Push()],
364
- [sg.VPush()],
465
+ def colocalization_layout(spot_list : list, **default_values) :
466
+ default = get_settings()
467
+
468
+ element_dict = {}
469
+ can_use_memory = len(spot_list) != 0
470
+
471
+ for spot_id in [1,2] :
472
+ element_dict[f"radio_spots{spot_id}_memory"] = sg.Radio("From memory : ", group_id = spot_id, enable_events = True, key = f"radio_spots{spot_id}_memory", default= can_use_memory or default_values.get(f"radio_spots{spot_id}_memory"), disabled= not can_use_memory)
473
+ element_dict[f"radio_spots{spot_id}_load"] = sg.Radio("Load spot detection : ", group_id = spot_id, enable_events = True, key = f"radio_spots{spot_id}_load", default= (not can_use_memory) or (default_values.get(f"radio_spots{spot_id}_load")))
474
+
475
+ element_dict[f"spots{spot_id}_browse"] = [
476
+ sg.Input(size=20, key= f"spots{spot_id}_browse", default_text=default_values.get(f"spots{spot_id}_browse"), disabled=can_use_memory and not default_values.get(f"radio_spots{spot_id}_load")),
477
+ sg.FileBrowse(key=f"spots{spot_id}_browsebutton", initial_folder=default_values.setdefault(f"spots{spot_id}_browsebutton", default_values["working_directory"]), disabled=can_use_memory and not default_values.get(f"radio_spots{spot_id}_load")),
478
+ ]
479
+ element_dict[f"spots{spot_id}_voxel_size"] = [
480
+ sg.Text("voxel size"),
481
+ sg.Input(size= 5, key= f"z_voxel_size_spot{spot_id}", default_text= default_values.setdefault(f"z_voxel_size_spot{spot_id}", "z"), disabled=can_use_memory and not default_values.get(f"radio_spots{spot_id}_load")),
482
+ sg.Input(size= 5, key= f"y_voxel_size_spot{spot_id}", default_text= default_values.setdefault(f"y_voxel_size_spot{spot_id}", "y"), disabled=can_use_memory and not default_values.get(f"radio_spots{spot_id}_load")),
483
+ sg.Input(size= 5, key= f"x_voxel_size_spot{spot_id}", default_text= default_values.setdefault(f"x_voxel_size_spot{spot_id}", "x"), disabled=can_use_memory and not default_values.get(f"radio_spots{spot_id}_load")),
484
+ ]
485
+
486
+ #Ref for updating
487
+ element_dict[f"options_spots{spot_id}_memory"] = sg.Col(
488
+ [[sg.DropDown(values=[""] + spot_list, key=f"spots{spot_id}_dropdown", size= 10, disabled= not can_use_memory or default_values.get(f"radio_spots{spot_id}_load"), default_value= default_values.setdefault(f"spots{spot_id}_dropdown", ""))]]
489
+ )
490
+ element_dict[f"options_spots{spot_id}_load"] = sg.Col(
491
+ [element_dict[f"spots{spot_id}_browse"], element_dict[f"spots{spot_id}_voxel_size"]]
492
+ )
493
+
494
+ col1 = sg.Col([
365
495
  [sg.Text("Spots 1", size = 10)],
366
- [sg.DropDown(values=[""] + spot_list, key="spots1_dropdown"), sg.Input(disabled=True, text_color="black"),sg.FileBrowse("Load spot extraction", key="spots1_browse")],
496
+ [element_dict["radio_spots1_memory"]],
497
+ [element_dict["options_spots1_memory"]],
498
+ [element_dict["radio_spots1_load"]],
499
+ [element_dict["options_spots1_load"]],
500
+ ])
501
+
502
+ col2 = sg.Col([
367
503
  [sg.Text("Spots 2", size = 10)],
368
- [sg.DropDown(values=[""] + spot_list, key="spots2_dropdown"), sg.Input(disabled=True, text_color="black"),sg.FileBrowse("Load spot extraction", key="spots2_browse")],
504
+ [element_dict["radio_spots2_memory"]],
505
+ [element_dict["options_spots2_memory"]],
506
+ [element_dict["radio_spots2_load"]],
507
+ [element_dict["options_spots2_load"]],
508
+ ])
509
+
510
+ layout = [
511
+ [sg.Push(), sg.Text("Co-localization", size=50, font="bold"), sg.Push()],
512
+ [sg.VPush()],
513
+ [col1,col2]
514
+ ]
515
+ layout += parameters_layout(['colocalisation distance'], unit= 'nm', default_values= [default_values.setdefault('colocalisation_distance', default_values["coloc_range"])])
516
+ layout += [[sg.Button("Ok", bind_return_key=True),sg.Button("Cancel"),sg.Push(),],
517
+ [sg.VPush()]
369
518
  ]
370
519
 
371
- layout += parameters_layout(['colocalisation distance'], unit= 'nm', default_values= default.COLOC_RANGE,)
520
+ return layout, element_dict
372
521
 
373
- layout += tuple_layout(opt={'voxel_size' : False},unit={'voxel_size' : "nm"}, voxel_size = ['z','y','x'], names={'voxel_size' : 'Voxel size'}, default_dict={'voxel_size' : default.COLOC_VOXEL_SIZE},)
374
- layout += [[sg.Text(" 'voxel size' is used only for loaded spot lists.")]]
522
+ def settings_layout(default_values : SettingsDict = get_default_settings()) :
375
523
 
376
- layout += [[sg.Push(),sg.Button("Ok", bind_return_key=True),sg.Button("Cancel"),sg.Push(),],
377
- [sg.VPush()]
378
- ]
524
+ if not isinstance(default_values, SettingsDict) : raise TypeError(f"Incorect type for default_values : {type(default_values)}; expected SettingsDict")
525
+ models_list = models.get_user_models() + models.MODEL_NAMES
526
+
527
+ layout = [[sg.Text("Default values", font="ArialBold 20")]]
528
+ layout += [[sg.Text("Default working directory"), sg.Input(default_text=default_values.working_directory, key= "working_directory"), sg.FolderBrowse()]]
529
+
530
+ image_layout = [[sg.Text("Image", font="ArialBold 15")]]
531
+ image_layout += bool_layout(['Multichannel stack', '3D stack'],preset= [default_values.multichannel_stack, default_values.stack_3D], keys=["multichannel_stack", "stack_3D"])
532
+ image_layout += parameters_layout(['Detection channel', 'Nucleus channel'],default_values=[default_values.detection_channel, default_values.nucleus_channel], keys=['detection_channel', 'nucleus_channel'])
533
+
534
+ segmentation_layout = [[sg.Text("Segmentation", font="ArialBold 15")],
535
+ [sg.Text("Cytoplasm model : "), sg.DropDown(models_list, default_value=default_values.cytoplasm_model, key= "cytoplasm_model")],
536
+ [sg.Radio(default= default_values.cytoplasm_mean_proj, group_id=0, key="cytoplasm_mean_proj", text= "mean proj"), sg.Radio(default=default_values.cytoplasm_max_proj, group_id=0, key="cytoplasm_max_proj", text= "max proj"), sg.Radio(default= default_values.cytoplasm_select_slice, group_id=0, key="cytoplasm_select_slice", text= "single slice"), sg.Input(default_values.cytoplasm_selected_slice, size=5, key= "cytoplasm_selected_slice")],
537
+ [sg.Text("Nucleus model : "), sg.DropDown(models_list, default_value=default_values.nucleus_model, key= "nucleus_model")],
538
+ [sg.Radio(default= default_values.nucleus_mean_proj, group_id=1, key="nucleus_mean_proj", text= "mean proj"), sg.Radio(default= default_values.nucleus_max_proj, group_id=1, key="nucleus_max_proj", text= "max proj"), sg.Radio(default= default_values.nucleus_select_slice, group_id=1, key="nucleus_select_slice", text= "single slice"), sg.Input(default_values.nucleus_selected_slice, size=5, key= "nucleus_selected_slice")],
539
+ ]
540
+ segmentation_layout += parameters_layout(
541
+ ["Flow threshold", "Cellprob threshold", "Cytoplasm diameter", "Cytoplasm min size", "Nucleus diameter", "Nucleus min size", "Anisotropy"],
542
+ default_values= [default_values.flow_threshold, default_values.cellprob_threshold, default_values.cytoplasm_diameter, default_values.cytoplasm_min_size, default_values.nucleus_diameter, default_values.nucleus_min_size, default_values.anisotropy],
543
+ keys=["flow_threshold", "cellprob_threshold", "cytoplasm_diameter", "cytoplasm_min_size", "nucleus_diameter", "nucleus_min_size", "anisotropy"])
544
+ segmentation_layout += bool_layout(
545
+ ["show segmentation", "segment only nuclei", "do 3D segmentation", "save segmentation visual"],
546
+ preset=[default_values.show_segmentation, default_values.segment_only_nuclei, default_values.do_3D_segmentation, default_values.save_segmentation_visuals],
547
+ keys= ["show_segmentation", "segment_only_nuclei", "do_3D_segmentation","save_segmentation_visuals"])
548
+
549
+ detection_layout = [[sg.Text("Detection", font="ArialBold 15")]]
550
+ detection_layout += parameters_layout(
551
+ ["Threshold", "Threshold penalty"],
552
+ default_values=[default_values.threshold, default_values.threshold_penalty],
553
+ keys=["threshold", "threshold_penalty"])
554
+ detection_layout += bool_layout(
555
+ ["Dense regions deconvolution", "Cluster computation", "show napari corrector", "Autofloresnce background removal", "interactive threshold selector"],
556
+ preset=[default_values.do_dense_regions_deconvolution, default_values.do_cluster, default_values.show_napari_corrector, default_values.do_background_removal, default_values.interactive_threshold_selector],
557
+ keys=["do_dense_regions_deconvolution", "do_cluster", "show_napari_corrector","do_background_removal", "interactive_threshold_selector"])
558
+
559
+ deconvolution_layout = [[sg.Text("Dense regions deconvolution", font="ArialBold 15")]]
560
+ deconvolution_layout += parameters_layout(
561
+ ["alpha", "beta", "gamma"],
562
+ default_values=[default_values.alpha, default_values.beta, default_values.gamma]
563
+ )
564
+
565
+ clustering_layout = [[sg.Text("Cluster computation", font="ArialBold 15")]]
566
+ clustering_layout += parameters_layout(
567
+ ["Cluster size", "Min spot number"],
568
+ default_values=[default_values.cluster_size, default_values.min_spot],
569
+ keys=["cluster_size", "min_spot"])
570
+
571
+ coloc_layout = [[sg.Text("Co-localization computation", font="ArialBold 15")]]
572
+ coloc_layout += parameters_layout(['Co-localization range'],
573
+ default_values=[default_values.coloc_range],
574
+ keys=['coloc_range'])
575
+ coloc_layout += tuple_layout(default_dict= {
576
+ 'voxel_size_z' : default_values.voxel_size[0],
577
+ 'voxel_size_y' : default_values.voxel_size[1],
578
+ 'voxel_size_x' : default_values.voxel_size[2],
579
+ }, voxel_size=('z','y','x'))
580
+
581
+ spot_extraction_layout = [[sg.Text("Spots extraction", font="ArialBold 15")]]
582
+ spot_extraction_layout += bool_layout(
583
+ ["do csv", "do excel"],
584
+ preset=[default_values.do_csv, default_values.do_excel],
585
+ keys=["do_csv", "do_excel"]
586
+ )
587
+ spot_extraction_layout += [[sg.Text("spot extraction folder"), sg.Input(default_text=default_values.spot_extraction_folder, key="spot_extraction_folder", size=7) ,sg.FolderBrowse()]]
588
+
589
+ background_removing_layout = [[sg.Text("Background removing (batch)", font="ArialBold 15")]]
590
+ background_removing_layout += [
591
+ [sg.Checkbox("Remove background :", key= "do_background_removal", default= settings.do_background_removal)],
592
+ [sg.Text("Background channel : "), sg.Input(settings.background_channel, key = "background_channel", size= 5)]
593
+ ]
594
+
595
+ layout += [[sg.Col(image_layout, vertical_alignment='top', expand_x = True), sg.Col(background_removing_layout, vertical_alignment='top', expand_x = True)]]
596
+ layout += [[sg.Col(segmentation_layout, vertical_alignment='top', expand_x = True), sg.Col(detection_layout, vertical_alignment='top', expand_x = True)]]
597
+ layout += [[sg.Col(deconvolution_layout, vertical_alignment='top', expand_x = True), sg.Col(clustering_layout, vertical_alignment='top', expand_x = True)]]
598
+ layout += [[sg.Col(spot_extraction_layout, vertical_alignment='top', expand_x = True), sg.Col(coloc_layout, vertical_alignment='top', expand_x = True)]]
379
599
 
380
600
  return layout
381
601
 
382
602
  def _ask_channel_map_layout(
383
603
  shape,
384
604
  is_3D_stack,
385
- multichannel,
605
+ is_multichannel,
386
606
  is_time_stack,
387
607
  preset_map={},
388
- ) :
608
+ ) :
389
609
 
390
610
  x = preset_map.setdefault('x',0)
391
611
  y = preset_map.setdefault('y',0)
@@ -394,11 +614,11 @@ def _ask_channel_map_layout(
394
614
  t = preset_map.setdefault('t',0)
395
615
 
396
616
  layout = [
397
- add_header("Dimensions mapping"), [sg.Text("Image shape : {0}".format(shape))]
617
+ [sg.Text("Dimensions mapping", font= "bold 15"), sg.Text("Image shape : {0}".format(shape))]
398
618
  ]
399
619
  layout += parameters_layout(['x','y'], default_values=[x,y])
400
620
  if is_3D_stack : layout += parameters_layout(['z'], default_values=[z])
401
- if multichannel : layout += parameters_layout(['c'], default_values=[c])
621
+ if is_multichannel : layout += parameters_layout(['c'], default_values=[c])
402
622
  if is_time_stack : layout += parameters_layout(['t'], default_values=[t])
403
623
 
404
624
  return layout