small-fish-gui 1.0.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 +41 -0
- small_fish_gui/__main__.py +15 -0
- small_fish_gui/gui/__init__.py +29 -0
- small_fish_gui/gui/animation.py +30 -0
- small_fish_gui/gui/general_help_screenshot.png +0 -0
- small_fish_gui/gui/help_module.py +256 -0
- small_fish_gui/gui/layout.py +184 -0
- small_fish_gui/gui/mapping_help_screenshot.png +0 -0
- small_fish_gui/gui/prompts.py +338 -0
- small_fish_gui/gui/segmentation_help_screenshot.png +0 -0
- small_fish_gui/gui/test.py +4 -0
- small_fish_gui/interface/__init__.py +10 -0
- small_fish_gui/interface/image.py +38 -0
- small_fish_gui/interface/output.py +42 -0
- small_fish_gui/interface/parameters.py +2 -0
- small_fish_gui/interface/testing.py +8 -0
- small_fish_gui/pipeline/_colocalisation.py +266 -0
- small_fish_gui/pipeline/_custom_errors.py +2 -0
- small_fish_gui/pipeline/_detection_visualisation.py +139 -0
- small_fish_gui/pipeline/_preprocess.py +272 -0
- small_fish_gui/pipeline/_segmentation.py +334 -0
- small_fish_gui/pipeline/_signaltonoise.py +219 -0
- small_fish_gui/pipeline/actions.py +127 -0
- small_fish_gui/pipeline/detection.py +640 -0
- small_fish_gui/pipeline/main.py +80 -0
- small_fish_gui/pipeline/test.py +116 -0
- small_fish_gui/start.py +7 -0
- small_fish_gui/utils.py +55 -0
- small_fish_gui-1.0.0.dist-info/METADATA +57 -0
- small_fish_gui-1.0.0.dist-info/RECORD +32 -0
- small_fish_gui-1.0.0.dist-info/WHEEL +4 -0
- small_fish_gui-1.0.0.dist-info/licenses/LICENSE +24 -0
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# Author: Floric Slimani
|
|
2
|
+
|
|
3
|
+
"""
|
|
4
|
+
Minimal software for spot detection using big-fish.
|
|
5
|
+
|
|
6
|
+
BigFish
|
|
7
|
+
|
|
8
|
+
Published work :
|
|
9
|
+
|
|
10
|
+
Arthur Imbert, Wei Ouyang, Adham Safieddine, Emeline Coleno, Christophe Zimmer, Edouard Bertrand, Thomas Walter, Florian Mueller.
|
|
11
|
+
FISH-quant v2: a scalable and modular analysis tool for smFISH image analysis. bioRxiv (2021) https://doi.org/10.1101/2021.07.20.453024
|
|
12
|
+
|
|
13
|
+
BSD 3-Clause License
|
|
14
|
+
|
|
15
|
+
Copyright © 2020, Arthur Imbert
|
|
16
|
+
All rights reserved.
|
|
17
|
+
|
|
18
|
+
Redistribution and use in source and binary forms, with or without
|
|
19
|
+
modification, are permitted provided that the following conditions are met:
|
|
20
|
+
* Redistributions of source code must retain the above copyright
|
|
21
|
+
notice, this list of conditions and the following disclaimer.
|
|
22
|
+
* Redistributions in binary form must reproduce the above copyright
|
|
23
|
+
notice, this list of conditions and the following disclaimer in the
|
|
24
|
+
documentation and/or other materials provided with the distribution.
|
|
25
|
+
* Neither the name of the copyright holder nor the names of its
|
|
26
|
+
contributors may be used to endorse or promote products derived from
|
|
27
|
+
this software without specific prior written permission.
|
|
28
|
+
|
|
29
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
30
|
+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
31
|
+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
32
|
+
DISCLAIMED. IN NO EVENT SHALL COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY
|
|
33
|
+
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
34
|
+
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
35
|
+
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
36
|
+
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
37
|
+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
38
|
+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
39
|
+
|
|
40
|
+
"""
|
|
41
|
+
__version__ = "0.5.0"
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
import os
|
|
3
|
+
import PySimpleGUI as sg
|
|
4
|
+
|
|
5
|
+
def main():
|
|
6
|
+
import small_fish.pipeline.main
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
if __name__ == "__main__":
|
|
10
|
+
try :
|
|
11
|
+
sys.exit(main())
|
|
12
|
+
except Exception as error :
|
|
13
|
+
sg.popup("Sorry. Something went wrong...\nIf you have some time to spare could you please communicate the error you encountered (next window) on :\nhttps://github.com/2Echoes/small_fish/issues.")
|
|
14
|
+
sg.popup_error_with_traceback(error)
|
|
15
|
+
raise error
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"""
|
|
2
|
+
This subpackge contains code related to graphical interface
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from .prompts import _error_popup
|
|
6
|
+
from .prompts import _warning_popup
|
|
7
|
+
from .prompts import prompt
|
|
8
|
+
from .prompts import prompt_with_help
|
|
9
|
+
from .prompts import input_image_prompt
|
|
10
|
+
from .prompts import hub_prompt
|
|
11
|
+
from .prompts import detection_parameters_promt
|
|
12
|
+
from .prompts import coloc_prompt
|
|
13
|
+
from .prompts import post_analysis_prompt
|
|
14
|
+
from .prompts import output_image_prompt
|
|
15
|
+
from .prompts import ask_cancel_detection
|
|
16
|
+
from .prompts import ask_cancel_segmentation
|
|
17
|
+
from .prompts import ask_help
|
|
18
|
+
from .prompts import ask_detection_confirmation
|
|
19
|
+
|
|
20
|
+
#Helpers to build windows
|
|
21
|
+
from .layout import parameters_layout
|
|
22
|
+
from .layout import bool_layout
|
|
23
|
+
from .layout import path_layout
|
|
24
|
+
from .layout import combo_layout
|
|
25
|
+
from .layout import tuple_layout
|
|
26
|
+
from .layout import radio_layout
|
|
27
|
+
from .layout import add_header
|
|
28
|
+
|
|
29
|
+
from .animation import add_default_loading
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import PySimpleGUI as sg
|
|
2
|
+
import numpy as np
|
|
3
|
+
|
|
4
|
+
WAITING_TEXT = [
|
|
5
|
+
'Running...',
|
|
6
|
+
'Computing science...',
|
|
7
|
+
'Preparing some good results...',
|
|
8
|
+
'A good day for science...'
|
|
9
|
+
]
|
|
10
|
+
|
|
11
|
+
def add_default_loading(funct) :
|
|
12
|
+
def inner(*args,**kwargs) :
|
|
13
|
+
random_text = np.random.randint(0,len(WAITING_TEXT))
|
|
14
|
+
waiting_layout = [
|
|
15
|
+
[sg.Text(WAITING_TEXT[random_text], font= '10')]
|
|
16
|
+
]
|
|
17
|
+
window = sg.Window(
|
|
18
|
+
title= 'small_fish',
|
|
19
|
+
layout= waiting_layout,
|
|
20
|
+
grab_anywhere= True,
|
|
21
|
+
finalize=True
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
window.read(timeout= 30, close= False)
|
|
25
|
+
try :
|
|
26
|
+
return funct(*args, **kwargs)
|
|
27
|
+
finally :
|
|
28
|
+
window.close()
|
|
29
|
+
return inner
|
|
30
|
+
|
|
Binary file
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
import PySimpleGUI as sg
|
|
2
|
+
import os
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def _fake_help() :
|
|
6
|
+
layout = [
|
|
7
|
+
[sg.Text("Fake help window")],
|
|
8
|
+
[sg.Button('Close')]
|
|
9
|
+
]
|
|
10
|
+
|
|
11
|
+
return layout
|
|
12
|
+
|
|
13
|
+
def ask_help(chapter= '') :
|
|
14
|
+
|
|
15
|
+
if chapter == 'general' :
|
|
16
|
+
help_l = _general_help()
|
|
17
|
+
|
|
18
|
+
elif chapter == 'segmentation' :
|
|
19
|
+
help_l= _segmentation_help()
|
|
20
|
+
|
|
21
|
+
elif chapter == 'mapping' :
|
|
22
|
+
help_l = _mapping_help()
|
|
23
|
+
|
|
24
|
+
elif chapter == 'detection' :
|
|
25
|
+
help_l = _detection_help()
|
|
26
|
+
|
|
27
|
+
else :
|
|
28
|
+
help_l = _fake_help()
|
|
29
|
+
|
|
30
|
+
window = sg.Window('Help (small fish)', layout=help_l, keep_on_top=True, auto_size_text=True)
|
|
31
|
+
event, values = window.read(timeout= 0.1)
|
|
32
|
+
|
|
33
|
+
if event == 'Close' :
|
|
34
|
+
window.close()
|
|
35
|
+
|
|
36
|
+
def add_help_button(help_request) :
|
|
37
|
+
pass
|
|
38
|
+
|
|
39
|
+
def _general_help() :
|
|
40
|
+
|
|
41
|
+
im_path = os.path.dirname(__file__) + '/general_help_screenshot.png'
|
|
42
|
+
|
|
43
|
+
help_text = """
|
|
44
|
+
Pipeline settings :
|
|
45
|
+
|
|
46
|
+
Dense regions deconvolution : (Recommanded for cluster computations) Detect dense and bright regions with potential clustered
|
|
47
|
+
spots and simulate a more realistic number of spots in these regions.
|
|
48
|
+
See bigfish documentation : https://big-fish.readthedocs.io/en/stable/detection/dense.html
|
|
49
|
+
|
|
50
|
+
Cluster computation :
|
|
51
|
+
DBScan algorithm is ran by big-fish to detecte clusters of spots. Use is you want to quantify one of the following :
|
|
52
|
+
Transcription sites, foci, colocalisation of spots near foci...
|
|
53
|
+
|
|
54
|
+
Segmentation : Perform full cell segmentation in 2D (cytoplasm + nucleus) via cellpose.
|
|
55
|
+
You can use your own retrained models or out of the box models from cellpose.
|
|
56
|
+
|
|
57
|
+
Napari correct :
|
|
58
|
+
After each detection, opens a Napari viewer, enabling the user to visualise, add or remove spots and clusters.
|
|
59
|
+
"""
|
|
60
|
+
|
|
61
|
+
layout = [
|
|
62
|
+
[sg.Text("Welcome to small fish", font= 'bold 15')],
|
|
63
|
+
[sg.Image(im_path)],
|
|
64
|
+
[sg.Text(help_text, font = 'bold 10')]
|
|
65
|
+
]
|
|
66
|
+
|
|
67
|
+
return layout
|
|
68
|
+
|
|
69
|
+
def _detection_help() :
|
|
70
|
+
|
|
71
|
+
header = """
|
|
72
|
+
Detection is the main feature we use from big-fish package (usage requires quote).
|
|
73
|
+
Access fully detailed documentation :
|
|
74
|
+
|
|
75
|
+
DETECTION : https://big-fish.readthedocs.io/en/stable/detection/spots.html
|
|
76
|
+
DENSE REGIONS DECONVOLUTION : https://big-fish.readthedocs.io/en/stable/detection/dense.html
|
|
77
|
+
CLUSTERING : https://big-fish.readthedocs.io/en/stable/detection/cluster.html
|
|
78
|
+
|
|
79
|
+
"""
|
|
80
|
+
detection_header= """
|
|
81
|
+
|
|
82
|
+
DETECTION PARAMETERS
|
|
83
|
+
"""
|
|
84
|
+
detection_text = """
|
|
85
|
+
threshold
|
|
86
|
+
Leave empty for automatic threshold computation (see doc). Or set a manual threshold to apply after LoG filter.
|
|
87
|
+
|
|
88
|
+
threshold penalty
|
|
89
|
+
Custom feature. Apply a multiplicator to automatic threshold.
|
|
90
|
+
Leave empty or 1 for no modification of auto threshold.
|
|
91
|
+
From 0<.<1 values will lower the threshold, increasing the number of spot detected.
|
|
92
|
+
On the contrary >1 values will increase the threshold, reducing the number of spot detected.
|
|
93
|
+
|
|
94
|
+
voxel_size
|
|
95
|
+
Size of a voxel, in nanometer. One value per spatial dimension (zyx or yx dimensions).
|
|
96
|
+
If it’s a scalar, the same value is applied to every dimensions. Not used if ‘log_kernel_size’ and ‘minimum_distance’ are provided.
|
|
97
|
+
|
|
98
|
+
spot_size
|
|
99
|
+
Radius of the spot, in nanometer. One value per spatial dimension (zyx or yx dimensions).
|
|
100
|
+
If it’s a scalar, the same radius is applied to every dimensions.
|
|
101
|
+
Not used if ‘log_kernel_size’ and ‘minimum_distance’ are provided.
|
|
102
|
+
|
|
103
|
+
log kernel size
|
|
104
|
+
Size of the LoG kernel. It equals the standard deviation (in pixels) used for the gaussian kernel
|
|
105
|
+
(one for each dimension). One value per spatial dimension (zyx or yx dimensions). If it’s a scalar,
|
|
106
|
+
the same standard deviation is applied to every dimensions.
|
|
107
|
+
If None, we estimate it with the voxel size and spot radius.
|
|
108
|
+
|
|
109
|
+
minimum distance
|
|
110
|
+
Minimum distance (in pixels) between two spots we want to be able to detect separately.
|
|
111
|
+
One value per spatial dimension (zyx or yx dimensions).
|
|
112
|
+
If it’s a scalar, the same distance is applied to every dimensions.
|
|
113
|
+
If None, we estimate it with the voxel size and spot radius.
|
|
114
|
+
|
|
115
|
+
"""
|
|
116
|
+
deconv_header="""
|
|
117
|
+
DENSE REGIONS DECONVOLUTION PARAMETERS
|
|
118
|
+
|
|
119
|
+
"""
|
|
120
|
+
deconv_text="""
|
|
121
|
+
alpha
|
|
122
|
+
Note : Simply put the higher alpha the less spots are added in bright regions.
|
|
123
|
+
|
|
124
|
+
Intensity percentile used to compute the reference spot, between 0 and 1.
|
|
125
|
+
The higher, the brighter are the spots simulated in the dense regions.
|
|
126
|
+
Consequently, a high intensity score reduces the number of spots added.
|
|
127
|
+
Default is 0.5, meaning the reference spot considered is the median spot.
|
|
128
|
+
|
|
129
|
+
beta
|
|
130
|
+
Note : Simply put the higher beta the brighter regions need to be to be deconvoluted.
|
|
131
|
+
|
|
132
|
+
Multiplicative factor for the intensity threshold of a dense region. Default is 1.
|
|
133
|
+
Threshold is computed with the formula:
|
|
134
|
+
|
|
135
|
+
threshold = beta * max(median_spot)
|
|
136
|
+
|
|
137
|
+
with median_spot the median value of all detected spot signals.
|
|
138
|
+
|
|
139
|
+
gamma
|
|
140
|
+
Note : for gamma = 0 no gaussian filter is performed.
|
|
141
|
+
|
|
142
|
+
Multiplicative factor use to compute the gaussian kernel size:
|
|
143
|
+
|
|
144
|
+
kernel_size = gamma * spot_size / voxel_size
|
|
145
|
+
|
|
146
|
+
We perform a large gaussian filter with such scale to estimate image background and remove it from original image.
|
|
147
|
+
A large gamma increases the scale of the gaussian filter and smooth the estimated background.
|
|
148
|
+
To decompose very large bright areas, a larger gamma should be set.
|
|
149
|
+
|
|
150
|
+
kernel_size
|
|
151
|
+
Standard deviation used for the gaussian kernel (one for each dimension), in pixel.
|
|
152
|
+
If it’s a scalar, the same standard deviation is applied to every dimensions.
|
|
153
|
+
If None, we estimate the kernel size from ‘spot_radius’, ‘voxel_size’ and ‘gamma’
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
"""
|
|
157
|
+
clustering_header="""
|
|
158
|
+
CLUSTERING PARAMETERS
|
|
159
|
+
|
|
160
|
+
"""
|
|
161
|
+
clustering_text="""
|
|
162
|
+
cluster size
|
|
163
|
+
The maximum distance between two samples for one to be considered as in the neighborhood of the other.
|
|
164
|
+
Radius expressed in nanometer.
|
|
165
|
+
|
|
166
|
+
NOTE : Cluster centroids are computed from bigfish DBScan algorithm.
|
|
167
|
+
But the number of spots belonging to those clusters is computed as the number of sptos closer than the cluster_size distance (nanometer).
|
|
168
|
+
Which can yield a slightly different result than bigfish but allow us to add and delete cluster with the napari correction option.
|
|
169
|
+
|
|
170
|
+
min number of spots
|
|
171
|
+
The number of spots in a neighborhood for a point to be considered as a core point (from which a cluster is expanded).
|
|
172
|
+
This includes the point itself.
|
|
173
|
+
|
|
174
|
+
"""
|
|
175
|
+
|
|
176
|
+
quote = """
|
|
177
|
+
BigFish quote :
|
|
178
|
+
Arthur Imbert, Wei Ouyang, Adham Safieddine, Emeline Coleno, Christophe Zimmer, Edouard Bertrand, Thomas Walter, Florian Mueller.
|
|
179
|
+
FISH-quant v2: a scalable and modular analysis tool for smFISH image analysis. bioRxiv (2021)
|
|
180
|
+
https://doi.org/10.1101/2021.07.20.45302
|
|
181
|
+
|
|
182
|
+
"""
|
|
183
|
+
|
|
184
|
+
layout = [
|
|
185
|
+
[sg.Text(header, font= "bold 15")],
|
|
186
|
+
[sg.Column([
|
|
187
|
+
[sg.Text(detection_header, font= 'bold 13')],
|
|
188
|
+
[sg.Text(detection_text)],
|
|
189
|
+
[sg.Text(deconv_header, font= 'bold 13')],
|
|
190
|
+
[sg.Text(deconv_text)],
|
|
191
|
+
[sg.Text(clustering_header, font= 'bold 13')],
|
|
192
|
+
[sg.Text(clustering_text)],
|
|
193
|
+
], scrollable=True, vertical_scroll_only=True)],
|
|
194
|
+
[sg.Text(quote, font= 'italic 8')]
|
|
195
|
+
]
|
|
196
|
+
|
|
197
|
+
return layout
|
|
198
|
+
|
|
199
|
+
def _segmentation_help() :
|
|
200
|
+
|
|
201
|
+
cellpose1_quote = """Stringer, C., Wang, T., Michaelos, M., & Pachitariu, M. (2021).
|
|
202
|
+
Cellpose: a generalist algorithm for cellular segmentation. Nature methods, 18(1), 100-106."""
|
|
203
|
+
cellpose2_quote = """Pachitariu, M. & Stringer, C. (2022).
|
|
204
|
+
Cellpose 2.0: how to train your own model. Nature methods, 1-8."""
|
|
205
|
+
im_path = os.path.dirname(__file__) + '/segmentation_help_screenshot.png'
|
|
206
|
+
|
|
207
|
+
layout =[
|
|
208
|
+
[sg.Text("Segmentation is performed using Cellpose 2.0; this is published work that requires citation.\n")],
|
|
209
|
+
[sg.Text(cellpose1_quote)],
|
|
210
|
+
[sg.Text(cellpose2_quote)],
|
|
211
|
+
[sg.Image(im_path)]
|
|
212
|
+
]
|
|
213
|
+
|
|
214
|
+
return layout
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
def _mapping_help() :
|
|
218
|
+
|
|
219
|
+
im_path = os.path.dirname(__file__) + '/mapping_help_screenshot.png'
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
help_text = """
|
|
223
|
+
Depending on image format, dimensions (time, channels, spatial dimensions) are not always stored in the same order.
|
|
224
|
+
An automatic configuration is performed; nonetheless it is recommanded to check it worked properly or your data can
|
|
225
|
+
get mixed up.
|
|
226
|
+
|
|
227
|
+
This window present the shape of your image : example (1080,1080,4)
|
|
228
|
+
1080x1080 are the xy dimension (pixel resolution); and 4 is the number of channel. Another example a 3D multichannel
|
|
229
|
+
stack could be (18,4,1080,1080)...
|
|
230
|
+
The machine understand the order of the information such as (1080,1080,4) positions are (0,1,2). /!\ It starts from zero! /!\
|
|
231
|
+
The mapping purpose is to link the position to the type of informations, in this case we want :
|
|
232
|
+
|
|
233
|
+
x : 1
|
|
234
|
+
y : 0
|
|
235
|
+
z : None
|
|
236
|
+
c : 2
|
|
237
|
+
t : None
|
|
238
|
+
|
|
239
|
+
The other example from above (18,4,1080,1080) mapping would be :
|
|
240
|
+
|
|
241
|
+
x : 3
|
|
242
|
+
y : 2
|
|
243
|
+
z : 0
|
|
244
|
+
c : 1
|
|
245
|
+
t : None
|
|
246
|
+
"""
|
|
247
|
+
|
|
248
|
+
layout = [
|
|
249
|
+
[sg.Text(help_text)],
|
|
250
|
+
[sg.Image(im_path)]
|
|
251
|
+
]
|
|
252
|
+
|
|
253
|
+
return layout
|
|
254
|
+
|
|
255
|
+
def _small_fish_help() :
|
|
256
|
+
pass
|
|
@@ -0,0 +1,184 @@
|
|
|
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(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
|
+
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
|
+
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
|
|
Binary file
|