small-fish-gui 1.3.3__tar.gz → 1.3.5__tar.gz

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 (41) hide show
  1. {small_fish_gui-1.3.3 → small_fish_gui-1.3.5}/PKG-INFO +1 -1
  2. {small_fish_gui-1.3.3 → small_fish_gui-1.3.5}/pyproject.toml +1 -1
  3. {small_fish_gui-1.3.3 → small_fish_gui-1.3.5}/src/small_fish_gui/__init__.py +1 -1
  4. {small_fish_gui-1.3.3 → small_fish_gui-1.3.5}/src/small_fish_gui/gui/__init__.py +1 -2
  5. small_fish_gui-1.3.5/src/small_fish_gui/gui/batch.py +312 -0
  6. small_fish_gui-1.3.5/src/small_fish_gui/gui/layout.py +307 -0
  7. {small_fish_gui-1.3.3 → small_fish_gui-1.3.5}/src/small_fish_gui/gui/prompts.py +21 -23
  8. small_fish_gui-1.3.5/src/small_fish_gui/gui/test.py +5 -0
  9. {small_fish_gui-1.3.3 → small_fish_gui-1.3.5}/src/small_fish_gui/pipeline/_napari_wrapper.py +3 -2
  10. {small_fish_gui-1.3.3 → small_fish_gui-1.3.5}/src/small_fish_gui/pipeline/_preprocess.py +10 -11
  11. {small_fish_gui-1.3.3 → small_fish_gui-1.3.5}/src/small_fish_gui/pipeline/_segmentation.py +1 -1
  12. {small_fish_gui-1.3.3 → small_fish_gui-1.3.5}/src/small_fish_gui/pipeline/detection.py +4 -1
  13. small_fish_gui-1.3.3/src/small_fish_gui/gui/layout.py +0 -184
  14. small_fish_gui-1.3.3/src/small_fish_gui/gui/test.py +0 -4
  15. {small_fish_gui-1.3.3 → small_fish_gui-1.3.5}/LICENSE +0 -0
  16. {small_fish_gui-1.3.3 → small_fish_gui-1.3.5}/README.md +0 -0
  17. {small_fish_gui-1.3.3 → small_fish_gui-1.3.5}/src/small_fish_gui/.github/workflows/python-publish.yml +0 -0
  18. {small_fish_gui-1.3.3 → small_fish_gui-1.3.5}/src/small_fish_gui/LICENSE +0 -0
  19. {small_fish_gui-1.3.3 → small_fish_gui-1.3.5}/src/small_fish_gui/README.md +0 -0
  20. {small_fish_gui-1.3.3 → small_fish_gui-1.3.5}/src/small_fish_gui/Segmentation example.jpg +0 -0
  21. {small_fish_gui-1.3.3 → small_fish_gui-1.3.5}/src/small_fish_gui/__main__.py +0 -0
  22. {small_fish_gui-1.3.3 → small_fish_gui-1.3.5}/src/small_fish_gui/gui/animation.py +0 -0
  23. {small_fish_gui-1.3.3 → small_fish_gui-1.3.5}/src/small_fish_gui/gui/general_help_screenshot.png +0 -0
  24. {small_fish_gui-1.3.3 → small_fish_gui-1.3.5}/src/small_fish_gui/gui/help_module.py +0 -0
  25. {small_fish_gui-1.3.3 → small_fish_gui-1.3.5}/src/small_fish_gui/gui/mapping_help_screenshot.png +0 -0
  26. {small_fish_gui-1.3.3 → small_fish_gui-1.3.5}/src/small_fish_gui/gui/segmentation_help_screenshot.png +0 -0
  27. {small_fish_gui-1.3.3 → small_fish_gui-1.3.5}/src/small_fish_gui/interface/__init__.py +0 -0
  28. {small_fish_gui-1.3.3 → small_fish_gui-1.3.5}/src/small_fish_gui/interface/image.py +0 -0
  29. {small_fish_gui-1.3.3 → small_fish_gui-1.3.5}/src/small_fish_gui/interface/output.py +0 -0
  30. {small_fish_gui-1.3.3 → small_fish_gui-1.3.5}/src/small_fish_gui/interface/parameters.py +0 -0
  31. {small_fish_gui-1.3.3 → small_fish_gui-1.3.5}/src/small_fish_gui/interface/testing.py +0 -0
  32. {small_fish_gui-1.3.3 → small_fish_gui-1.3.5}/src/small_fish_gui/napari_detection_example.png +0 -0
  33. {small_fish_gui-1.3.3 → small_fish_gui-1.3.5}/src/small_fish_gui/pipeline/_colocalisation.py +0 -0
  34. {small_fish_gui-1.3.3 → small_fish_gui-1.3.5}/src/small_fish_gui/pipeline/_custom_errors.py +0 -0
  35. {small_fish_gui-1.3.3 → small_fish_gui-1.3.5}/src/small_fish_gui/pipeline/_signaltonoise.py +0 -0
  36. {small_fish_gui-1.3.3 → small_fish_gui-1.3.5}/src/small_fish_gui/pipeline/actions.py +0 -0
  37. {small_fish_gui-1.3.3 → small_fish_gui-1.3.5}/src/small_fish_gui/pipeline/main.py +0 -0
  38. {small_fish_gui-1.3.3 → small_fish_gui-1.3.5}/src/small_fish_gui/pipeline/spots.py +0 -0
  39. {small_fish_gui-1.3.3 → small_fish_gui-1.3.5}/src/small_fish_gui/pipeline/test.py +0 -0
  40. {small_fish_gui-1.3.3 → small_fish_gui-1.3.5}/src/small_fish_gui/requirements.txt +0 -0
  41. {small_fish_gui-1.3.3 → small_fish_gui-1.3.5}/src/small_fish_gui/utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: small_fish_gui
3
- Version: 1.3.3
3
+ Version: 1.3.5
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/2Echoes/small_fish
6
6
  Project-URL: Issues, https://github.com/2Echoes/small_fish/issues
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "small_fish_gui"
7
- version = "1.3.3"
7
+ version = "1.3.5"
8
8
  authors = [
9
9
  { name="Slimani Floric", email="floric.slimani@live.com" },
10
10
  ]
@@ -38,4 +38,4 @@ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
38
38
  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39
39
 
