small-fish-gui 1.10.4__py3-none-any.whl → 2.0.2__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/README.md +54 -69
- small_fish_gui/__init__.py +9 -3
- small_fish_gui/__main__.py +1 -1
- small_fish_gui/batch/integrity.py +8 -1
- small_fish_gui/batch/output.py +16 -0
- small_fish_gui/batch/pipeline.py +43 -24
- small_fish_gui/batch/prompt.py +44 -26
- small_fish_gui/batch/update.py +19 -3
- small_fish_gui/batch/utils.py +2 -0
- small_fish_gui/batch/values.txt +5 -5
- small_fish_gui/default_values.py +51 -0
- small_fish_gui/gui/__init__.py +3 -1
- small_fish_gui/gui/_napari_widgets.py +15 -4
- small_fish_gui/gui/layout.py +123 -54
- small_fish_gui/gui/napari_visualiser.py +12 -8
- small_fish_gui/gui/prompts.py +61 -74
- small_fish_gui/gui/tooltips.py +15 -0
- small_fish_gui/hints.py +23 -4
- small_fish_gui/illustrations/DetectionVitrine_filtre.png +0 -0
- small_fish_gui/illustrations/DetectionVitrine_signal.png +0 -0
- small_fish_gui/illustrations/FocciVitrine.png +0 -0
- small_fish_gui/illustrations/FocciVitrine_no_spots.png +0 -0
- small_fish_gui/illustrations/Segmentation2D.png +0 -0
- small_fish_gui/illustrations/Segmentation2D_with_labels.png +0 -0
- small_fish_gui/logo.png +0 -0
- small_fish_gui/{pipeline/main.py → main_menu.py} +16 -15
- small_fish_gui/pipeline/_colocalisation.py +60 -41
- small_fish_gui/pipeline/_preprocess.py +13 -12
- small_fish_gui/pipeline/actions.py +102 -14
- small_fish_gui/pipeline/detection.py +5 -1
- small_fish_gui/pipeline/segmentation.py +206 -73
- small_fish_gui/pipeline/spots.py +129 -5
- small_fish_gui/pipeline/testing.ipynb +1571 -2
- small_fish_gui/requirements.txt +4 -4
- {small_fish_gui-1.10.4.dist-info → small_fish_gui-2.0.2.dist-info}/METADATA +14 -16
- small_fish_gui-2.0.2.dist-info/RECORD +59 -0
- small_fish_gui-1.10.4.dist-info/RECORD +0 -49
- {small_fish_gui-1.10.4.dist-info → small_fish_gui-2.0.2.dist-info}/WHEEL +0 -0
- {small_fish_gui-1.10.4.dist-info → small_fish_gui-2.0.2.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
""""
|
|
2
|
+
Constant submodule to have a common reference for parameters default values
|
|
3
|
+
"""
|
|
4
|
+
import os
|
|
5
|
+
|
|
6
|
+
#Image
|
|
7
|
+
IS_MULTICHANNEL = False
|
|
8
|
+
IS_3D_STACK = False
|
|
9
|
+
CHANNEL = 0
|
|
10
|
+
NUC_CHANNEL = 1
|
|
11
|
+
|
|
12
|
+
#Segmentation
|
|
13
|
+
FLOW_THRESHOLD = 0.4
|
|
14
|
+
CELLPROB_THRESHOD = 0.
|
|
15
|
+
CYTO_MODEL = "cpsam"
|
|
16
|
+
NUC_MODEL = "cpsam"
|
|
17
|
+
CYTO_DIAMETER = 90
|
|
18
|
+
NUC_DIAMETER = 60
|
|
19
|
+
ANISOTROPY = 1.
|
|
20
|
+
SHOW_SEGMENTATION = True
|
|
21
|
+
SEGMENT_ONLY_NUCLEI = False
|
|
22
|
+
DO_3D_SEMGENTATION = False
|
|
23
|
+
VISUAL_PATH = os.getcwd()
|
|
24
|
+
SAVE_SEGMENTATION_VISUAL = False
|
|
25
|
+
|
|
26
|
+
#Detection
|
|
27
|
+
THRESHOLD = None
|
|
28
|
+
THRESHOLD_PENALTY = 1
|
|
29
|
+
DO_DENSE_REGIONS_DECONVOLUTION = False
|
|
30
|
+
DO_CLUSTER_COMPUTATION = False
|
|
31
|
+
DO_CLUSTER_COMPUTATION = False
|
|
32
|
+
SHOW_NAPARI_CORRECTOR = True
|
|
33
|
+
INTERACTIVE_THRESHOLD = False
|
|
34
|
+
|
|
35
|
+
#Deconvolution
|
|
36
|
+
ALPHA = 0.5
|
|
37
|
+
BETA = 1.
|
|
38
|
+
GAMMA = 3.
|
|
39
|
+
|
|
40
|
+
#Clustering
|
|
41
|
+
CLUSTER_SIZE = 400
|
|
42
|
+
MIN_NUMBER_SPOTS = 5
|
|
43
|
+
|
|
44
|
+
#Coloc
|
|
45
|
+
COLOC_RANGE = 400
|
|
46
|
+
COLOC_VOXEL_SIZE = (1,2,3)
|
|
47
|
+
|
|
48
|
+
#Spots Extraction
|
|
49
|
+
DO_CSV = False
|
|
50
|
+
DO_EXCEL = False
|
|
51
|
+
SPOT_EXTRACTION_FOLDER = os.getcwd()
|
small_fish_gui/gui/__init__.py
CHANGED
|
@@ -158,21 +158,32 @@ class ChangesPropagater(NapariWidget) :
|
|
|
158
158
|
"""
|
|
159
159
|
def __init__(self, label_list):
|
|
160
160
|
self.label_list = label_list
|
|
161
|
+
for label_layer in self.label_list :
|
|
162
|
+
label_layer.events.selected_label.connect((self, 'update'))
|
|
161
163
|
super().__init__()
|
|
162
164
|
|
|
163
165
|
def _create_widget(self) :
|
|
164
166
|
@magicgui(
|
|
165
|
-
call_button='
|
|
167
|
+
call_button='Expand label',
|
|
166
168
|
auto_call=False,
|
|
167
169
|
)
|
|
168
|
-
def apply_changes() -> None:
|
|
170
|
+
def apply_changes(label_number : int) -> None:
|
|
169
171
|
for layer in self.label_list :
|
|
170
172
|
slices = layer.data.shape[0]
|
|
171
|
-
|
|
172
|
-
|
|
173
|
+
masked_layer = layer.data.copy()
|
|
174
|
+
masked_layer[masked_layer != label_number] = 0
|
|
175
|
+
masked_layer = np.max(masked_layer, axis=0)
|
|
176
|
+
expanded_layer = np.repeat(masked_layer[np.newaxis], slices, axis=0)
|
|
177
|
+
layer.data[expanded_layer == label_number] = expanded_layer[expanded_layer == label_number]
|
|
173
178
|
layer.refresh()
|
|
174
179
|
return apply_changes
|
|
175
180
|
|
|
181
|
+
def update(self, event) :
|
|
182
|
+
layer : Labels = event.source
|
|
183
|
+
new_label = layer.selected_label
|
|
184
|
+
self.widget.label_number.value = new_label
|
|
185
|
+
self.widget.update()
|
|
186
|
+
|
|
176
187
|
class ClusterIDSetter(ClusterWidget) :
|
|
177
188
|
"""
|
|
178
189
|
Allow user to set selected single spots to chosen cluster_id
|
small_fish_gui/gui/layout.py
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import FreeSimpleGUI as sg
|
|
2
2
|
import os
|
|
3
|
-
from ..utils import check_parameter
|
|
4
|
-
from ..hints import pipeline_parameters
|
|
5
|
-
from typing import Optional, Union
|
|
6
3
|
import cellpose.models as models
|
|
7
|
-
|
|
4
|
+
import small_fish_gui.default_values as default
|
|
5
|
+
from typing import Optional, Union
|
|
8
6
|
|
|
9
|
-
|
|
7
|
+
from cellpose.core import use_gpu
|
|
8
|
+
from .tooltips import FLOW_THRESHOLD_TOOLTIP,CELLPROB_TOOLTIP
|
|
9
|
+
from ..hints import pipeline_parameters
|
|
10
|
+
from ..utils import check_parameter
|
|
10
11
|
|
|
11
12
|
|
|
12
13
|
def add_header(header_text) :
|
|
@@ -20,13 +21,29 @@ def pad_right(string, length, pad_char) :
|
|
|
20
21
|
else : return string + pad_char* (length - len(string))
|
|
21
22
|
|
|
22
23
|
|
|
23
|
-
def parameters_layout(
|
|
24
|
+
def parameters_layout(
|
|
25
|
+
parameters:'list[str]' = [],
|
|
26
|
+
unit=None,
|
|
27
|
+
header= None,
|
|
28
|
+
default_values=None,
|
|
29
|
+
keys = None,
|
|
30
|
+
tooltips = None,
|
|
31
|
+
size=5,
|
|
32
|
+
opt:list=None
|
|
33
|
+
) :
|
|
24
34
|
|
|
25
35
|
if len(parameters) == 0 : return []
|
|
26
36
|
check_parameter(parameters= list, header = (str, type(None)))
|
|
27
37
|
for key in parameters : check_parameter(key = str)
|
|
28
38
|
max_length = len(max(parameters, key=len))
|
|
29
39
|
|
|
40
|
+
if keys is None : keys = [None] * len(parameters)
|
|
41
|
+
else :
|
|
42
|
+
if len(keys) != len(parameters) : raise ValueError("keys length must be equal with parameters length or set to None.")
|
|
43
|
+
if tooltips is None : tooltips = [None] * len(parameters)
|
|
44
|
+
else :
|
|
45
|
+
if len(tooltips) != len(parameters) : raise ValueError("tooltips length must be equal with parameters length or set to None.")
|
|
46
|
+
|
|
30
47
|
if type(opt) == type(None) :
|
|
31
48
|
opt = [False] * len(parameters)
|
|
32
49
|
else :
|
|
@@ -35,10 +52,11 @@ def parameters_layout(parameters:'list[str]' = [], unit=None, header= None, defa
|
|
|
35
52
|
if isinstance(default_values, (list, tuple)) :
|
|
36
53
|
if len(default_values) != len(parameters) : raise ValueError("if default values specified it must be of equal length as parameters.")
|
|
37
54
|
layout= [
|
|
38
|
-
[
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
55
|
+
[
|
|
56
|
+
sg.Text("{0}".format(pad_right(parameter, max_length, ' ')), text_color= 'green' if option else None),
|
|
57
|
+
sg.InputText(size= size, key= parameter if key is None else key, default_text= value, tooltip=tooltip)
|
|
58
|
+
|
|
59
|
+
] for parameter,value, option, key, tooltip in zip(parameters,default_values, opt, keys, tooltips)
|
|
42
60
|
]
|
|
43
61
|
else :
|
|
44
62
|
layout= [
|
|
@@ -56,7 +74,7 @@ def parameters_layout(parameters:'list[str]' = [], unit=None, header= None, defa
|
|
|
56
74
|
layout = [add_header(header)] + layout
|
|
57
75
|
return layout
|
|
58
76
|
|
|
59
|
-
def tuple_layout(opt=None, default_dict={}, unit:dict={}, **tuples) :
|
|
77
|
+
def tuple_layout(opt=None, default_dict={}, unit:dict={}, names : dict = {}, **tuples) :
|
|
60
78
|
"""
|
|
61
79
|
tuples example : voxel_size = ['z','y','x']; will ask a tuple with 3 element default to 'z', 'y' 'x'.
|
|
62
80
|
"""
|
|
@@ -77,9 +95,9 @@ def tuple_layout(opt=None, default_dict={}, unit:dict={}, **tuples) :
|
|
|
77
95
|
max_size = len(max(tuples.keys(), key=len))
|
|
78
96
|
|
|
79
97
|
layout = [
|
|
80
|
-
[sg.Text(pad_right(tup, max_size, ' '), text_color= 'green' if opt[option] else None)]
|
|
98
|
+
[sg.Text(pad_right(names[tup] if tup in names.keys() else tup, max_size, ' '), text_color= 'green' if opt[option] else None)]
|
|
81
99
|
+ [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]]
|
|
82
|
-
+ [sg.Text(unit.setdefault(tup,''))]
|
|
100
|
+
+ [sg.Text(unit.setdefault(tup,''))]
|
|
83
101
|
for tup,option, in zip(tuples,opt)
|
|
84
102
|
]
|
|
85
103
|
|
|
@@ -96,9 +114,13 @@ def path_layout(keys= [],look_for_dir = False, header=None, preset=os.getcwd())
|
|
|
96
114
|
else : Browse = sg.FileBrowse
|
|
97
115
|
|
|
98
116
|
max_length = len(max(keys, key=len))
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
117
|
+
|
|
118
|
+
layout = []
|
|
119
|
+
for name in keys :
|
|
120
|
+
layout += [
|
|
121
|
+
[sg.Text(pad_right(name, max_length, ' '))],
|
|
122
|
+
[sg.InputText(key= name, expand_x=True, default_text=preset), Browse(key= name + "_browse", initial_folder= preset), sg.Text('')],
|
|
123
|
+
]
|
|
102
124
|
if isinstance(header, str) :
|
|
103
125
|
layout = [add_header(header)] + layout
|
|
104
126
|
return layout
|
|
@@ -163,18 +185,25 @@ def radio_layout(values, header=None, key=None) :
|
|
|
163
185
|
return layout
|
|
164
186
|
|
|
165
187
|
def _segmentation_layout(
|
|
166
|
-
multichannel,
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
188
|
+
multichannel : bool,
|
|
189
|
+
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,
|
|
171
194
|
other_nucleus_image_preset = None,
|
|
172
|
-
cyto_diameter_preset=
|
|
173
|
-
nucleus_diameter_preset=
|
|
174
|
-
show_segmentation_preset=
|
|
175
|
-
|
|
176
|
-
|
|
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,
|
|
177
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,
|
|
178
207
|
) :
|
|
179
208
|
|
|
180
209
|
USE_GPU = use_gpu()
|
|
@@ -189,30 +218,51 @@ def _segmentation_layout(
|
|
|
189
218
|
|
|
190
219
|
#cytoplasm parameters
|
|
191
220
|
layout += [
|
|
192
|
-
add_header("
|
|
193
|
-
[sg.Text("Choose
|
|
194
|
-
combo_elmt(models_list, key='cyto_model_name', default_value= cytoplasm_model_preset)
|
|
221
|
+
add_header("Cytoplasm Segmentation"),
|
|
222
|
+
[sg.Text("Choose parameters for cytoplasm segmentation: \n")],
|
|
195
223
|
]
|
|
196
224
|
|
|
197
|
-
if
|
|
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"])
|
|
198
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
|
+
)
|
|
199
236
|
|
|
200
|
-
layout += parameters_layout(['cytoplasm diameter'], unit= "px", default_values= [cyto_diameter_preset])
|
|
201
237
|
#Nucleus parameters
|
|
202
238
|
layout += [
|
|
203
|
-
add_header("
|
|
204
|
-
[sg.Text("Choose
|
|
205
|
-
combo_elmt(models_list, key='nucleus_model_name', default_value= nucleus_model_preset)
|
|
239
|
+
add_header("Nuclei segmentation"),
|
|
240
|
+
[sg.Text("Choose parameters for nuclei segmentation: \n")],
|
|
206
241
|
]
|
|
207
242
|
|
|
208
|
-
if multichannel : layout += parameters_layout(['nucleus channel'], default_values= [nucleus_channel_preset])
|
|
209
243
|
layout += path_layout(['other_nucleus_image'], preset=other_nucleus_image_preset)
|
|
210
|
-
layout +=
|
|
211
|
-
layout +=
|
|
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"])
|
|
212
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'])
|
|
250
|
+
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]
|
|
260
|
+
)
|
|
261
|
+
|
|
213
262
|
#Control plots
|
|
214
|
-
layout += bool_layout(['
|
|
215
|
-
layout +=
|
|
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)
|
|
216
266
|
layout += parameters_layout(['filename'], default_values=[filename_preset], size= 25)
|
|
217
267
|
|
|
218
268
|
return layout
|
|
@@ -254,7 +304,7 @@ def _detection_layout(
|
|
|
254
304
|
|
|
255
305
|
#Detection
|
|
256
306
|
detection_parameters = ['threshold', 'threshold penalty']
|
|
257
|
-
default_detection = [default_dict.setdefault('threshold',
|
|
307
|
+
default_detection = [default_dict.setdefault('threshold',default.THRESHOLD), default_dict.setdefault('threshold penalty', default.THRESHOLD_PENALTY)]
|
|
258
308
|
opt= [True, True]
|
|
259
309
|
if is_multichannel :
|
|
260
310
|
detection_parameters += ['channel_to_compute']
|
|
@@ -268,34 +318,31 @@ def _detection_layout(
|
|
|
268
318
|
else : tuple_shape = ('z','y','x')
|
|
269
319
|
opt = {'voxel_size' : False, 'spot_size' : False, 'log_kernel_size' : True, 'minimum_distance' : True}
|
|
270
320
|
unit = {'voxel_size' : 'nm', 'minimum_distance' : 'nm', 'spot_size' : 'radius(nm)', 'log_kernel_size' : 'px'}
|
|
321
|
+
names = {'voxel_size' : 'Voxel size', 'spot_size' : 'Spot size', 'log_kernel_size' : 'LoG kernel size', 'minimum_distance' : 'Minimum distance between spots'}
|
|
271
322
|
|
|
272
|
-
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)
|
|
323
|
+
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)
|
|
273
324
|
|
|
274
325
|
if (do_segmentation and is_multichannel) or (is_multichannel and segmentation_done):
|
|
275
|
-
|
|
276
|
-
layout += [[sg.Text("nucleus channel signal "), sg.InputText(default_text=default_segmentation, key= "nucleus channel signal", size= 5, tooltip= "Channel from which signal will be measured for nucleus features, \nallowing you to measure signal from a different channel than the one used for segmentation.")]]
|
|
277
|
-
# layout += parameters_layout(['nucleus channel signal'], default_values=default_segmentation) + [[sg.Text("Channel from which signal will be measured for nucleus features, allowing you to measure signal from a different channel than the one used for segmentation.")]]
|
|
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.")]]
|
|
278
327
|
|
|
279
328
|
#Deconvolution
|
|
280
329
|
if do_dense_region_deconvolution :
|
|
281
|
-
default_dense_regions_deconvolution = [default_dict.setdefault('alpha',
|
|
330
|
+
default_dense_regions_deconvolution = [default_dict.setdefault('alpha',default.ALPHA), default_dict.setdefault('beta',default.BETA)]
|
|
282
331
|
layout += parameters_layout(['alpha', 'beta',], default_values= default_dense_regions_deconvolution, header= 'do_dense_regions_deconvolution')
|
|
283
|
-
layout += parameters_layout(['gamma'], unit= 'px', default_values= [default_dict.setdefault('gamma',
|
|
332
|
+
layout += parameters_layout(['gamma'], unit= 'px', default_values= [default_dict.setdefault('gamma',default.GAMMA)])
|
|
284
333
|
layout += tuple_layout(opt= {"deconvolution_kernel" : True}, unit= {"deconvolution_kernel" : 'px'}, default_dict=default_dict, deconvolution_kernel = tuple_shape)
|
|
285
334
|
|
|
286
335
|
#Clustering
|
|
287
336
|
if do_clustering :
|
|
288
|
-
layout += parameters_layout(['cluster_size'], unit="radius(nm)", default_values=[default_dict.setdefault('cluster_size',
|
|
289
|
-
layout += parameters_layout(['min_number_of_spots'], default_values=[default_dict.setdefault('min_number_of_spots',
|
|
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)])
|
|
290
339
|
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
layout += bool_layout(['Interactive threshold selector'],keys = ['show_interactive_threshold_selector'], preset=[False])
|
|
340
|
+
layout += bool_layout(['Interactive threshold selector'],keys = ['show_interactive_threshold_selector'], preset=[default.INTERACTIVE_THRESHOLD])
|
|
294
341
|
layout += path_layout(
|
|
295
342
|
keys=['spots_extraction_folder'],
|
|
296
343
|
look_for_dir=True,
|
|
297
344
|
header= "Individual spot extraction",
|
|
298
|
-
preset= default_dict.setdefault('spots_extraction_folder',
|
|
345
|
+
preset= default_dict.setdefault('spots_extraction_folder', default.SPOT_EXTRACTION_FOLDER)
|
|
299
346
|
)
|
|
300
347
|
default_filename = default_dict.setdefault("filename","") + "_spot_extraction"
|
|
301
348
|
layout += parameters_layout(
|
|
@@ -304,12 +351,34 @@ def _detection_layout(
|
|
|
304
351
|
size= 13
|
|
305
352
|
)
|
|
306
353
|
layout += bool_layout(
|
|
307
|
-
|
|
308
|
-
|
|
354
|
+
['.csv','.excel',],
|
|
355
|
+
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),]
|
|
309
357
|
)
|
|
310
358
|
|
|
311
359
|
return layout
|
|
312
360
|
|
|
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()],
|
|
365
|
+
[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")],
|
|
367
|
+
[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")],
|
|
369
|
+
]
|
|
370
|
+
|
|
371
|
+
layout += parameters_layout(['colocalisation distance'], unit= 'nm', default_values= default.COLOC_RANGE,)
|
|
372
|
+
|
|
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.")]]
|
|
375
|
+
|
|
376
|
+
layout += [[sg.Push(),sg.Button("Ok", bind_return_key=True),sg.Button("Cancel"),sg.Push(),],
|
|
377
|
+
[sg.VPush()]
|
|
378
|
+
]
|
|
379
|
+
|
|
380
|
+
return layout
|
|
381
|
+
|
|
313
382
|
def _ask_channel_map_layout(
|
|
314
383
|
shape,
|
|
315
384
|
is_3D_stack,
|
|
@@ -134,7 +134,7 @@ def correct_spots(
|
|
|
134
134
|
new_clusters = np.concatenate([
|
|
135
135
|
cluster_layer.data,
|
|
136
136
|
cluster_layer.features.loc[:,["spot_number","cluster_id"]].to_numpy()
|
|
137
|
-
],axis=1)
|
|
137
|
+
],axis=1).astype(int)
|
|
138
138
|
|
|
139
139
|
new_spots = np.concatenate([
|
|
140
140
|
single_layer.data,
|
|
@@ -145,7 +145,7 @@ def correct_spots(
|
|
|
145
145
|
new_min_spot_number = widget_cluster_updater.min_spot
|
|
146
146
|
|
|
147
147
|
else :
|
|
148
|
-
new_spots = single_layer.data
|
|
148
|
+
new_spots = single_layer.data.astype(int)
|
|
149
149
|
new_clusters = None
|
|
150
150
|
new_cluster_radius = None
|
|
151
151
|
new_min_spot_number = None
|
|
@@ -159,6 +159,7 @@ def show_segmentation(
|
|
|
159
159
|
nuc_label : np.ndarray,
|
|
160
160
|
cyto_image : np.ndarray = None,
|
|
161
161
|
cyto_label : np.ndarray = None,
|
|
162
|
+
anisotrpy : float = 1,
|
|
162
163
|
) :
|
|
163
164
|
dim = nuc_image.ndim
|
|
164
165
|
|
|
@@ -186,16 +187,18 @@ def show_segmentation(
|
|
|
186
187
|
#Init Napari viewer
|
|
187
188
|
Viewer = napari.Viewer(ndisplay=2, title= 'Show segmentation', axis_labels=['z','y','x'] if dim == 3 else ['y', 'x'])
|
|
188
189
|
|
|
190
|
+
scale = (anisotrpy, 1, 1)
|
|
191
|
+
|
|
189
192
|
# Adding nuclei
|
|
190
|
-
nuc_signal_layer = Viewer.add_image(nuc_image, name= "nucleus signal", blending= 'additive', colormap='blue', contrast_limits=[nuc_image.min(), nuc_image.max()])
|
|
191
|
-
nuc_label_layer = Viewer.add_labels(nuc_label, opacity= 0.6, name= 'nucleus_label',)
|
|
193
|
+
nuc_signal_layer = Viewer.add_image(nuc_image, name= "nucleus signal", blending= 'additive', colormap='blue', contrast_limits=[nuc_image.min(), nuc_image.max()], scale=scale)
|
|
194
|
+
nuc_label_layer = Viewer.add_labels(nuc_label, opacity= 0.6, name= 'nucleus_label', scale=scale)
|
|
192
195
|
nuc_label_layer.preserve_labels = True
|
|
193
196
|
labels_layer_list = [nuc_label_layer]
|
|
194
197
|
|
|
195
198
|
#Adding cytoplasm
|
|
196
199
|
if (type(cyto_label) != type(None) and not np.array_equal(cyto_label, nuc_label) ) or (type(cyto_label) != type(None) and cyto_label.max() == 0):
|
|
197
|
-
Viewer.add_image(cyto_image, name= "cytoplasm signal", blending= 'additive', colormap='red', contrast_limits=[cyto_image.min(), cyto_image.max()])
|
|
198
|
-
cyto_label_layer = Viewer.add_labels(cyto_label, opacity= 0.6, name= 'cytoplasm_label')
|
|
200
|
+
Viewer.add_image(cyto_image, name= "cytoplasm signal", blending= 'additive', colormap='red', contrast_limits=[cyto_image.min(), cyto_image.max()], scale=scale)
|
|
201
|
+
cyto_label_layer = Viewer.add_labels(cyto_label, opacity= 0.6, name= 'cytoplasm_label', scale=scale)
|
|
199
202
|
cyto_label_layer.preserve_labels = True
|
|
200
203
|
labels_layer_list += [cyto_label_layer]
|
|
201
204
|
|
|
@@ -205,9 +208,10 @@ def show_segmentation(
|
|
|
205
208
|
label_reseter = SegmentationReseter(labels_layer_list)
|
|
206
209
|
changes_applier = ChangesPropagater(labels_layer_list)
|
|
207
210
|
|
|
208
|
-
buttons_container = widgets.Container(widgets=[label_picker.widget,
|
|
211
|
+
buttons_container = widgets.Container(widgets=[label_picker.widget, label_reseter.widget], labels=False, layout='horizontal')
|
|
212
|
+
changes_applier = widgets.Container(widgets=[changes_applier.widget], labels=False, layout='horizontal')
|
|
209
213
|
tools_container = widgets.Container(
|
|
210
|
-
widgets = [buttons_container, label_eraser.widget],
|
|
214
|
+
widgets = [buttons_container, changes_applier, label_eraser.widget],
|
|
211
215
|
labels=False,
|
|
212
216
|
)
|
|
213
217
|
Viewer.window.add_dock_widget(tools_container, name='SmallFish', area='left')
|
small_fish_gui/gui/prompts.py
CHANGED
|
@@ -2,8 +2,19 @@ import FreeSimpleGUI as sg
|
|
|
2
2
|
import pandas as pd
|
|
3
3
|
import os
|
|
4
4
|
import numpy as np
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
import small_fish_gui.default_values as default
|
|
6
|
+
|
|
7
|
+
from typing import Literal, Union
|
|
8
|
+
from .layout import (
|
|
9
|
+
path_layout,
|
|
10
|
+
parameters_layout,
|
|
11
|
+
bool_layout,
|
|
12
|
+
path_layout,
|
|
13
|
+
radio_layout,
|
|
14
|
+
colocalization_layout,
|
|
15
|
+
tuple_layout,
|
|
16
|
+
_detection_layout
|
|
17
|
+
)
|
|
7
18
|
from ..interface import open_image, check_format, FormatError
|
|
8
19
|
|
|
9
20
|
|
|
@@ -13,12 +24,9 @@ def prompt(layout, add_ok_cancel=True, timeout=None, timeout_key='TIMEOUT_KEY',
|
|
|
13
24
|
"""
|
|
14
25
|
if add_ok_cancel : layout += [[sg.Button('Ok', bind_return_key=True), sg.Button('Cancel')]]
|
|
15
26
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
layout = [[col_elmt]]
|
|
20
|
-
else :
|
|
21
|
-
size = (None,None)
|
|
27
|
+
size = (400,500)
|
|
28
|
+
col_elmt = sg.Column(layout, scrollable=True, vertical_scroll_only=True, size=size, expand_x=True, expand_y=True)
|
|
29
|
+
layout = [[col_elmt]]
|
|
22
30
|
|
|
23
31
|
window = sg.Window('small fish', layout=layout, margins=(10,10), size=size, resizable=True, location=None)
|
|
24
32
|
event, values = window.read(timeout=timeout, timeout_key=timeout_key)
|
|
@@ -33,8 +41,6 @@ def prompt(layout, add_ok_cancel=True, timeout=None, timeout_key='TIMEOUT_KEY',
|
|
|
33
41
|
window.close()
|
|
34
42
|
return event, values
|
|
35
43
|
|
|
36
|
-
|
|
37
|
-
|
|
38
44
|
def input_image_prompt(
|
|
39
45
|
is_3D_stack_preset=False,
|
|
40
46
|
multichannel_preset = False,
|
|
@@ -90,15 +96,16 @@ def output_image_prompt(filename) :
|
|
|
90
96
|
layout = path_layout(['folder'], look_for_dir= True, header= "Output parameters :")
|
|
91
97
|
layout += parameters_layout(["filename"], default_values= [filename + "_quantification"], size=25)
|
|
92
98
|
layout += bool_layout(['csv','Excel', 'Feather'])
|
|
93
|
-
layout.append([sg.Button('Cancel')])
|
|
94
99
|
|
|
95
100
|
event,values= prompt(layout)
|
|
101
|
+
if event == ('Cancel') : return None
|
|
96
102
|
|
|
97
103
|
values['filename'] = values['filename'].replace(".xlsx","")
|
|
98
104
|
values['filename'] = values['filename'].replace(".feather","")
|
|
99
105
|
excel_filename = values['filename'] + ".xlsx"
|
|
100
106
|
feather_filename = values['filename'] + ".feather"
|
|
101
107
|
|
|
108
|
+
|
|
102
109
|
if not values['Excel'] and not values['Feather'] and not values['csv'] :
|
|
103
110
|
sg.popup("Please check at least one box : Excel/Feather/csv")
|
|
104
111
|
relaunch = True
|
|
@@ -118,9 +125,7 @@ def output_image_prompt(filename) :
|
|
|
118
125
|
|
|
119
126
|
if not relaunch : break
|
|
120
127
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
else : return values
|
|
128
|
+
return values
|
|
124
129
|
|
|
125
130
|
def detection_parameters_promt(
|
|
126
131
|
is_3D_stack,
|
|
@@ -135,60 +140,15 @@ def detection_parameters_promt(
|
|
|
135
140
|
Returns Values
|
|
136
141
|
|
|
137
142
|
"""
|
|
138
|
-
if is_3D_stack : dim = 3
|
|
139
|
-
else : dim = 2
|
|
140
|
-
|
|
141
|
-
#Detection
|
|
142
|
-
detection_parameters = ['threshold', 'threshold penalty']
|
|
143
|
-
default_detection = [default_dict.setdefault('threshold',''), default_dict.setdefault('threshold penalty', '1')]
|
|
144
|
-
opt= [True, True]
|
|
145
|
-
if is_multichannel :
|
|
146
|
-
detection_parameters += ['channel_to_compute']
|
|
147
|
-
opt += [False]
|
|
148
|
-
default_detection += [default_dict.setdefault('channel_to_compute', '')]
|
|
149
|
-
layout = [[sg.Text("Green parameters", text_color= 'green'), sg.Text(" are optional parameters.")]]
|
|
150
|
-
layout += parameters_layout(detection_parameters, header= 'Detection', opt=opt, default_values=default_detection)
|
|
151
|
-
|
|
152
|
-
if dim == 2 : tuple_shape = ('y','x')
|
|
153
|
-
else : tuple_shape = ('z','y','x')
|
|
154
|
-
opt = {'voxel_size' : False, 'spot_size' : False, 'log_kernel_size' : True, 'minimum_distance' : True}
|
|
155
|
-
unit = {'voxel_size' : 'nm', 'minimum_distance' : 'nm', 'spot_size' : 'radius(nm)', 'log_kernel_size' : 'px'}
|
|
156
|
-
|
|
157
|
-
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)
|
|
158
|
-
|
|
159
|
-
#Deconvolution
|
|
160
|
-
if do_dense_region_deconvolution :
|
|
161
|
-
default_dense_regions_deconvolution = [default_dict.setdefault('alpha',0.5), default_dict.setdefault('beta',1)]
|
|
162
|
-
layout += parameters_layout(['alpha', 'beta',], default_values= default_dense_regions_deconvolution, header= 'do_dense_regions_deconvolution')
|
|
163
|
-
layout += parameters_layout(['gamma'], unit= 'px', default_values= [default_dict.setdefault('gamma',5)])
|
|
164
|
-
layout += tuple_layout(opt= {"deconvolution_kernel" : True}, unit= {"deconvolution_kernel" : 'px'}, default_dict=default_dict, deconvolution_kernel = tuple_shape)
|
|
165
143
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
layout += bool_layout(['Interactive threshold selector'], keys=['show_interactive_threshold_selector'], preset=[False])
|
|
176
|
-
layout += path_layout(
|
|
177
|
-
keys=['spots_extraction_folder'],
|
|
178
|
-
look_for_dir=True,
|
|
179
|
-
header= "Individual spot extraction",
|
|
180
|
-
preset= default_dict.setdefault('spots_extraction_folder', '')
|
|
181
|
-
)
|
|
182
|
-
default_filename = default_dict.setdefault("filename","") + "_spot_extraction"
|
|
183
|
-
layout += parameters_layout(
|
|
184
|
-
parameters=['spots_filename'],
|
|
185
|
-
default_values=[default_filename],
|
|
186
|
-
size= 13
|
|
187
|
-
)
|
|
188
|
-
layout += bool_layout(
|
|
189
|
-
['.csv','.excel','.feather'],
|
|
190
|
-
keys= ['do_spots_csv', 'do_spots_excel', 'do_spots_feather'],
|
|
191
|
-
preset= [default_dict.setdefault('do_spots_csv',False), default_dict.setdefault('do_spots_excel',False),default_dict.setdefault('do_spots_feather',False)]
|
|
144
|
+
layout = _detection_layout(
|
|
145
|
+
is_3D_stack=is_3D_stack,
|
|
146
|
+
is_multichannel=is_multichannel,
|
|
147
|
+
do_dense_region_deconvolution=do_dense_region_deconvolution,
|
|
148
|
+
do_clustering=do_clustering,
|
|
149
|
+
segmentation_done=segmentation_done,
|
|
150
|
+
default_dict=default_dict,
|
|
151
|
+
do_segmentation=False,
|
|
192
152
|
)
|
|
193
153
|
|
|
194
154
|
event, values = prompt(layout)
|
|
@@ -268,18 +228,45 @@ def hub_prompt(fov_results : pd.DataFrame, do_segmentation=False) -> 'Union[Lite
|
|
|
268
228
|
while True :
|
|
269
229
|
event, values = window.read()
|
|
270
230
|
if event == None : quit()
|
|
271
|
-
elif event == 'Help' : pass
|
|
272
231
|
else :
|
|
273
232
|
window.close()
|
|
274
233
|
return event, values
|
|
275
234
|
|
|
276
|
-
def coloc_prompt() :
|
|
277
|
-
layout =
|
|
278
|
-
event, values = prompt(layout)
|
|
235
|
+
def coloc_prompt(spot_list : list) :
|
|
236
|
+
layout = colocalization_layout(spot_list)
|
|
279
237
|
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
238
|
+
layout = [[sg.Col(
|
|
239
|
+
layout,
|
|
240
|
+
expand_x=True,
|
|
241
|
+
expand_y=True,
|
|
242
|
+
vertical_scroll_only=True,
|
|
243
|
+
scrollable=True
|
|
244
|
+
)
|
|
245
|
+
]]
|
|
246
|
+
window = sg.Window('small fish', layout=layout, margins=(10,10), resizable=True, location=None, auto_size_buttons=True)
|
|
247
|
+
while True :
|
|
248
|
+
event, values = window.read(timeout=100, timeout_key="timeout")
|
|
249
|
+
|
|
250
|
+
if event == None : quit()
|
|
251
|
+
elif event == "timeout" : pass
|
|
252
|
+
elif event == 'Ok' :
|
|
253
|
+
|
|
254
|
+
if values["spots1_dropdown"] =="" :
|
|
255
|
+
spots1 = values["spots1_browse"]
|
|
256
|
+
else :
|
|
257
|
+
spots1 = values["spots1_dropdown"]
|
|
258
|
+
|
|
259
|
+
if values["spots2_dropdown"] =="" :
|
|
260
|
+
spots2 = values["spots2_browse"]
|
|
261
|
+
else :
|
|
262
|
+
spots2 = values["spots2_dropdown"]
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
window.close()
|
|
266
|
+
return values['colocalisation distance'], [values['voxel_size_z'], values['voxel_size_y'], values['voxel_size_x']], spots1, spots2
|
|
267
|
+
else :
|
|
268
|
+
window.close()
|
|
269
|
+
return None,None,None,None
|
|
283
270
|
|
|
284
271
|
def rename_prompt() :
|
|
285
272
|
layout = parameters_layout(['name'], header= "Rename acquisitions", size=12)
|