small-fish-gui 1.7.1__py3-none-any.whl → 1.8.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- small_fish_gui/__init__.py +1 -1
- small_fish_gui/batch/integrity.py +3 -3
- small_fish_gui/batch/pipeline.py +11 -6
- small_fish_gui/batch/prompt.py +4 -4
- small_fish_gui/batch/update.py +2 -2
- small_fish_gui/batch/utils.py +8 -8
- small_fish_gui/batch/values.txt +2 -2
- small_fish_gui/gui/help_module.py +4 -4
- small_fish_gui/gui/layout.py +20 -12
- small_fish_gui/gui/prompts.py +99 -51
- small_fish_gui/hints.py +54 -0
- small_fish_gui/interface/__init__.py +1 -1
- small_fish_gui/interface/image.py +2 -2
- small_fish_gui/interface/{output.py → inoutput.py} +39 -0
- small_fish_gui/interface/testing.py +10 -6
- small_fish_gui/pipeline/__init__.py +4 -4
- small_fish_gui/pipeline/_colocalisation.py +19 -14
- small_fish_gui/pipeline/_preprocess.py +98 -50
- small_fish_gui/pipeline/actions.py +142 -38
- small_fish_gui/pipeline/detection.py +54 -106
- small_fish_gui/pipeline/main.py +28 -35
- small_fish_gui/pipeline/{_segmentation.py → segmentation.py} +32 -14
- small_fish_gui/pipeline/spots.py +4 -1
- {small_fish_gui-1.7.1.dist-info → small_fish_gui-1.8.0.dist-info}/METADATA +1 -2
- small_fish_gui-1.8.0.dist-info/RECORD +50 -0
- {small_fish_gui-1.7.1.dist-info → small_fish_gui-1.8.0.dist-info}/WHEEL +1 -1
- small_fish_gui/batch/output.py +0 -0
- small_fish_gui/batch/values.py +0 -3
- small_fish_gui/docs/conf.py +0 -1
- small_fish_gui/interface/parameters.py +0 -2
- small_fish_gui-1.7.1.dist-info/RECORD +0 -53
- /small_fish_gui/gui/{general_help_screenshot.png → screenshot/general_help_screenshot.png} +0 -0
- /small_fish_gui/gui/{mapping_help_screenshot.png → screenshot/mapping_help_screenshot.png} +0 -0
- /small_fish_gui/gui/{segmentation_help_screenshot.png → screenshot/segmentation_help_screenshot.png} +0 -0
- {small_fish_gui-1.7.1.dist-info → small_fish_gui-1.8.0.dist-info}/licenses/LICENSE +0 -0
small_fish_gui/__init__.py
CHANGED
|
@@ -9,7 +9,7 @@ import numpy as np
|
|
|
9
9
|
import PySimpleGUI as sg
|
|
10
10
|
|
|
11
11
|
from ..pipeline._preprocess import check_integrity, convert_parameters_types, ParameterInputError, _check_segmentation_parameters
|
|
12
|
-
from ..pipeline.
|
|
12
|
+
from ..pipeline.segmentation import _cast_segmentation_parameters
|
|
13
13
|
|
|
14
14
|
def check_file(filename:str) :
|
|
15
15
|
|
|
@@ -105,7 +105,7 @@ def check_detection_parameters(
|
|
|
105
105
|
do_clustering,
|
|
106
106
|
is_multichannel,
|
|
107
107
|
is_3D,
|
|
108
|
-
|
|
108
|
+
map_,
|
|
109
109
|
shape
|
|
110
110
|
) :
|
|
111
111
|
|
|
@@ -118,7 +118,7 @@ def check_detection_parameters(
|
|
|
118
118
|
do_clustering=do_clustering,
|
|
119
119
|
multichannel=is_multichannel,
|
|
120
120
|
segmentation_done=None,
|
|
121
|
-
|
|
121
|
+
map_=map_,
|
|
122
122
|
shape=shape
|
|
123
123
|
)
|
|
124
124
|
except ParameterInputError as e:
|
small_fish_gui/batch/pipeline.py
CHANGED
|
@@ -6,6 +6,8 @@ import os
|
|
|
6
6
|
import pandas as pd
|
|
7
7
|
import PySimpleGUI as sg
|
|
8
8
|
|
|
9
|
+
from ..hints import pipeline_parameters
|
|
10
|
+
|
|
9
11
|
from .input import open_image
|
|
10
12
|
from ..interface import write_results
|
|
11
13
|
from ..pipeline import reorder_shape, reorder_image_stack, prepare_image_detection
|
|
@@ -24,10 +26,10 @@ def batch_pipeline(
|
|
|
24
26
|
batch_window : sg.Window,
|
|
25
27
|
batch_progress_bar : sg.ProgressBar,
|
|
26
28
|
progress_count : sg.Text,
|
|
27
|
-
parameters :
|
|
29
|
+
parameters : pipeline_parameters,
|
|
28
30
|
filenames_list : list,
|
|
29
31
|
do_segmentation : bool,
|
|
30
|
-
|
|
32
|
+
map_ : dict,
|
|
31
33
|
results_df : pd.DataFrame,
|
|
32
34
|
cell_results_df : pd.DataFrame,
|
|
33
35
|
is_3D,
|
|
@@ -73,12 +75,12 @@ def batch_pipeline(
|
|
|
73
75
|
#1. Re-order shape
|
|
74
76
|
shape = image.shape
|
|
75
77
|
parameters['shape'] = shape
|
|
76
|
-
parameters['reordered_shape'] = reorder_shape(shape,
|
|
78
|
+
parameters['reordered_shape'] = reorder_shape(shape, map_=map_)
|
|
77
79
|
|
|
78
80
|
#2. Segmentation (opt)
|
|
79
81
|
if do_segmentation :
|
|
80
82
|
window_print(batch_window,"Segmenting cells...")
|
|
81
|
-
im_seg = reorder_image_stack(
|
|
83
|
+
im_seg = reorder_image_stack(map_, image)
|
|
82
84
|
parameters = _cast_segmentation_parameters(parameters)
|
|
83
85
|
cytoplasm_label, nucleus_label = cell_segmentation(
|
|
84
86
|
im_seg,
|
|
@@ -90,6 +92,8 @@ def batch_pipeline(
|
|
|
90
92
|
do_only_nuc=parameters['Segment only nuclei']
|
|
91
93
|
)
|
|
92
94
|
|
|
95
|
+
parameters['segmentation_done'] = True
|
|
96
|
+
|
|
93
97
|
if cytoplasm_label.max() == 0 : #No cell segmented
|
|
94
98
|
window_print(batch_window,"No cell was segmented, computing next image.")
|
|
95
99
|
continue
|
|
@@ -108,11 +112,12 @@ def batch_pipeline(
|
|
|
108
112
|
|
|
109
113
|
else :
|
|
110
114
|
cytoplasm_label, nucleus_label = None,None
|
|
115
|
+
parameters['segmentation_done'] = False
|
|
111
116
|
|
|
112
117
|
#3. Detection, deconvolution, clusterisation
|
|
113
118
|
window_print(batch_window,"Detecting spots...")
|
|
114
119
|
parameters = convert_parameters_types(parameters)
|
|
115
|
-
image, other_image = prepare_image_detection(
|
|
120
|
+
image, other_image = prepare_image_detection(map_, parameters)
|
|
116
121
|
nucleus_signal = get_nucleus_signal(image, other_image, parameters)
|
|
117
122
|
try : # Catch error raised if user enter a spot size too small compare to voxel size
|
|
118
123
|
parameters, frame_result, spots, clusters = launch_detection(
|
|
@@ -132,7 +137,7 @@ def batch_pipeline(
|
|
|
132
137
|
raise(error)
|
|
133
138
|
|
|
134
139
|
if parameters['save detection'] :
|
|
135
|
-
if parameters['
|
|
140
|
+
if parameters['do_cluster_computation'] : spots_list = [spots, clusters[:,:parameters['dim']]]
|
|
136
141
|
else : spots_list = [spots]
|
|
137
142
|
output_spot_tiffvisual(
|
|
138
143
|
image,
|
small_fish_gui/batch/prompt.py
CHANGED
|
@@ -49,7 +49,7 @@ def batch_promp(
|
|
|
49
49
|
time_stack_preset=False,
|
|
50
50
|
multichannel_preset=preset.setdefault("multichannel" ,False),
|
|
51
51
|
do_dense_regions_deconvolution_preset=preset.setdefault("Dense regions deconvolution" ,False),
|
|
52
|
-
do_clustering_preset= preset.setdefault("
|
|
52
|
+
do_clustering_preset= preset.setdefault("do_cluster_computation", False),
|
|
53
53
|
do_Napari_correction=False,
|
|
54
54
|
do_segmentation_preset= preset.setdefault("Segmentation", False),
|
|
55
55
|
)
|
|
@@ -232,7 +232,7 @@ def batch_promp(
|
|
|
232
232
|
is_3D = values.get('3D stack')
|
|
233
233
|
do_segmentation = values.get('Segmentation')
|
|
234
234
|
do_dense_regions_deconvolution = values.get('Dense regions deconvolution')
|
|
235
|
-
do_clustering = values.get('
|
|
235
|
+
do_clustering = values.get('do_cluster_computation')
|
|
236
236
|
|
|
237
237
|
if type(batch_folder) != type(None) and event == 'Load':
|
|
238
238
|
|
|
@@ -321,7 +321,7 @@ def batch_promp(
|
|
|
321
321
|
do_clustering=do_clustering,
|
|
322
322
|
is_multichannel=is_multichanel,
|
|
323
323
|
is_3D=is_3D,
|
|
324
|
-
|
|
324
|
+
map_= Master_parameters_dict.get('_map'),
|
|
325
325
|
shape=last_shape
|
|
326
326
|
)
|
|
327
327
|
|
|
@@ -350,7 +350,7 @@ def batch_promp(
|
|
|
350
350
|
parameters=values,
|
|
351
351
|
filenames_list=filename_list,
|
|
352
352
|
do_segmentation=do_segmentation,
|
|
353
|
-
|
|
353
|
+
map_= Master_parameters_dict['_map'],
|
|
354
354
|
results_df=results_df,
|
|
355
355
|
cell_results_df=cell_results_df,
|
|
356
356
|
is_3D=is_3D,
|
small_fish_gui/batch/update.py
CHANGED
|
@@ -36,7 +36,7 @@ def update_detection_tab(
|
|
|
36
36
|
|
|
37
37
|
#Acess elements
|
|
38
38
|
##Detection
|
|
39
|
-
channel_to_compute = get_elmt_from_key(tab_elmt, key= '
|
|
39
|
+
channel_to_compute = get_elmt_from_key(tab_elmt, key= 'channel_to_compute')
|
|
40
40
|
voxel_size_z = get_elmt_from_key(tab_elmt, key= 'voxel_size_z')
|
|
41
41
|
spot_size_z = get_elmt_from_key(tab_elmt, key= 'spot_size_z')
|
|
42
42
|
log_kernel_size_z = get_elmt_from_key(tab_elmt, key= 'log_kernel_size_z')
|
|
@@ -58,7 +58,7 @@ def update_detection_tab(
|
|
|
58
58
|
nucleus_channel_signal = get_elmt_from_key(tab_elmt, key= 'nucleus channel signal')
|
|
59
59
|
|
|
60
60
|
#disable
|
|
61
|
-
interactive_threshold_selector = get_elmt_from_key(tab_elmt, key= '
|
|
61
|
+
interactive_threshold_selector = get_elmt_from_key(tab_elmt, key= 'show_interactive_threshold_selector')
|
|
62
62
|
|
|
63
63
|
update_dict={
|
|
64
64
|
'is_3D' : is_3D,
|
small_fish_gui/batch/utils.py
CHANGED
|
@@ -16,12 +16,12 @@ def call_auto_map(
|
|
|
16
16
|
) :
|
|
17
17
|
|
|
18
18
|
if len(shape) < 2 + is_3D + is_multichannel :
|
|
19
|
-
sg.popup("Image is of dimension {0} and you're trying to
|
|
19
|
+
sg.popup("Image is of dimension {0} and you're trying to map_ {1} dimensions".format(len(shape), 2+is_3D+is_multichannel))
|
|
20
20
|
return {}
|
|
21
21
|
|
|
22
|
-
#Get auto
|
|
22
|
+
#Get auto map_
|
|
23
23
|
try :
|
|
24
|
-
|
|
24
|
+
map_ = _auto_map_channels(
|
|
25
25
|
is_3D_stack=is_3D,
|
|
26
26
|
is_time_stack=False,
|
|
27
27
|
multichannel=is_multichannel,
|
|
@@ -41,12 +41,12 @@ def call_auto_map(
|
|
|
41
41
|
c_elmt = get_elmt_from_key(tab_elmt, 'c')
|
|
42
42
|
|
|
43
43
|
#Update values
|
|
44
|
-
x_elmt.update(value=
|
|
45
|
-
y_elmt.update(value=
|
|
46
|
-
z_elmt.update(value=
|
|
47
|
-
c_elmt.update(value=
|
|
44
|
+
x_elmt.update(value=map_.get('x'))
|
|
45
|
+
y_elmt.update(value=map_.get('y'))
|
|
46
|
+
z_elmt.update(value=map_.get('z'))
|
|
47
|
+
c_elmt.update(value=map_.get('c'))
|
|
48
48
|
|
|
49
|
-
return
|
|
49
|
+
return map_
|
|
50
50
|
|
|
51
51
|
def create_map(
|
|
52
52
|
values:dict,
|
small_fish_gui/batch/values.txt
CHANGED
|
@@ -6,7 +6,7 @@ image path
|
|
|
6
6
|
3D stack
|
|
7
7
|
multichannel
|
|
8
8
|
Dense regions deconvolution
|
|
9
|
-
|
|
9
|
+
do_cluster_computation
|
|
10
10
|
Segmentation
|
|
11
11
|
Napari correction
|
|
12
12
|
x
|
|
@@ -48,7 +48,7 @@ deconvolution_kernel_y
|
|
|
48
48
|
deconvolution_kernel_x
|
|
49
49
|
cluster size
|
|
50
50
|
min number of spots
|
|
51
|
-
|
|
51
|
+
show_interactive_threshold_selector
|
|
52
52
|
spots_extraction_folder
|
|
53
53
|
spots_filename
|
|
54
54
|
do_spots_csv
|
|
@@ -43,11 +43,11 @@ def _general_help() :
|
|
|
43
43
|
help_text = """
|
|
44
44
|
Pipeline settings :
|
|
45
45
|
|
|
46
|
-
|
|
46
|
+
do_dense_regions_deconvolution : (Recommanded for cluster computations) Detect dense and bright regions with potential clustered
|
|
47
47
|
spots and simulate a more realistic number of spots in these regions.
|
|
48
48
|
See bigfish documentation : https://big-fish.readthedocs.io/en/stable/detection/dense.html
|
|
49
49
|
|
|
50
|
-
|
|
50
|
+
do_cluster_computation :
|
|
51
51
|
DBScan algorithm is ran by big-fish to detecte clusters of spots. Use is you want to quantify one of the following :
|
|
52
52
|
Transcription sites, foci, colocalisation of spots near foci...
|
|
53
53
|
|
|
@@ -73,7 +73,7 @@ def _detection_help() :
|
|
|
73
73
|
Access fully detailed documentation :
|
|
74
74
|
|
|
75
75
|
DETECTION : https://big-fish.readthedocs.io/en/stable/detection/spots.html
|
|
76
|
-
|
|
76
|
+
do_dense_regions_deconvolution : https://big-fish.readthedocs.io/en/stable/detection/dense.html
|
|
77
77
|
CLUSTERING : https://big-fish.readthedocs.io/en/stable/detection/cluster.html
|
|
78
78
|
|
|
79
79
|
"""
|
|
@@ -114,7 +114,7 @@ def _detection_help() :
|
|
|
114
114
|
|
|
115
115
|
"""
|
|
116
116
|
deconv_header="""
|
|
117
|
-
|
|
117
|
+
do_dense_regions_deconvolution PARAMETERS
|
|
118
118
|
|
|
119
119
|
"""
|
|
120
120
|
deconv_text="""
|
small_fish_gui/gui/layout.py
CHANGED
|
@@ -101,7 +101,7 @@ def path_layout(keys= [],look_for_dir = False, header=None, preset=os.getcwd())
|
|
|
101
101
|
layout = [add_header(header)] + layout
|
|
102
102
|
return layout
|
|
103
103
|
|
|
104
|
-
def bool_layout(parameters= [], header=None, preset=None) :
|
|
104
|
+
def bool_layout(parameters= [], header=None, preset=None, keys=None) :
|
|
105
105
|
if len(parameters) == 0 : return []
|
|
106
106
|
check_parameter(parameters= list, header= (str, type(None)), preset=(type(None), list, tuple, bool))
|
|
107
107
|
for key in parameters : check_parameter(key = str)
|
|
@@ -112,11 +112,19 @@ def bool_layout(parameters= [], header=None, preset=None) :
|
|
|
112
112
|
else :
|
|
113
113
|
for key in preset : check_parameter(key = bool)
|
|
114
114
|
|
|
115
|
+
max_length = len(max(parameters, key=len))
|
|
115
116
|
|
|
117
|
+
if type(keys) == type(None) :
|
|
118
|
+
keys = parameters
|
|
119
|
+
elif isinstance(keys,(list,tuple)) :
|
|
120
|
+
if len(keys) != len(parameters) : raise ValueError("keys arguement must be of same length than parameters argument")
|
|
121
|
+
elif len(parameters) == 1 and isinstance(keys, str) :
|
|
122
|
+
keys = [keys]
|
|
123
|
+
else :
|
|
124
|
+
raise ValueError('Incorrect keys parameters. Expected list of same length than parameters or None.')
|
|
116
125
|
|
|
117
|
-
max_length = len(max(parameters, key=len))
|
|
118
126
|
layout = [
|
|
119
|
-
[sg.Checkbox(pad_right(name, max_length, ' '), key=
|
|
127
|
+
[sg.Checkbox(pad_right(name, max_length, ' '), key=key, default=box_preset)] for name, box_preset, key in zip(parameters,preset,keys)
|
|
120
128
|
]
|
|
121
129
|
if isinstance(header, str) :
|
|
122
130
|
layout = [add_header(header)] + layout
|
|
@@ -139,14 +147,14 @@ def combo_elmt(values, key, header=None, read_only=True, default_value=None) :
|
|
|
139
147
|
layout = add_header(header) + layout
|
|
140
148
|
return layout
|
|
141
149
|
|
|
142
|
-
def radio_layout(values, header=None) :
|
|
150
|
+
def radio_layout(values, header=None, key=None) :
|
|
143
151
|
"""
|
|
144
152
|
Single choice buttons.
|
|
145
153
|
"""
|
|
146
154
|
if len(values) == 0 : return []
|
|
147
155
|
check_parameter(values= list, header= (str, type(None)))
|
|
148
156
|
layout = [
|
|
149
|
-
[sg.Radio(value, group_id= 0) for value in values]
|
|
157
|
+
[sg.Radio(value, group_id= 0, key=key) for value in values]
|
|
150
158
|
]
|
|
151
159
|
if isinstance(header, str) :
|
|
152
160
|
layout = [add_header(header)] + layout
|
|
@@ -219,16 +227,16 @@ def _input_parameters_layout(
|
|
|
219
227
|
|
|
220
228
|
) :
|
|
221
229
|
layout_image_path = path_layout(['image path'], header= "Image")
|
|
222
|
-
layout_image_path += bool_layout(['
|
|
230
|
+
layout_image_path += bool_layout(['is_3D_stack', 'is_multichannel'], preset= [is_3D_stack_preset, time_stack_preset, multichannel_preset])
|
|
223
231
|
|
|
224
232
|
if ask_for_segmentation :
|
|
225
233
|
layout_image_path += bool_layout(
|
|
226
|
-
['
|
|
234
|
+
['do_dense_regions_deconvolution', 'do_cluster_computation', 'Segmentation', 'show_napari_corrector'],
|
|
227
235
|
preset= [do_dense_regions_deconvolution_preset, do_clustering_preset, do_segmentation_preset, do_Napari_correction],
|
|
228
236
|
header= "Pipeline settings")
|
|
229
237
|
else :
|
|
230
238
|
layout_image_path += bool_layout(
|
|
231
|
-
['
|
|
239
|
+
['do_dense_regions_deconvolution', 'do_cluster_computation', 'show_napari_corrector'],
|
|
232
240
|
preset= [do_dense_regions_deconvolution_preset, do_clustering_preset, do_Napari_correction],
|
|
233
241
|
header= "Pipeline settings")
|
|
234
242
|
|
|
@@ -251,9 +259,9 @@ def _detection_layout(
|
|
|
251
259
|
default_detection = [default_dict.setdefault('threshold',''), default_dict.setdefault('threshold penalty', '1')]
|
|
252
260
|
opt= [True, True]
|
|
253
261
|
if is_multichannel :
|
|
254
|
-
detection_parameters += ['
|
|
262
|
+
detection_parameters += ['channel_to_compute']
|
|
255
263
|
opt += [False]
|
|
256
|
-
default_detection += [default_dict.setdefault('
|
|
264
|
+
default_detection += [default_dict.setdefault('channel_to_compute', '')]
|
|
257
265
|
|
|
258
266
|
layout = [[sg.Text("Green parameters", text_color= 'green'), sg.Text(" are optional parameters.")]]
|
|
259
267
|
layout += parameters_layout(detection_parameters, header= 'Detection', opt=opt, default_values=default_detection)
|
|
@@ -273,7 +281,7 @@ def _detection_layout(
|
|
|
273
281
|
#Deconvolution
|
|
274
282
|
if do_dense_region_deconvolution :
|
|
275
283
|
default_dense_regions_deconvolution = [default_dict.setdefault('alpha',0.5), default_dict.setdefault('beta',1)]
|
|
276
|
-
layout += parameters_layout(['alpha', 'beta',], default_values= default_dense_regions_deconvolution, header= '
|
|
284
|
+
layout += parameters_layout(['alpha', 'beta',], default_values= default_dense_regions_deconvolution, header= 'do_dense_regions_deconvolution')
|
|
277
285
|
layout += parameters_layout(['gamma'], unit= 'px', default_values= [default_dict.setdefault('gamma',5)])
|
|
278
286
|
layout += tuple_layout(opt= {"deconvolution_kernel" : True}, unit= {"deconvolution_kernel" : 'px'}, default_dict=default_dict, deconvolution_kernel = tuple_shape)
|
|
279
287
|
|
|
@@ -284,7 +292,7 @@ def _detection_layout(
|
|
|
284
292
|
|
|
285
293
|
|
|
286
294
|
|
|
287
|
-
layout += bool_layout(['Interactive threshold selector'], preset=[False])
|
|
295
|
+
layout += bool_layout(['Interactive threshold selector'],keys = ['show_interactive_threshold_selector'], preset=[False])
|
|
288
296
|
layout += path_layout(
|
|
289
297
|
keys=['spots_extraction_folder'],
|
|
290
298
|
look_for_dir=True,
|
small_fish_gui/gui/prompts.py
CHANGED
|
@@ -2,7 +2,8 @@ import PySimpleGUI as sg
|
|
|
2
2
|
import pandas as pd
|
|
3
3
|
import os
|
|
4
4
|
import numpy as np
|
|
5
|
-
from
|
|
5
|
+
from typing import Literal, Union, Any
|
|
6
|
+
from .layout import path_layout, parameters_layout, bool_layout, tuple_layout, combo_elmt, add_header, path_layout, radio_layout
|
|
6
7
|
from ..interface import open_image, check_format, FormatError
|
|
7
8
|
from .help_module import ask_help
|
|
8
9
|
|
|
@@ -34,7 +35,6 @@ def prompt(layout, add_ok_cancel=True, timeout=None, timeout_key='TIMEOUT_KEY',
|
|
|
34
35
|
|
|
35
36
|
def prompt_with_help(layout, help =None, add_scrollbar=True, vertical_scroll_only=True) :
|
|
36
37
|
layout += [[]]
|
|
37
|
-
layout += [[sg.Button('Help')]]
|
|
38
38
|
layout += [[sg.Button('Ok'), sg.Button('Cancel')]]
|
|
39
39
|
|
|
40
40
|
if add_scrollbar :
|
|
@@ -63,34 +63,29 @@ def prompt_with_help(layout, help =None, add_scrollbar=True, vertical_scroll_onl
|
|
|
63
63
|
|
|
64
64
|
def input_image_prompt(
|
|
65
65
|
is_3D_stack_preset=False,
|
|
66
|
-
time_stack_preset=False,
|
|
67
66
|
multichannel_preset = False,
|
|
68
67
|
do_dense_regions_deconvolution_preset= False,
|
|
69
68
|
do_clustering_preset = False,
|
|
70
|
-
do_segmentation_preset= False,
|
|
71
69
|
do_Napari_correction= False,
|
|
72
|
-
ask_for_segmentation= True
|
|
73
70
|
) :
|
|
74
71
|
"""
|
|
75
72
|
Keys :
|
|
76
73
|
- 'image path'
|
|
77
|
-
- '
|
|
74
|
+
- 'is_3D_stack'
|
|
78
75
|
- 'time stack'
|
|
79
|
-
- '
|
|
80
|
-
- '
|
|
76
|
+
- 'is_multichannel'
|
|
77
|
+
- 'do_dense_regions_deconvolution'
|
|
81
78
|
- 'Segmentation'
|
|
82
|
-
- '
|
|
79
|
+
- 'show_napari_corrector'
|
|
83
80
|
|
|
84
81
|
Returns Values
|
|
85
82
|
|
|
86
83
|
"""
|
|
87
84
|
layout_image_path = path_layout(['image path'], header= "Image")
|
|
88
|
-
layout_image_path += bool_layout(['3D stack', '
|
|
85
|
+
layout_image_path += bool_layout(['3D stack', 'Multichannel stack'],keys= ['is_3D_stack', 'is_multichannel'], preset= [is_3D_stack_preset, multichannel_preset])
|
|
89
86
|
|
|
90
|
-
if
|
|
91
|
-
layout_image_path += bool_layout(['Dense regions deconvolution', '
|
|
92
|
-
else :
|
|
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")
|
|
87
|
+
if type(do_dense_regions_deconvolution_preset) != type(None) and type(do_clustering_preset) != type(None) and type(do_Napari_correction) != type(None):
|
|
88
|
+
layout_image_path += bool_layout(['Dense regions deconvolution', 'Compute clusters', 'Open results in Napari'], keys = ['do_dense_regions_deconvolution', 'do_cluster_computation', 'show_napari_corrector'], preset= [do_dense_regions_deconvolution_preset, do_clustering_preset, do_Napari_correction], header= "Pipeline settings")
|
|
94
89
|
|
|
95
90
|
event, values = prompt_with_help(layout_image_path, help= 'general', add_scrollbar=False)
|
|
96
91
|
|
|
@@ -98,18 +93,12 @@ def input_image_prompt(
|
|
|
98
93
|
return None
|
|
99
94
|
|
|
100
95
|
im_path = values['image path']
|
|
101
|
-
is_3D_stack = values['
|
|
102
|
-
|
|
103
|
-
is_multichannel = values['multichannel']
|
|
104
|
-
if not ask_for_segmentation : values['Segmentation'] = False
|
|
105
|
-
|
|
106
|
-
if is_time_stack :
|
|
107
|
-
sg.popup("Sorry time stack images are not yet supported.")
|
|
108
|
-
return values
|
|
96
|
+
is_3D_stack = values['is_3D_stack']
|
|
97
|
+
is_multichannel = values['is_multichannel']
|
|
109
98
|
|
|
110
99
|
try :
|
|
111
100
|
image = open_image(im_path)
|
|
112
|
-
check_format(image, is_3D_stack,
|
|
101
|
+
check_format(image, is_3D_stack, is_multichannel)
|
|
113
102
|
values.update({'image' : image})
|
|
114
103
|
except FormatError as error:
|
|
115
104
|
sg.popup("Inconsistency between image format and options selected.\n Image shape : {0}".format(image.shape))
|
|
@@ -159,24 +148,16 @@ def output_image_prompt(filename) :
|
|
|
159
148
|
|
|
160
149
|
else : return values
|
|
161
150
|
|
|
162
|
-
def detection_parameters_promt(
|
|
151
|
+
def detection_parameters_promt(
|
|
152
|
+
is_3D_stack,
|
|
153
|
+
is_multichannel,
|
|
154
|
+
do_dense_region_deconvolution,
|
|
155
|
+
do_clustering,
|
|
156
|
+
segmentation_done,
|
|
157
|
+
default_dict: dict
|
|
158
|
+
):
|
|
163
159
|
"""
|
|
164
160
|
|
|
165
|
-
keys :
|
|
166
|
-
- 'threshold'
|
|
167
|
-
- 'threshold penalty
|
|
168
|
-
- 'time step'
|
|
169
|
-
- 'channel to compute'
|
|
170
|
-
- 'alpha'
|
|
171
|
-
- 'beta'
|
|
172
|
-
- 'gamma'
|
|
173
|
-
- 'voxel_size_{(z,y,x)}'
|
|
174
|
-
- 'spot_size{(z,y,x)}'
|
|
175
|
-
- 'log_kernel_size{(z,y,x)}'
|
|
176
|
-
- 'minimum_distance{(z,y,x)}'
|
|
177
|
-
- 'cluster size'
|
|
178
|
-
- 'min number of spots'
|
|
179
|
-
|
|
180
161
|
Returns Values
|
|
181
162
|
|
|
182
163
|
"""
|
|
@@ -188,9 +169,9 @@ def detection_parameters_promt(is_3D_stack, is_multichannel, do_dense_region_dec
|
|
|
188
169
|
default_detection = [default_dict.setdefault('threshold',''), default_dict.setdefault('threshold penalty', '1')]
|
|
189
170
|
opt= [True, True]
|
|
190
171
|
if is_multichannel :
|
|
191
|
-
detection_parameters += ['
|
|
172
|
+
detection_parameters += ['channel_to_compute']
|
|
192
173
|
opt += [False]
|
|
193
|
-
default_detection += [default_dict.setdefault('
|
|
174
|
+
default_detection += [default_dict.setdefault('channel_to_compute', '')]
|
|
194
175
|
layout = [[sg.Text("Green parameters", text_color= 'green'), sg.Text(" are optional parameters.")]]
|
|
195
176
|
layout += parameters_layout(detection_parameters, header= 'Detection', opt=opt, default_values=default_detection)
|
|
196
177
|
|
|
@@ -204,7 +185,7 @@ def detection_parameters_promt(is_3D_stack, is_multichannel, do_dense_region_dec
|
|
|
204
185
|
#Deconvolution
|
|
205
186
|
if do_dense_region_deconvolution :
|
|
206
187
|
default_dense_regions_deconvolution = [default_dict.setdefault('alpha',0.5), default_dict.setdefault('beta',1)]
|
|
207
|
-
layout += parameters_layout(['alpha', 'beta',], default_values= default_dense_regions_deconvolution, header= '
|
|
188
|
+
layout += parameters_layout(['alpha', 'beta',], default_values= default_dense_regions_deconvolution, header= 'do_dense_regions_deconvolution')
|
|
208
189
|
layout += parameters_layout(['gamma'], unit= 'px', default_values= [default_dict.setdefault('gamma',5)])
|
|
209
190
|
layout += tuple_layout(opt= {"deconvolution_kernel" : True}, unit= {"deconvolution_kernel" : 'px'}, default_dict=default_dict, deconvolution_kernel = tuple_shape)
|
|
210
191
|
|
|
@@ -213,11 +194,11 @@ def detection_parameters_promt(is_3D_stack, is_multichannel, do_dense_region_dec
|
|
|
213
194
|
layout += parameters_layout(['cluster size'], unit="radius(nm)", default_values=[default_dict.setdefault('cluster size',400)])
|
|
214
195
|
layout += parameters_layout(['min number of spots'], default_values=[default_dict.setdefault('min number of spots', 5)])
|
|
215
196
|
|
|
216
|
-
if
|
|
197
|
+
if is_multichannel and segmentation_done :
|
|
217
198
|
default_segmentation = [default_dict.setdefault('nucleus channel signal', default_dict.setdefault('nucleus channel',0))]
|
|
218
199
|
layout += parameters_layout(['nucleus channel signal'], default_values=default_segmentation) + [[sg.Text(" channel from which signal will be measured for nucleus features.")]]
|
|
219
200
|
|
|
220
|
-
layout += bool_layout(['Interactive threshold selector'], preset=[False])
|
|
201
|
+
layout += bool_layout(['Interactive threshold selector'], keys=['show_interactive_threshold_selector'], preset=[False])
|
|
221
202
|
layout += path_layout(
|
|
222
203
|
keys=['spots_extraction_folder'],
|
|
223
204
|
look_for_dir=True,
|
|
@@ -230,7 +211,8 @@ def detection_parameters_promt(is_3D_stack, is_multichannel, do_dense_region_dec
|
|
|
230
211
|
size= 13
|
|
231
212
|
)
|
|
232
213
|
layout += bool_layout(
|
|
233
|
-
|
|
214
|
+
['.csv','.excel','.feather'],
|
|
215
|
+
keys= ['do_spots_csv', 'do_spots_excel', 'do_spots_feather'],
|
|
234
216
|
preset= [default_dict.setdefault('do_spots_csv',False), default_dict.setdefault('do_spots_excel',False),default_dict.setdefault('do_spots_feather',False)]
|
|
235
217
|
)
|
|
236
218
|
|
|
@@ -280,17 +262,17 @@ def _warning_popup(warning:str) :
|
|
|
280
262
|
|
|
281
263
|
def _sumup_df(results: pd.DataFrame) :
|
|
282
264
|
|
|
283
|
-
COLUMNS = ['acquisition_id','name','threshold', 'spot_number', 'cell_number', 'filename', '
|
|
265
|
+
COLUMNS = ['acquisition_id','name','threshold', 'spot_number', 'cell_number', 'filename', 'channel_to_compute']
|
|
284
266
|
|
|
285
267
|
if len(results) > 0 :
|
|
286
|
-
if '
|
|
268
|
+
if 'channel_to_compute' not in results : results['channel_to_compute'] = np.NaN
|
|
287
269
|
res = results.loc[:,COLUMNS]
|
|
288
270
|
else :
|
|
289
271
|
res = pd.DataFrame(columns= COLUMNS)
|
|
290
272
|
|
|
291
273
|
return res
|
|
292
274
|
|
|
293
|
-
def hub_prompt(fov_results, do_segmentation=False) :
|
|
275
|
+
def hub_prompt(fov_results, do_segmentation=False) -> 'Union[Literal["Add detection", "Compute colocalisation", "Batch detection", "Rename acquisition", "Save results", "Delete acquisitions", "Reset segmentation", "Reset results", "Segment cells"], dict[Literal["result_table", ""]]]':
|
|
294
276
|
|
|
295
277
|
sumup_df = _sumup_df(fov_results)
|
|
296
278
|
|
|
@@ -302,9 +284,9 @@ def hub_prompt(fov_results, do_segmentation=False) :
|
|
|
302
284
|
layout = [
|
|
303
285
|
[sg.Text('RESULTS', font= 'bold 13')],
|
|
304
286
|
[sg.Table(values= list(sumup_df.values), headings= list(sumup_df.columns), row_height=20, num_rows= 5, vertical_scroll_only=False, key= "result_table"), segmentation_object],
|
|
305
|
-
[sg.Button('Add detection'), sg.Button('Compute colocalisation'), sg.Button('Batch detection')],
|
|
306
|
-
[sg.Button('
|
|
307
|
-
|
|
287
|
+
[sg.Button('Segment cells'), sg.Button('Add detection'), sg.Button('Compute colocalisation'), sg.Button('Batch detection')],
|
|
288
|
+
[sg.Button('Save results', button_color= 'green'), sg.Button('Save segmentation', button_color= 'green'), sg.Button('Load segmentation', button_color= 'green')],
|
|
289
|
+
[sg.Button('Rename acquisition', button_color= 'gray'), sg.Button('Delete acquisitions',button_color= 'gray'), sg.Button('Reset segmentation',button_color= 'gray'), sg.Button('Reset all',button_color= 'gray')],
|
|
308
290
|
]
|
|
309
291
|
|
|
310
292
|
window = sg.Window('small fish', layout= layout, margins= (10,10))
|
|
@@ -359,3 +341,69 @@ def ask_cancel_detection() :
|
|
|
359
341
|
else :
|
|
360
342
|
return True
|
|
361
343
|
|
|
344
|
+
|
|
345
|
+
def ask_confirmation(question_displayed : str) :
|
|
346
|
+
layout =[
|
|
347
|
+
[sg.Text(question_displayed, font= 'bold 10')],
|
|
348
|
+
[sg.Button("Yes"), sg.Button("No")]
|
|
349
|
+
]
|
|
350
|
+
|
|
351
|
+
event, value = prompt(layout, add_ok_cancel=False, add_scrollbar=False)
|
|
352
|
+
|
|
353
|
+
if event == 'No' :
|
|
354
|
+
return False
|
|
355
|
+
else :
|
|
356
|
+
return True
|
|
357
|
+
|
|
358
|
+
|
|
359
|
+
def prompt_save_segmentation() -> 'dict[Literal["folder","filename","ext"]]':
|
|
360
|
+
while True :
|
|
361
|
+
relaunch = False
|
|
362
|
+
layout = path_layout(['folder'], look_for_dir= True, header= "Output parameters :")
|
|
363
|
+
layout += parameters_layout(["filename"], default_values= ["small_fish_segmentation"], size=25)
|
|
364
|
+
layout += radio_layout(['npy','npz_uncompressed', 'npz_compressed'], key= 'ext')
|
|
365
|
+
|
|
366
|
+
event,values= prompt(layout)
|
|
367
|
+
if event == ('Cancel') :
|
|
368
|
+
return None
|
|
369
|
+
|
|
370
|
+
values['filename'] = values['filename'].replace(".npy","")
|
|
371
|
+
values['filename'] = values['filename'].replace(".npz","")
|
|
372
|
+
filename = values['filename']
|
|
373
|
+
|
|
374
|
+
if not os.path.isdir(values['folder']) :
|
|
375
|
+
sg.popup("Incorrect folder")
|
|
376
|
+
relaunch = True
|
|
377
|
+
elif os.path.isfile(values['folder'] + filename):
|
|
378
|
+
if ask_replace_file(filename) :
|
|
379
|
+
pass
|
|
380
|
+
else :
|
|
381
|
+
relaunch = True
|
|
382
|
+
|
|
383
|
+
if not relaunch : break
|
|
384
|
+
|
|
385
|
+
return values
|
|
386
|
+
|
|
387
|
+
def prompt_load_segmentation() -> 'dict[Literal["nucleus","cytoplasm"]]':
|
|
388
|
+
while True :
|
|
389
|
+
relaunch = False
|
|
390
|
+
layout = path_layout(['nucleus'], look_for_dir= False, header= "Load segmentation :")
|
|
391
|
+
layout += path_layout(['cytoplasm'], look_for_dir= False)
|
|
392
|
+
|
|
393
|
+
event,values= prompt(layout)
|
|
394
|
+
if event == ('Cancel') :
|
|
395
|
+
return None
|
|
396
|
+
|
|
397
|
+
if not os.path.isfile(values['nucleus']) :
|
|
398
|
+
sg.popup("Incorrect nucleus file selected.")
|
|
399
|
+
relaunch = True
|
|
400
|
+
|
|
401
|
+
if not os.path.isfile(values['cytoplasm']) and values['cytoplasm'] != "" :
|
|
402
|
+
sg.popup("Incorrect cytoplasm file selected.")
|
|
403
|
+
relaunch = True
|
|
404
|
+
|
|
405
|
+
|
|
406
|
+
if not relaunch : break
|
|
407
|
+
|
|
408
|
+
|
|
409
|
+
return values
|
small_fish_gui/hints.py
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
|
|
2
|
+
#Add keys hinting to user_parameters instance keys.
|
|
3
|
+
|
|
4
|
+
from typing import TypedDict, Sequence
|
|
5
|
+
from numpy import ndarray
|
|
6
|
+
|
|
7
|
+
class pipeline_parameters(TypedDict) :
|
|
8
|
+
"""
|
|
9
|
+
At run time is a regular dict instance, this class is used for keys hinting
|
|
10
|
+
"""
|
|
11
|
+
is_3D_stack : bool
|
|
12
|
+
alpha : float
|
|
13
|
+
beta : float
|
|
14
|
+
channel_to_compute : int
|
|
15
|
+
do_cluster_computation : bool
|
|
16
|
+
do_dense_regions_deconvolution : bool
|
|
17
|
+
do_spots_excel : bool
|
|
18
|
+
do_spots_feather : bool
|
|
19
|
+
do_spots_csv : bool
|
|
20
|
+
dim : int
|
|
21
|
+
filename : str
|
|
22
|
+
gamma : float
|
|
23
|
+
image_path : str
|
|
24
|
+
image : ndarray
|
|
25
|
+
show_interactive_threshold_selector : bool
|
|
26
|
+
log_kernel_size : 'Sequence[float,float,float]'
|
|
27
|
+
log_kernel_size_x : float
|
|
28
|
+
log_kernel_size_y : float
|
|
29
|
+
log_kernel_size_z : float
|
|
30
|
+
minimum_distance : 'Sequence[float,float,float]'
|
|
31
|
+
minimum_distance_x : float
|
|
32
|
+
minimum_distance_y : float
|
|
33
|
+
minimum_distance_z : float
|
|
34
|
+
is_multichannel : bool
|
|
35
|
+
show_napari_corrector : bool
|
|
36
|
+
nucleus_channel_signal : int
|
|
37
|
+
reodered_shape : 'Sequence[int,int,int,int,int]'
|
|
38
|
+
do_segmentation : bool
|
|
39
|
+
segmentation_done : bool
|
|
40
|
+
shape : 'Sequence[int,int,int,int,int]'
|
|
41
|
+
spots_extraction_folder : str
|
|
42
|
+
spots_filename : str
|
|
43
|
+
spot_size : 'Sequence[int,int,int]'
|
|
44
|
+
spot_size_x : int
|
|
45
|
+
spot_size_y : int
|
|
46
|
+
spot_size_z : int
|
|
47
|
+
threshold : int
|
|
48
|
+
threshold_penalty : int
|
|
49
|
+
time_stack : None
|
|
50
|
+
time_step : None
|
|
51
|
+
voxel_size : 'Sequence[float,float,float]'
|
|
52
|
+
voxel_size_x : float
|
|
53
|
+
voxel_size_y : float
|
|
54
|
+
voxel_size_z : float
|