40
40
  """
41
- __version__ = "1.3.3"
41
+ __version__ = "1.3.5"
@@ -10,7 +10,6 @@ from .prompts import input_image_prompt
10
10
  from .prompts import hub_prompt
11
11
  from .prompts import detection_parameters_promt
12
12
  from .prompts import coloc_prompt
13
- from .prompts import post_analysis_prompt
14
13
  from .prompts import output_image_prompt
15
14
  from .prompts import ask_cancel_detection
16
15
  from .prompts import ask_cancel_segmentation
@@ -21,7 +20,7 @@ from .prompts import ask_detection_confirmation
21
20
  from .layout import parameters_layout
22
21
  from .layout import bool_layout
23
22
  from .layout import path_layout
24
- from .layout import combo_layout
23
+ from .layout import combo_elmt
25
24
  from .layout import tuple_layout
26
25
  from .layout import radio_layout
27
26
  from .layout import add_header
@@ -0,0 +1,312 @@
1
+ import os
2
+ import numpy as np
3
+ import PySimpleGUI as sg
4
+ import bigfish.stack as stack
5
+ import czifile as czi
6
+
7
+ from .layout import _segmentation_layout, _detection_layout, _input_parameters_layout, _ask_channel_map_layout
8
+
9
+
10
+ from time import sleep
11
+
12
+ def get_images(filename:str) :
13
+ """returns filename if is image else return None"""
14
+
15
+ supported_types = ('.tiff', '.tif', '.png', '.czi')
16
+ if filename.endswith(supported_types) :
17
+ return [filename]
18
+ else :
19
+ return None
20
+
21
+
22
+ def get_files(path) :
23
+
24
+ filelist = os.listdir(path)
25
+ filelist = list(map(get_images,filelist))
26
+
27
+ while None in filelist : filelist.remove(None)
28
+
29
+ return filelist
30
+
31
+ def extract_files(filenames: list) :
32
+ return sum(filenames,[])
33
+
34
+ def check_file(filename:str) :
35
+
36
+ if filename.endswith('.czi') :
37
+ image = czi.imread(filename)
38
+ else :
39
+ image = stack.read_image(filename)
40
+
41
+ image = np.squeeze(image)
42
+
43
+ return image.shape
44
+
45
+ def sanity_check(
46
+ filename_list: list,
47
+ batch_folder : str,
48
+ window : sg.Window,
49
+ progress_bar: sg.ProgressBar,
50
+ ) :
51
+
52
+ filenumber = len(filename_list)
53
+ if filenumber == 0 :
54
+ print("No file to check")
55
+ progress_bar.update(current_count= 0, bar_color=('gray','gray'))
56
+ return None
57
+ else :
58
+ print("{0} files to check".format(filenumber))
59
+ progress_bar.update(current_count=0, max= filenumber)
60
+ ref_shape = check_file(batch_folder + '/' + filename_list[0])
61
+
62
+ print("Starting sanity check. This could take some time...")
63
+ for i, file in enumerate(filename_list) :
64
+ progress_bar.update(current_count= i+1, bar_color=('green','gray'))
65
+ shape = check_file(batch_folder + '/' + file)
66
+
67
+ if len(shape) != len(ref_shape) : #then dimension missmatch
68
+ print("Different number of dimensions found : {0}, {1}".format(len(ref_shape), len(shape)))
69
+ progress_bar.update(current_count=filenumber, bar_color=('red','black'))
70
+ window= window.refresh()
71
+ break
72
+
73
+ window= window.refresh()
74
+
75
+ print("Sanity check completed.")
76
+ return None if len(shape) != len(ref_shape) else shape
77
+
78
+
79
+ def get_elmt_from_key(Tab_elmt:sg.Tab, key) -> sg.Element:
80
+ elmt_list = sum(Tab_elmt.Rows,[])
81
+ for elmt in elmt_list :
82
+ if elmt.Key == key : return elmt
83
+ raise KeyError("{0} key not found amongst {1}.".format(key, [elmt.Key for elmt in elmt_list]))
84
+
85
+ def update_detection_tab(
86
+ tab_elmt:sg.Tab,
87
+ is_multichannel,
88
+ is_3D,
89
+ do_dense_region_deconvolution,
90
+ do_clustering
91
+ ) :
92
+
93
+ #Acess elements
94
+ ##Detection
95
+ channel_to_compute = get_elmt_from_key(tab_elmt, key= 'channel to compute')
96
+ voxel_size_z = get_elmt_from_key(tab_elmt, key= 'voxel_size_z')
97
+ spot_size_z = get_elmt_from_key(tab_elmt, key= 'spot_size_z')
98
+ log_kernel_size_z = get_elmt_from_key(tab_elmt, key= 'log_kernel_size_z')
99
+ minimum_distance_z = get_elmt_from_key(tab_elmt, key= 'minimum_distance_z')
100
+
101
+ ##Dense regions deconvolution
102
+ alpha = get_elmt_from_key(tab_elmt, key= 'alpha')
103
+ beta = get_elmt_from_key(tab_elmt, key= 'beta')
104
+ gamma = get_elmt_from_key(tab_elmt, key= 'gamma')
105
+ deconvolution_kernel_z = get_elmt_from_key(tab_elmt, key= 'deconvolution_kernel_z')
106
+ cluster_size = get_elmt_from_key(tab_elmt, key= 'cluster size')
107
+ min_number_of_spot = get_elmt_from_key(tab_elmt, key= 'min number of spots')
108
+ nucleus_channel_signal = get_elmt_from_key(tab_elmt, key= 'nucleus channel signal')
109
+ interactive_threshold_selector = get_elmt_from_key(tab_elmt, key= 'Interactive threshold selector')
110
+
111
+ update_dict={
112
+ 'is_3D' : is_3D,
113
+ 'is_multichannel' : is_multichannel,
114
+ 'do_dense_region_deconvolution' : do_dense_region_deconvolution,
115
+ 'do_clustering' : do_clustering,
116
+ 'always_hidden' : False
117
+ }
118
+
119
+ list_dict={
120
+ 'is_3D' : [voxel_size_z, spot_size_z, log_kernel_size_z, minimum_distance_z, deconvolution_kernel_z],
121
+ 'is_multichannel' : [channel_to_compute, nucleus_channel_signal],
122
+ 'do_dense_region_deconvolution' : [alpha,beta,gamma],
123
+ 'do_clustering' : [cluster_size, min_number_of_spot],
124
+ 'always_hidden' : [interactive_threshold_selector]
125
+
126
+ }
127
+
128
+ for key, enabled in update_dict.items() :
129
+ for elmt in list_dict.get(key) :
130
+ elmt.update(disabled=not enabled)
131
+
132
+
133
+
134
+ def update_segmentation_tab(tab_elmt : sg.Tab, do_segmentation, is_multichannel) : #TODO
135
+
136
+ #Access elements
137
+ cytoplasm_channel_elmt = get_elmt_from_key(tab_elmt, key= 'cytoplasm channel')
138
+ nucleus_channel_elmt = get_elmt_from_key(tab_elmt, key= 'nucleus channel')
139
+
140
+ #Update values
141
+ tab_elmt.update(visible=do_segmentation)
142
+ cytoplasm_channel_elmt.update(disabled = not is_multichannel)
143
+ nucleus_channel_elmt.update(disabled = not is_multichannel)
144
+
145
+ def update_map_tab() :
146
+ #TODO
147
+ pass
148
+
149
+ def batch_promp() :
150
+
151
+ files_values = [[]]
152
+
153
+
154
+ #LOAD FILES
155
+ files_table = sg.Table(values=files_values, headings=['Filenames'], col_widths=100, max_col_width= 200, def_col_width=100, num_rows= 10, auto_size_columns=False)
156
+
157
+ #Start&Stop
158
+ start_button =sg.Button('Start', button_color= 'green', disabled= True)
159
+ stop_button = sg.Button('Cancel', button_color= 'red')
160
+
161
+ #DIMENSION SANITY
162
+ sanity_progress = sg.ProgressBar(10, size_px=(500,10))
163
+ sanity_check_button = sg.Button(
164
+ 'Check',
165
+ tooltip= "Will check that all files loaded have the same dimension number and that small fish is able to open them.",
166
+ pad=(10,0))
167
+ sanity_header = sg.Text("Dimension sanity", font=('bold',15), pad=(0,10))
168
+ dimension_number_text = sg.Text("Dimension number : unknown")
169
+
170
+ #Input tab
171
+ input_layout = _input_parameters_layout(
172
+ ask_for_segmentation=True,
173
+ is_3D_stack_preset=False,
174
+ time_stack_preset=False,
175
+ multichannel_preset=False,
176
+ do_dense_regions_deconvolution_preset=False,
177
+ do_clustering_preset=False,
178
+ do_Napari_correction=False,
179
+ do_segmentation_preset=False,
180
+ )
181
+ input_layout += [[sg.Button('Ok')]]
182
+ input_tab = sg.Tab("Input", input_layout)
183
+
184
+ #Maptab
185
+ map_layout = _ask_channel_map_layout(
186
+ shape=(0,1,2,3,4),
187
+ is_3D_stack=True,
188
+ is_time_stack=True,
189
+ multichannel=True,
190
+ )
191
+ last_shape_read = sg.Text("Last shape read : None")
192
+ auto_map = sg.Button("auto-map", disabled=True, pad=(10,0))
193
+ map_layout += [[last_shape_read, auto_map]]
194
+ map_tab = sg.Tab("Map", map_layout)
195
+
196
+ #Segmentation tab
197
+ segmentation_layout = _segmentation_layout(multichannel=True, cytoplasm_model_preset='cyto3')
198
+ segmentation_tab = sg.Tab("Segmentation", segmentation_layout, visible=False)
199
+
200
+ #Detection tab
201
+ detection_layout = _detection_layout(
202
+ is_3D_stack=True,
203
+ is_multichannel=True,
204
+ do_clustering=True,
205
+ do_dense_region_deconvolution=True,
206
+ do_segmentation=True,
207
+ )
208
+
209
+
210
+ detection_tab = sg.Tab("Detection", detection_layout)
211
+
212
+
213
+
214
+ #TABS
215
+ _tab_group = sg.TabGroup([[input_tab, map_tab, segmentation_tab, detection_tab]], enable_events=True)
216
+ tab_group = sg.Column( #Allow the tab to be scrollable
217
+ [[_tab_group]],
218
+ scrollable=True,
219
+ vertical_scroll_only=True,
220
+ pad=(150,5)
221
+ )
222
+ tab_dict= {
223
+ "Input" : input_tab,
224
+ "Segmentation" : segmentation_tab,
225
+ "Detection" : detection_tab,
226
+ "Map" : map_tab,
227
+ }
228
+
229
+ layout = [
230
+ [sg.Text("Batch Processing", font=('bold',20), pad=((300,0),(0,2)))],
231
+ [sg.Text("Select a folder : "), sg.FolderBrowse(initial_folder=os.getcwd(), key='Batch_folder'), sg.Button('Load')],
232
+ [files_table],
233
+ [sanity_header, sanity_check_button, sanity_progress],
234
+ [dimension_number_text],
235
+ [tab_group],
236
+ [sg.Output(size=(100,10), pad=(30,10))],
237
+ [start_button, stop_button],
238
+ ]
239
+
240
+ window = sg.Window("small fish", layout=layout, size= (800,800), auto_size_buttons=True, auto_size_text=True)
241
+ loop = 0
242
+ timeout = 1
243
+ while True :
244
+ loop +=1
245
+ window = window.refresh()
246
+ event, values = window.read(timeout=timeout)
247
+
248
+ #Welcome message
249
+ if loop == 1 :
250
+ timeout = None
251
+ print("Welcome to small fish batch analysis. Please start by loading some files and setting parameters.")
252
+
253
+ batch_folder = values.get('Batch_folder')
254
+ is_multichanel = values.get('multichannel')
255
+ is_3D = values.get('3D stack')
256
+ do_segmentation = values.get('Segmentation')
257
+ do_dense_regions_deconvolution = values.get('Dense regions deconvolution')
258
+ do_clustering = values.get('Cluster computation')
259
+
260
+ if type(batch_folder) != type(None) and event == 'Load':
261
+ if not os.path.isdir(batch_folder) :
262
+ print("Can't open {0}".format(batch_folder))
263
+ else :
264
+ files_values = get_files(batch_folder)
265
+ files_table.update(values=files_values)
266
+
267
+ elif event == 'Check' :
268
+ filename_list = extract_files(files_values)
269
+ last_shape = sanity_check(
270
+ filename_list=filename_list,
271
+ batch_folder=batch_folder,
272
+ window=window,
273
+ progress_bar=sanity_progress
274
+ )
275
+ if isinstance(last_shape,(tuple,list)) :
276
+ dim_number = len(last_shape)
277
+ dimension_number_text.update("Dimension number : {0}".format(dim_number))
278
+ auto_map.update(disabled=False)
279
+ else :
280
+ dimension_number_text.update("Dimension number : unknown")
281
+ auto_map.update(disabled=True)
282
+
283
+ last_shape_read.update("Last shape read : {0}".format(last_shape))
284
+
285
+
286
+ elif event == _tab_group.key or event == 'Ok': #Tab switch in parameters
287
+ update_segmentation_tab(
288
+ tab_elmt=tab_dict.get("Segmentation"),
289
+ do_segmentation=do_segmentation,
290
+ is_multichannel=is_multichanel,
291
+ )
292
+
293
+ update_detection_tab(
294
+ tab_elmt=tab_dict.get("Detection"),
295
+ is_multichannel=is_multichanel,
296
+ is_3D=is_3D,
297
+ do_dense_region_deconvolution=do_dense_regions_deconvolution,
298
+ do_clustering=do_clustering,
299
+ )
300
+
301
+ elif event == 'auto-map' :
302
+ #TODO
303
+ pass
304
+
305
+ # elif event == 'apply' (map) #TODO
306
+
307
+ # elif event == 'check parameters' -> un/lock start #TODO
308
+
309
+ elif event == "Cancel" :
310
+ print(values)
311
+ elif event == None :
312
+ quit()
@@ -0,0 +1,307 @@
1
+ import PySimpleGUI as sg
2
+ import os
3
+ from ..utils import check_parameter
4
+ import cellpose.models as models
5
+ from cellpose.core import use_gpu
6
+
7
+ sg.theme('DarkAmber')
8
+
9
+
10
+ def add_header(header_text) :
11
+ """Returns [elmnt] not layout"""
12
+ header = [sg.Text('\n{0}'.format(header_text), size= (len(header_text),3), font= 'bold 15')]
13
+ return header
14
+
15
+
16
+ def pad_right(string, length, pad_char) :
17
+ if len(string) >= length : return string
18
+ else : return string + pad_char* (length - len(string))
19
+
20
+
21
+ def parameters_layout(parameters:'list[str]' = [], unit=None, header= None, default_values=None, size=5, opt=None) :
22
+
23
+ if len(parameters) == 0 : return []
24
+ check_parameter(parameters= list, header = (str, type(None)))
25
+ for key in parameters : check_parameter(key = str)
26
+ max_length = len(max(parameters, key=len))
27
+
28
+ if type(opt) == type(None) :
29
+ opt = [False] * len(parameters)
30
+ else :
31
+ if len(opt) != len(parameters) : raise ValueError("Parameters and opt must be of same length.")
32
+
33
+ if isinstance(default_values, (list, tuple)) :
34
+ if len(default_values) != len(parameters) : raise ValueError("if default values specified it must be of equal length as parameters.")
35
+ layout= [
36
+ [sg.Text("{0}".format(pad_right(parameter, max_length, ' ')), text_color= 'green' if option else None),
37
+ sg.InputText(size= size, key= parameter, default_text= value)
38
+
39
+ ] for parameter,value, option in zip(parameters,default_values, opt)
40
+ ]
41
+ else :
42
+ layout= [
43
+ [sg.Text("{0}".format(pad_right(parameter, max_length, ' ')), text_color= 'green' if option else None),
44
+ sg.InputText(size= size, key= parameter)
45
+
46
+ ] for parameter, option in zip(parameters, opt)
47
+ ]
48
+
49
+ if type(unit) == str :
50
+ for line_id, line in enumerate(layout) :
51
+ layout[line_id] += [sg.Text('{0}'.format(unit))]
52
+
53
+ if isinstance(header, str) :
54
+ layout = [add_header(header)] + layout
55
+ return layout
56
+
57
+ def tuple_layout(opt=None, default_dict={}, unit:dict={}, **tuples) :
58
+ """
59
+ tuples example : voxel_size = ['z','y','x']; will ask a tuple with 3 element default to 'z', 'y' 'x'.
60
+ """
61
+ if type(tuples) == type(None) : return []
62
+ if len(tuples.keys()) == 0 : return []
63
+
64
+ if type(opt) != type(None) :
65
+ if not isinstance(opt, dict) : raise TypeError("opt parameter should be either None or dict type.")
66
+ if not opt.keys() == tuples.keys() : raise ValueError("If opt is passed it is expected to have same keys as tuples dict.")
67
+ else :
68
+ opt = tuples.copy()
69
+ for key in opt.keys() :
70
+ opt[key] = False
71
+
72
+ for tup in tuples :
73
+ if not isinstance(tuples[tup], (list,tuple)) : raise TypeError()
74
+
75
+ max_size = len(max(tuples.keys(), key=len))
76
+
77
+ layout = [
78
+ [sg.Text(pad_right(tup, max_size, ' '), text_color= 'green' if opt[option] else None)]
79
+ + [sg.InputText(default_text=default_dict.setdefault('{0}_{1}'.format(tup,elmnt), elmnt),key= '{0}_{1}'.format(tup, elmnt), size= 5) for elmnt in tuples[tup]]
80
+ + [sg.Text(unit.setdefault(tup,''))]
81
+ for tup,option, in zip(tuples,opt)
82
+ ]
83
+
84
+ return layout
85
+
86
+ def path_layout(keys= [],look_for_dir = False, header=None, preset=os.getcwd()) :
87
+ """
88
+ If not look for dir then looks for file.
89
+ """
90
+ if len(keys) == 0 : return []
91
+ check_parameter(keys= list, header = (str, type(None)))
92
+ for key in keys : check_parameter(key = str)
93
+ if look_for_dir : Browse = sg.FolderBrowse
94
+ else : Browse = sg.FileBrowse
95
+
96
+ max_length = len(max(keys, key=len))
97
+ layout = [
98
+ [sg.Text(pad_right(name, max_length, ' ')), Browse(key= name, initial_folder= preset)] for name in keys
99
+ ]
100
+ if isinstance(header, str) :
101
+ layout = [add_header(header)] + layout
102
+ return layout
103
+
104
+ def bool_layout(parameters= [], header=None, preset=None) :
105
+ if len(parameters) == 0 : return []
106
+ check_parameter(parameters= list, header= (str, type(None)), preset=(type(None), list, tuple, bool))
107
+ for key in parameters : check_parameter(key = str)
108
+ if type(preset) == type(None) :
109
+ preset = [False] * len(parameters)
110
+ elif type(preset) == bool :
111
+ preset = [preset] * len(parameters)
112
+ else :
113
+ for key in preset : check_parameter(key = bool)
114
+
115
+
116
+
117
+ max_length = len(max(parameters, key=len))
118
+ layout = [
119
+ [sg.Checkbox(pad_right(name, max_length, ' '), key= name, default=box_preset)] for name, box_preset in zip(parameters,preset)
120
+ ]
121
+ if isinstance(header, str) :
122
+ layout = [add_header(header)] + layout
123
+ return layout
124
+
125
+ def combo_elmt(values, key, header=None, read_only=True, default_value=None) :
126
+ """
127
+ drop-down list
128
+ """
129
+ if len(values) == 0 : return []
130
+ check_parameter(values= list, header= (str, type(None)))
131
+ if type(default_value) == type(None) :
132
+ default_value = values[0]
133
+ elif default_value not in values :
134
+ default_value = values[0]
135
+ layout = [
136
+ sg.Combo(values, default_value=default_value, readonly=read_only, key=key)
137
+ ]
138
+ if isinstance(header, str) :
139
+ layout = add_header(header) + layout
140
+ return layout
141
+
142
+ def radio_layout(values, header=None) :
143
+ """
144
+ Single choice buttons.
145
+ """
146
+ if len(values) == 0 : return []
147
+ check_parameter(values= list, header= (str, type(None)))
148
+ layout = [
149
+ [sg.Radio(value, group_id= 0) for value in values]
150
+ ]
151
+ if isinstance(header, str) :
152
+ layout = [add_header(header)] + layout
153
+ return layout
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',) :
156
+
157
+ USE_GPU = use_gpu()
158
+
159
+ models_list = models.get_user_models() + models.MODEL_NAMES
160
+ if len(models_list) == 0 : models_list = ['no model found']
161
+
162
+ #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')]]
164
+
165
+ #cytoplasm parameters
166
+ layout += [
167
+ add_header("Cell Segmentation"),
168
+ [sg.Text("Choose cellpose model for cytoplasm: \n")],
169
+ combo_elmt(models_list, key='cyto_model_name', default_value= cytoplasm_model_preset)
170
+ ]
171
+
172
+ if multichannel : layout += parameters_layout(['cytoplasm channel'],default_values= [cytoplasm_channel_preset])
173
+ layout += parameters_layout(['cytoplasm diameter'], unit= "px", default_values= [cyto_diameter_preset])
174
+ #Nucleus parameters
175
+ layout += [
176
+ add_header("Nucleus segmentation"),
177
+ [sg.Text("Choose cellpose model for nucleus: \n")],
178
+ combo_elmt(models_list, key='nucleus_model_name', default_value= nucleus_model_preset)
179
+ ]
180
+
181
+ if multichannel : layout += parameters_layout(['nucleus channel'], default_values= [nucleus_channel_preset])
182
+ layout += parameters_layout([ 'nucleus diameter'],unit= "px", default_values= [nucleus_diameter_preset])
183
+ layout += bool_layout(["Segment only nuclei"], preset=segment_only_nuclei_preset)
184
+
185
+ #Control plots
186
+ layout += bool_layout(['show segmentation'], header= 'Segmentation plots', preset= show_segmentation_preset)
187
+ layout += path_layout(['saving path'], look_for_dir=True, preset=saving_path_preset)
188
+ layout += parameters_layout(['filename'], default_values=[filename_preset], size= 25)
189
+
190
+ return layout
191
+
192
+ def _input_parameters_layout(
193
+ ask_for_segmentation,
194
+ is_3D_stack_preset,
195
+ time_stack_preset,
196
+ multichannel_preset,
197
+ do_dense_regions_deconvolution_preset,
198
+ do_clustering_preset,
199
+ do_segmentation_preset,
200
+ do_Napari_correction
201
+
202
+ ) :
203
+ layout_image_path = path_layout(['image path'], header= "Image")
204
+ layout_image_path += bool_layout(['3D stack', 'multichannel'], preset= [is_3D_stack_preset, time_stack_preset, multichannel_preset])
205
+
206
+ if ask_for_segmentation :
207
+ layout_image_path += bool_layout(
208
+ ['Dense regions deconvolution', 'Cluster computation', 'Segmentation', 'Napari correction'],
209
+ preset= [do_dense_regions_deconvolution_preset, do_clustering_preset, do_segmentation_preset, do_Napari_correction],
210
+ header= "Pipeline settings")
211
+ else :
212
+ layout_image_path += bool_layout(
213
+ ['Dense regions deconvolution', 'Cluster computation', 'Napari correction'],
214
+ preset= [do_dense_regions_deconvolution_preset, do_clustering_preset, do_Napari_correction],
215
+ header= "Pipeline settings")
216
+
217
+ return layout_image_path
218
+
219
+ def _detection_layout(
220
+ is_3D_stack,
221
+ is_multichannel,
222
+ do_dense_region_deconvolution,
223
+ do_clustering,
224
+ do_segmentation,
225
+ segmentation_done=False,
226
+ default_dict={},
227
+ ) :
228
+ if is_3D_stack : dim = 3
229
+ else : dim = 2
230
+
231
+ #Detection
232
+ detection_parameters = ['threshold', 'threshold penalty']
233
+ default_detection = [default_dict.setdefault('threshold',''), default_dict.setdefault('threshold penalty', '1')]
234
+ opt= [True, True]
235
+ if is_multichannel :
236
+ detection_parameters += ['channel to compute']
237
+ opt += [False]
238
+ default_detection += [default_dict.setdefault('channel to compute', '')]
239
+
240
+ layout = [[sg.Text("Green parameters", text_color= 'green'), sg.Text(" are optional parameters.")]]
241
+ layout += parameters_layout(detection_parameters, header= 'Detection', opt=opt, default_values=default_detection)
242
+
243
+ if dim == 2 : tuple_shape = ('y','x')
244
+ else : tuple_shape = ('z','y','x')
245
+ opt = {'voxel_size' : False, 'spot_size' : False, 'log_kernel_size' : True, 'minimum_distance' : True}
246
+ unit = {'voxel_size' : 'nm', 'minimum_distance' : 'nm', 'spot_size' : 'radius(nm)', 'log_kernel_size' : 'px'}
247
+
248
+ 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
+
250
+ #Deconvolution
251
+ if do_dense_region_deconvolution :
252
+ default_dense_regions_deconvolution = [default_dict.setdefault('alpha',0.5), default_dict.setdefault('beta',1)]
253
+ layout += parameters_layout(['alpha', 'beta',], default_values= default_dense_regions_deconvolution, header= 'Dense regions deconvolution')
254
+ layout += parameters_layout(['gamma'], unit= 'px', default_values= [default_dict.setdefault('gamma',5)])
255
+ layout += tuple_layout(opt= {"deconvolution_kernel" : True}, unit= {"deconvolution_kernel" : 'px'}, default_dict=default_dict, deconvolution_kernel = tuple_shape)
256
+
257
+ #Clustering
258
+ if do_clustering :
259
+ layout += parameters_layout(['cluster size'], unit="radius(nm)", default_values=[default_dict.setdefault('cluster size',400)])
260
+ layout += parameters_layout(['min number of spots'], default_values=[default_dict.setdefault('min number of spots', 5)])
261
+
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.")]]
265
+
266
+ layout += bool_layout(['Interactive threshold selector'], preset=[False])
267
+ layout += path_layout(
268
+ keys=['spots_extraction_folder'],
269
+ look_for_dir=True,
270
+ header= "Individual spot extraction",
271
+ preset= default_dict.setdefault('spots_extraction_folder', '')
272
+ )
273
+ layout += parameters_layout(
274
+ parameters=['spots_filename'],
275
+ default_values=[default_dict.setdefault('spots_filename','spots_extraction')],
276
+ size= 13
277
+ )
278
+ layout += bool_layout(
279
+ parameters= ['do_spots_csv', 'do_spots_excel', 'do_spots_feather'],
280
+ preset= [default_dict.setdefault('do_spots_csv',False), default_dict.setdefault('do_spots_excel',False),default_dict.setdefault('do_spots_feather',False)]
281
+ )
282
+
283
+ return layout
284
+
285
+ def _ask_channel_map_layout(
286
+ shape,
287
+ is_3D_stack,
288
+ multichannel,
289
+ is_time_stack,
290
+ preset_map={},
291
+ ) :
292
+
293
+ x = preset_map.setdefault('x',0)
294
+ y = preset_map.setdefault('y',0)
295
+ z = preset_map.setdefault('z',0)
296
+ c = preset_map.setdefault('c',0)
297
+ t = preset_map.setdefault('t',0)
298
+
299
+ layout = [
300
+ add_header("Dimensions mapping"), [sg.Text("Image shape : {0}".format(shape))]
301
+ ]
302
+ layout += parameters_layout(['x','y'], default_values=[x,y])
303
+ if is_3D_stack : layout += parameters_layout(['z'], default_values=[z])
304
+ if multichannel : layout += parameters_layout(['c'], default_values=[c])
305
+ if is_time_stack : layout += parameters_layout(['t'], default_values=[t])
306
+
307
+ return layout
@@ -2,18 +2,24 @@ import PySimpleGUI as sg
2
2
  import pandas as pd
3
3
  import os
4
4
  import numpy as np
5
- from .layout import path_layout, parameters_layout, bool_layout, tuple_layout, combo_layout, add_header, path_layout
5
+ from .layout import path_layout, parameters_layout, bool_layout, tuple_layout, combo_elmt, add_header, path_layout
6
6
  from ..interface import open_image, check_format, FormatError
7
7
  from .help_module import ask_help
8
8
 
9
- def prompt(layout, add_ok_cancel=True, timeout=None, timeout_key='TIMEOUT_KEY') :
9
+ def prompt(layout, add_ok_cancel=True, timeout=None, timeout_key='TIMEOUT_KEY', add_scrollbar=True) :
10
10
  """
11
11
  Default event : 'Ok', 'Cancel'
12
12
  """
13
13
  if add_ok_cancel : layout += [[sg.Button('Ok'), sg.Button('Cancel')]]
14
14
 
15
+ if add_scrollbar :
16
+ size = (400,500)
17
+ col_elmt = sg.Column(layout, scrollable=True, vertical_scroll_only=True, size=size)
18
+ layout = [[col_elmt]]
19
+ else :
20
+ size = (None,None)
15
21
 
16
- window = sg.Window('small fish', layout=layout, margins=(10,10))
22
+ window = sg.Window('small fish', layout=layout, margins=(10,10), size=size, resizable=True)
17
23
  event, values = window.read(timeout=timeout, timeout_key=timeout_key)
18
24
  if event == None :
19
25
  window.close()
@@ -26,12 +32,19 @@ def prompt(layout, add_ok_cancel=True, timeout=None, timeout_key='TIMEOUT_KEY')
26
32
  window.close()
27
33
  return event, values
28
34
 
29
- def prompt_with_help(layout, help =None) :
35
+ def prompt_with_help(layout, help =None, add_scrollbar=True) :
30
36
  layout += [[]]
31
37
  layout += [[sg.Button('Help')]]
32
38
  layout += [[sg.Button('Ok'), sg.Button('Cancel')]]
33
39
 
34
- window = sg.Window('small fish', layout=layout)
40
+ if add_scrollbar :
41
+ size = (400,500)
42
+ col_elmt = sg.Column(layout, scrollable=True, vertical_scroll_only=True, size=size)
43
+ layout = [[col_elmt]]
44
+ else :
45
+ size = (None,None)
46
+
47
+ window = sg.Window('small fish', layout=layout, size=size, resizable=True)
35
48
  while True :
36
49
  event, values = window.read()
37
50
  if event == None :
@@ -79,7 +92,7 @@ def input_image_prompt(
79
92
  else :
80
93
  layout_image_path += bool_layout(['Dense regions deconvolution', 'Cluster computation', 'Napari correction'], preset= [do_dense_regions_deconvolution_preset, do_clustering_preset, do_Napari_correction], header= "Pipeline settings")
81
94
 
82
- event, values = prompt_with_help(layout_image_path, help= 'general')
95
+ event, values = prompt_with_help(layout_image_path, help= 'general', add_scrollbar=False)
83
96
 
84
97
  if event == 'Cancel' :
85
98
  return None
@@ -227,22 +240,6 @@ def detection_parameters_promt(is_3D_stack, is_multichannel, do_dense_region_dec
227
240
  else : values['dim'] = 2
228
241
  return values
229
242
 
230
- def post_analysis_prompt() :
231
- answer = events(['Save results','add_detection', 'colocalisation', 'open results in napari'])
232
-
233
- return answer
234
-
235
- def events(event_list) :
236
- """
237
- Return event chose from user
238
- """
239
-
240
- layout = [
241
- [sg.Button(event) for event in event_list]
242
- ]
243
-
244
- event, values = prompt(layout, add_ok_cancel= False)
245
- return event
246
243
 
247
244
  def ask_replace_file(filename:str) :
248
245
  layout = [
@@ -354,4 +351,5 @@ def ask_cancel_detection() :
354
351
  if event == 'No' :
355
352
  return False
356
353
  else :
357
- return True
354
+ return True
355
+
@@ -0,0 +1,5 @@
1
+ import PySimpleGUI as sg
2
+ import small_fish_gui.gui.batch as prompt
3
+
4
+ prompt.batch_promp()
5
+ print('end')
@@ -199,19 +199,20 @@ def threshold_selection(
199
199
  """
200
200
 
201
201
  Viewer = napari.Viewer(title= "Small fish - Threshold selector", ndisplay=2, show=True)
202
+ scale = compute_anisotropy_coef(voxel_size)
202
203
  Viewer.add_image(
203
204
  data= image,
204
205
  contrast_limits= [image.min(), image.max()],
205
206
  name= "raw signal",
206
207
  colormap= 'green',
207
- scale= voxel_size,
208
+ scale= scale,
208
209
  blending= 'additive'
209
210
  )
210
211
  Viewer.add_image(
211
212
  data= filtered_image,
212
213
  contrast_limits= [filtered_image.min(), filtered_image.max()],
213
214
  colormap= 'gray',
214
- scale=voxel_size,
215
+ scale=scale,
215
216
  blending='additive'
216
217
  )
217
218
 
@@ -122,14 +122,13 @@ def _auto_map_channels(image: np.ndarray, is_3D_stack, is_time_stack, multichann
122
122
  return map
123
123
 
124
124
  def _ask_channel_map(shape, is_3D_stack, is_time_stack, multichannel, preset_map: dict= {}) :
125
- map = preset_map
126
125
  while True :
127
126
  relaunch = False
128
- x = map.setdefault('x',0)
129
- y = map.setdefault('y',0)
130
- z = map.setdefault('z',0)
131
- c = map.setdefault('c',0)
132
- t = map.setdefault('t',0)
127
+ x = preset_map.setdefault('x',0)
128
+ y = preset_map.setdefault('y',0)
129
+ z = preset_map.setdefault('z',0)
130
+ c = preset_map.setdefault('c',0)
131
+ t = preset_map.setdefault('t',0)
133
132
 
134
133
  layout = [
135
134
  add_header("Dimensions mapping", [sg.Text("Image shape : {0}".format(shape))])
@@ -139,12 +138,12 @@ def _ask_channel_map(shape, is_3D_stack, is_time_stack, multichannel, preset_map
139
138
  if multichannel : layout += [parameters_layout(['c'], default_values=[c])]
140
139
  if is_time_stack : layout += [parameters_layout(['t'], default_values=[t])]
141
140
 
142
- event, map = prompt_with_help(layout,help= 'mapping')
141
+ event, preset_map = prompt_with_help(layout,help= 'mapping', add_scrollbar=False)
143
142
  if event == 'Cancel' : quit()
144
143
 
145
144
  #Check integrity
146
- channels_values = np.array(list(map.values()), dtype= int)
147
- total_channels = len(map)
145
+ channels_values = np.array(list(preset_map.values()), dtype= int)
146
+ total_channels = len(preset_map)
148
147
  unique_channel = len(np.unique(channels_values))
149
148
  if total_channels != unique_channel :
150
149
  sg.popup("{0} channel(s) are not uniquely mapped.".format(total_channels - unique_channel))
@@ -154,7 +153,7 @@ def _ask_channel_map(shape, is_3D_stack, is_time_stack, multichannel, preset_map
154
153
  relaunch= True
155
154
  if not relaunch : break
156
155
 
157
- return map
156
+ return preset_map
158
157
 
159
158
  def _show_mapping(shape, map, is_3D_stack, is_time_stack, multichannel) :
160
159
  layout = [
@@ -166,7 +165,7 @@ def _show_mapping(shape, map, is_3D_stack, is_time_stack, multichannel) :
166
165
  [sg.Button('Change mapping')]
167
166
  ]
168
167
 
169
- event, values = prompt_with_help(layout, help='mapping')
168
+ event, values = prompt_with_help(layout, help='mapping', add_scrollbar=False)
170
169
 
171
170
  if event == 'Ok' :
172
171
  return map
@@ -170,7 +170,7 @@ def launch_segmentation(image: np.ndarray, user_parameters: dict) :
170
170
  [sg.Button("Yes"), sg.Button("No")]
171
171
  ]
172
172
 
173
- event, values = prompt(layout=layout, add_ok_cancel=False)
173
+ event, values = prompt(layout=layout, add_ok_cancel=False, add_scrollbar=False)
174
174
  if event == "No" :
175
175
  continue
176
176
 
@@ -8,6 +8,7 @@ from ._signaltonoise import compute_snr_spots
8
8
  from ._napari_wrapper import correct_spots, _update_clusters, threshold_selection
9
9
  from ..gui import add_default_loading
10
10
  from ..gui import detection_parameters_promt, input_image_prompt
11
+ from ..utils import compute_anisotropy_coef
11
12
  from .spots import compute_Spots
12
13
  from magicgui import magicgui
13
14
  from napari.layers import Image, Points
@@ -766,9 +767,11 @@ def _create_threshold_slider(
766
767
  threshold=threshold
767
768
  )[0]
768
769
 
770
+ scale = compute_anisotropy_coef(voxel_size)
771
+
769
772
  layer_args = {
770
773
  'size': 5,
771
- 'scale' : voxel_size,
774
+ 'scale' : scale,
772
775
  'face_color' : 'transparent',
773
776
  'edge_color' : 'blue',
774
777
  'symbol' : 'ring',
@@ -1,184 +0,0 @@
1
- import PySimpleGUI as sg
2
- import os
3
- from ..utils import check_parameter
4
- import cellpose.models as models
5
- from cellpose.core import use_gpu
6
-
7
- sg.theme('DarkAmber')
8
-
9
-
10
- def add_header(header_text, layout) :
11
- header = [[sg.Text('\n{0}'.format(header_text), size= (len(header_text),3), font= 'bold 15')]]
12
- return header + layout
13
-
14
-
15
- def pad_right(string, length, pad_char) :
16
- if len(string) >= length : return string
17
- else : return string + pad_char* (length - len(string))
18
-
19
-
20
- def parameters_layout(parameters:'list[str]' = [], unit=None, header= None, default_values=None, size=5, opt=None) :
21
-
22
- if len(parameters) == 0 : return []
23
- check_parameter(parameters= list, header = (str, type(None)))
24
- for key in parameters : check_parameter(key = str)
25
- max_length = len(max(parameters, key=len))
26
-
27
- if type(opt) == type(None) :
28
- opt = [False] * len(parameters)
29
- else :
30
- if len(opt) != len(parameters) : raise ValueError("Parameters and opt must be of same length.")
31
-
32
- if isinstance(default_values, (list, tuple)) :
33
- if len(default_values) != len(parameters) : raise ValueError("if default values specified it must be of equal length as parameters.")
34
- layout= [
35
- [sg.Text("{0}".format(pad_right(parameter, max_length, ' ')), text_color= 'green' if option else None),
36
- sg.InputText(size= size, key= parameter, default_text= value)
37
-
38
- ] for parameter,value, option in zip(parameters,default_values, opt)
39
- ]
40
- else :
41
- layout= [
42
- [sg.Text("{0}".format(pad_right(parameter, max_length, ' ')), text_color= 'green' if option else None),
43
- sg.InputText(size= size, key= parameter)
44
-
45
- ] for parameter, option in zip(parameters, opt)
46
- ]
47
-
48
- if type(unit) == str :
49
- for line_id, line in enumerate(layout) :
50
- layout[line_id] += [sg.Text('{0}'.format(unit))]
51
-
52
- if isinstance(header, str) :
53
- layout = add_header(header, layout)
54
- return layout
55
-
56
- def tuple_layout(opt=None, default_dict={}, unit:dict={}, **tuples) :
57
- """
58
- tuples example : voxel_size = ['z','y','x']; will ask a tuple with 3 element default to 'z', 'y' 'x'.
59
- """
60
- if type(tuples) == type(None) : return []
61
- if len(tuples.keys()) == 0 : return []
62
-
63
- if type(opt) != type(None) :
64
- if not isinstance(opt, dict) : raise TypeError("opt parameter should be either None or dict type.")
65
- if not opt.keys() == tuples.keys() : raise ValueError("If opt is passed it is expected to have same keys as tuples dict.")
66
- else :
67
- opt = tuples.copy()
68
- for key in opt.keys() :
69
- opt[key] = False
70
-
71
- for tup in tuples :
72
- if not isinstance(tuples[tup], (list,tuple)) : raise TypeError()
73
-
74
- max_size = len(max(tuples.keys(), key=len))
75
-
76
- layout = [
77
- [sg.Text(pad_right(tup, max_size, ' '), text_color= 'green' if opt[option] else None)]
78
- + [sg.InputText(default_text=default_dict.setdefault('{0}_{1}'.format(tup,elmnt), elmnt),key= '{0}_{1}'.format(tup, elmnt), size= 5) for elmnt in tuples[tup]]
79
- + [sg.Text(unit.setdefault(tup,''))]
80
- for tup,option, in zip(tuples,opt)
81
- ]
82
-
83
- return layout
84
-
85
- def path_layout(keys= [],look_for_dir = False, header=None, preset=os.getcwd()) :
86
- """
87
- If not look for dir then looks for file.
88
- """
89
- if len(keys) == 0 : return []
90
- check_parameter(keys= list, header = (str, type(None)))
91
- for key in keys : check_parameter(key = str)
92
- if look_for_dir : Browse = sg.FolderBrowse
93
- else : Browse = sg.FileBrowse
94
-
95
- max_length = len(max(keys, key=len))
96
- layout = [
97
- [sg.Text(pad_right(name, max_length, ' ')), Browse(key= name, initial_folder= preset)] for name in keys
98
- ]
99
- if isinstance(header, str) :
100
- layout = add_header(header, layout=layout)
101
- return layout
102
-
103
- def bool_layout(parameters= [], header=None, preset=None) :
104
- if len(parameters) == 0 : return []
105
- check_parameter(parameters= list, header= (str, type(None)), preset=(type(None), list, tuple, bool))
106
- for key in parameters : check_parameter(key = str)
107
- if type(preset) == type(None) :
108
- preset = [False] * len(parameters)
109
- elif type(preset) == bool :
110
- preset = [preset] * len(parameters)
111
- else :
112
- for key in preset : check_parameter(key = bool)
113
-
114
-
115
-
116
- max_length = len(max(parameters, key=len))
117
- layout = [
118
- [sg.Checkbox(pad_right(name, max_length, ' '), key= name, default=box_preset)] for name, box_preset in zip(parameters,preset)
119
- ]
120
- if isinstance(header, str) :
121
- layout = add_header(header, layout=layout)
122
- return layout
123
-
124
- def combo_layout(values, key, header=None, read_only=True, default_value=None) :
125
- """
126
- drop-down list
127
- """
128
- if len(values) == 0 : return []
129
- check_parameter(values= list, header= (str, type(None)))
130
- if type(default_value) == type(None) :
131
- default_value = values[0]
132
- elif default_value not in values :
133
- default_value = values[0]
134
- layout = [
135
- sg.Combo(values, default_value=default_value, readonly=read_only, key=key)
136
- ]
137
- if isinstance(header, str) :
138
- layout = add_header(header, layout=layout)
139
- return layout
140
-
141
- def radio_layout(values, header=None) :
142
- """
143
- Single choice buttons.
144
- """
145
- if len(values) == 0 : return []
146
- check_parameter(values= list, header= (str, type(None)))
147
- layout = [
148
- [sg.Radio(value, group_id= 0) for value in values]
149
- ]
150
- if isinstance(header, str) :
151
- layout = add_header(header, layout=layout)
152
- return layout
153
-
154
- 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
-
156
- USE_GPU = use_gpu()
157
-
158
- models_list = models.get_user_models() + models.MODEL_NAMES
159
- if len(models_list) == 0 : models_list = ['no model found']
160
-
161
- #Header : GPU availabality
162
- layout = [[sg.Text("GPU is currently "), sg.Text('ON', text_color= 'green') if USE_GPU else sg.Text('OFF', text_color= 'red')]]
163
-
164
- #cytoplasm parameters
165
- layout += [add_header("Cell Segmentation", [sg.Text("Choose cellpose model for cytoplasm: \n")]),
166
- [combo_layout(models_list, key='cyto_model_name', default_value= cytoplasm_model_preset)]
167
- ]
168
- if multichannel : layout += [parameters_layout(['cytoplasm channel'],default_values= [cytoplasm_channel_preset])]
169
- layout += [parameters_layout(['cytoplasm diameter'], unit= "px", default_values= [cyto_diameter_preset])]
170
- #Nucleus parameters
171
- layout += [
172
- add_header("Nucleus segmentation",[sg.Text("Choose cellpose model for nucleus: \n")]),
173
- combo_layout(models_list, key='nucleus_model_name', default_value= nucleus_model_preset)
174
- ]
175
- if multichannel : layout += [parameters_layout(['nucleus channel'], default_values= [nucleus_channel_preset])]
176
- layout += [parameters_layout([ 'nucleus diameter'],unit= "px", default_values= [nucleus_diameter_preset])]
177
- layout += [bool_layout(["Segment only nuclei"], preset=segment_only_nuclei_preset)]
178
-
179
- #Control plots
180
- layout += [bool_layout(['show segmentation'], header= 'Segmentation plots', preset= show_segmentation_preset)]
181
- layout += [path_layout(['saving path'], look_for_dir=True, preset=saving_path_preset)]
182
- layout += [parameters_layout(['filename'], default_values=[filename_preset], size= 25)]
183
-
184
- return layout
@@ -1,4 +0,0 @@
1
- import PySimpleGUI as sg
2
- import small_fish.gui.prompts as p
3
-
4
- p.hub_prompt([{},{},{"cell_number" : 100, "spot_number" : 1000},{},{},{'cell_number' : 10},{}])
File without changes
File without changes