small-fish-gui 1.9.3__py3-none-any.whl → 1.10.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/README.md +7 -9
- small_fish_gui/__init__.py +5 -2
- small_fish_gui/__main__.py +40 -17
- small_fish_gui/batch/prompt.py +1 -1
- small_fish_gui/batch/update.py +2 -2
- small_fish_gui/batch/values.txt +1 -1
- small_fish_gui/gui/__init__.py +1 -2
- small_fish_gui/gui/_napari_widgets.py +433 -25
- small_fish_gui/gui/layout.py +10 -7
- small_fish_gui/gui/napari_visualiser.py +68 -167
- small_fish_gui/gui/prompts.py +42 -45
- small_fish_gui/gui/testing.ipynb +138 -28
- small_fish_gui/gui/theme.py +5 -0
- small_fish_gui/hints.py +9 -7
- small_fish_gui/interface/__init__.py +1 -0
- small_fish_gui/interface/image.py +22 -1
- small_fish_gui/interface/testing.py +60 -9
- small_fish_gui/pipeline/_preprocess.py +18 -12
- small_fish_gui/pipeline/actions.py +5 -0
- small_fish_gui/pipeline/detection.py +31 -8
- small_fish_gui/pipeline/main.py +40 -3
- small_fish_gui/pipeline/segmentation.py +2 -2
- small_fish_gui/requirements.txt +12 -11
- {small_fish_gui-1.9.3.dist-info → small_fish_gui-1.10.0.dist-info}/METADATA +12 -10
- small_fish_gui-1.10.0.dist-info/RECORD +49 -0
- small_fish_gui/Segmentation example.jpg +0 -0
- small_fish_gui/gui/help_module.py +0 -256
- small_fish_gui/napari_detection_example.png +0 -0
- small_fish_gui-1.9.3.dist-info/RECORD +0 -51
- {small_fish_gui-1.9.3.dist-info → small_fish_gui-1.10.0.dist-info}/WHEEL +0 -0
- {small_fish_gui-1.9.3.dist-info → small_fish_gui-1.10.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -2,145 +2,16 @@
|
|
|
2
2
|
Contains Napari wrappers to visualise and correct spots/clusters.
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
-
import napari.layers
|
|
6
|
-
import napari.types
|
|
7
5
|
import numpy as np
|
|
8
6
|
import napari
|
|
9
7
|
|
|
10
|
-
from sklearn.cluster import DBSCAN
|
|
11
|
-
from sklearn.neighbors import NearestNeighbors
|
|
12
|
-
|
|
13
8
|
from magicgui import widgets
|
|
14
9
|
|
|
15
10
|
from bigfish.stack import check_parameter
|
|
16
|
-
from
|
|
17
|
-
from ._napari_widgets import
|
|
11
|
+
from ._napari_widgets import CellLabelEraser, SegmentationReseter, ChangesPropagater, FreeLabelPicker
|
|
12
|
+
from ._napari_widgets import ClusterIDSetter, ClusterMerger, ClusterUpdater, ClusterCreator
|
|
13
|
+
from ._napari_widgets import initialize_all_cluster_wizards
|
|
18
14
|
from ..utils import compute_anisotropy_coef
|
|
19
|
-
from ..pipeline._colocalisation import spots_multicolocalisation
|
|
20
|
-
|
|
21
|
-
#Post detection
|
|
22
|
-
|
|
23
|
-
def _update_clusters(
|
|
24
|
-
old_spots : np.ndarray,
|
|
25
|
-
spot_cluster_id : np.ndarray,
|
|
26
|
-
new_spots : np.ndarray,
|
|
27
|
-
old_clusters : np.ndarray,
|
|
28
|
-
new_clusters : np.ndarray,
|
|
29
|
-
cluster_size : int,
|
|
30
|
-
min_number_spot : int,
|
|
31
|
-
voxel_size : tuple,
|
|
32
|
-
null_value = -2,
|
|
33
|
-
talks = False,
|
|
34
|
-
) :
|
|
35
|
-
"""
|
|
36
|
-
|
|
37
|
-
new_spots get weight of 1.
|
|
38
|
-
spots already in cluster get weight 1
|
|
39
|
-
spots not in cluster before but now in cluster radius get weigth = min_number_spot/*number of spot in new cluster radius (>=1)*
|
|
40
|
-
spots in radius of deleted cluster get weight = 0 unless they are in radius of a new cluster.
|
|
41
|
-
|
|
42
|
-
Parameters
|
|
43
|
-
----------
|
|
44
|
-
new_spots : array (spots_number, space_dim + 1,) containing coordinates of each spots after napari correction as well as the id of belonging cluster. -1 if free spot, np.NaN if unknown.
|
|
45
|
-
old_clusters : array (spots_number, space_dim + 2,) containing coordinates of each clusters centroid before napari correction, number of spots in cluster and the id of cluster.
|
|
46
|
-
new_clusters : array (spots_number, space_dim + 2,) containing coordinates of each clusters centroid after napari correction, number of spots in cluster and the id of cluster. number of spots is NaN if new cluster.
|
|
47
|
-
cluster_size : size of cluster in nanometer passed to DBSCAN.
|
|
48
|
-
|
|
49
|
-
Returns
|
|
50
|
-
-------
|
|
51
|
-
corrected_spots : array with updated cluster id.
|
|
52
|
-
corrected_clusters : array with updated number of spot.
|
|
53
|
-
|
|
54
|
-
"""
|
|
55
|
-
|
|
56
|
-
spots_weights = np.ones(len(new_spots), dtype=float)
|
|
57
|
-
|
|
58
|
-
if talks :
|
|
59
|
-
print("\nTALKS IN napari_visualiser._update_clusters")
|
|
60
|
-
print('new_spots_shape : ', new_spots.shape)
|
|
61
|
-
print('old_clusters : ', old_clusters.shape)
|
|
62
|
-
print('new_clusters : ', new_clusters.shape)
|
|
63
|
-
|
|
64
|
-
#Finding new and deleted clusters
|
|
65
|
-
deleted_cluster = old_clusters[~(np.isin(old_clusters[:,-1], new_clusters[:,-1]))]
|
|
66
|
-
added_cluster = new_clusters[new_clusters[:,-1] == null_value]
|
|
67
|
-
|
|
68
|
-
if talks :
|
|
69
|
-
print('deleted_cluster : ', deleted_cluster.shape)
|
|
70
|
-
print('added_cluster : ', added_cluster.shape)
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
#Removing cluster_id from points clustered in deleted clusters
|
|
75
|
-
spots_0_weights = old_spots[np.isin(spot_cluster_id, deleted_cluster[:,-1])]
|
|
76
|
-
spots_weights[np.isin(new_spots, spots_0_weights).all(axis=1)] = 0 #Setting weigth to 0 for spots in deleted clusters.
|
|
77
|
-
|
|
78
|
-
if talks :
|
|
79
|
-
print("deleted cluster ids : ", deleted_cluster[:,-1])
|
|
80
|
-
print("spots in deleted cluster : \n", spots_0_weights)
|
|
81
|
-
|
|
82
|
-
#Finding spots in range of new clusters
|
|
83
|
-
if len(added_cluster) > 0 :
|
|
84
|
-
points_neighbors = NearestNeighbors(radius= cluster_size)
|
|
85
|
-
points_neighbors.fit(new_spots*voxel_size)
|
|
86
|
-
neighbor_query = points_neighbors.radius_neighbors(added_cluster[:,:-2]*voxel_size, return_distance=False)
|
|
87
|
-
|
|
88
|
-
for cluster_neighbor in neighbor_query :
|
|
89
|
-
neighboring_spot_number = len(cluster_neighbor)
|
|
90
|
-
if neighboring_spot_number == 0 : continue # will not add a cluster if there is not even one spot nearby.
|
|
91
|
-
weight = min_number_spot / neighboring_spot_number # >1
|
|
92
|
-
if weight <= 1 : print("napari._update_clusters warning : weight <= 1; this should not happen some clusters might be missed during post napari computation.")
|
|
93
|
-
if any(spots_weights[cluster_neighbor] > weight) : # Not replacing a weight for a smaller weigth to ensure all new clusters will be added.
|
|
94
|
-
mask = spots_weights[cluster_neighbor] > weight
|
|
95
|
-
cluster_neighbor = np.delete(cluster_neighbor, mask)
|
|
96
|
-
if len(cluster_neighbor) > 0 : spots_weights[cluster_neighbor] = weight
|
|
97
|
-
|
|
98
|
-
#Initiating new DBSCAN model
|
|
99
|
-
dbscan_model = DBSCAN(cluster_size, min_samples=min_number_spot)
|
|
100
|
-
dbscan_model.fit(new_spots*voxel_size, sample_weight=spots_weights)
|
|
101
|
-
|
|
102
|
-
#Constructing corrected_arrays
|
|
103
|
-
spots_labels = dbscan_model.labels_.reshape(len(new_spots), 1)
|
|
104
|
-
corrected_spots = np.concatenate([new_spots, spots_labels], axis=1).astype(int)
|
|
105
|
-
corrected_cluster = _extract_information(corrected_spots)
|
|
106
|
-
|
|
107
|
-
if talks :
|
|
108
|
-
print("spots with weigth 0 :", len(spots_weights[spots_weights == 0]))
|
|
109
|
-
print("spots with weigth > 1 :", len(spots_weights[spots_weights > 1]))
|
|
110
|
-
print("spots with weigth == 1 :", len(spots_weights[spots_weights == 1]))
|
|
111
|
-
print("spots with weigth < 1 :", len(spots_weights[np.logical_and(spots_weights < 1,spots_weights > 0)]))
|
|
112
|
-
|
|
113
|
-
print('corrected_spots : ', corrected_spots.shape)
|
|
114
|
-
print('corrected_cluster : ', corrected_cluster.shape)
|
|
115
|
-
print("END TALK\n")
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
return corrected_spots, corrected_cluster
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
def __update_clusters(new_clusters: np.ndarray, spots: np.ndarray, voxel_size, cluster_size, shape) :
|
|
122
|
-
"""
|
|
123
|
-
Outdated. previous behaviour.
|
|
124
|
-
"""
|
|
125
|
-
if len(new_clusters) == 0 : return new_clusters
|
|
126
|
-
if len(spots) == 0 : return np.empty(shape=(0,2+len(voxel_size)), dtype=int)
|
|
127
|
-
|
|
128
|
-
if len(new_clusters[0]) in [2,3] :
|
|
129
|
-
new_clusters = np.concatenate([
|
|
130
|
-
new_clusters,
|
|
131
|
-
np.zeros(shape=(len(new_clusters),1), dtype=int),
|
|
132
|
-
np.arange(len(new_clusters), dtype=int).reshape(len(new_clusters),1)
|
|
133
|
-
],axis=1, dtype=int)
|
|
134
|
-
|
|
135
|
-
assert len(new_clusters[0]) == 4 or len(new_clusters[0]) == 5, "Wrong number of coordinates for clusters should not happen."
|
|
136
|
-
|
|
137
|
-
# Update spots clusters
|
|
138
|
-
new_clusters[:,-2] = spots_multicolocalisation(new_clusters[:,:-2], spots, radius_nm= cluster_size, voxel_size=voxel_size, image_shape=shape)
|
|
139
|
-
|
|
140
|
-
# delete too small clusters
|
|
141
|
-
new_clusters = np.delete(new_clusters, new_clusters[:,-2] == 0, 0)
|
|
142
|
-
|
|
143
|
-
return new_clusters
|
|
144
15
|
|
|
145
16
|
def correct_spots(
|
|
146
17
|
image,
|
|
@@ -184,14 +55,19 @@ def correct_spots(
|
|
|
184
55
|
for im, color in zip(other_images, other_colors) :
|
|
185
56
|
Viewer.add_image(im, scale=scale, blending='additive', visible=False, colormap=color, contrast_limits=[im.min(), im.max()])
|
|
186
57
|
|
|
187
|
-
Viewer.add_points( # single molecule spots; this layer can be update by user.
|
|
58
|
+
single_layer = Viewer.add_points( # single molecule spots; this layer can be update by user.
|
|
188
59
|
spots,
|
|
189
60
|
size = 5,
|
|
190
61
|
scale=scale,
|
|
191
|
-
face_color= 'transparent',
|
|
62
|
+
face_color= 'transparent',
|
|
63
|
+
border_color ='red',
|
|
192
64
|
opacity= 1,
|
|
193
65
|
symbol= 'disc',
|
|
194
|
-
name= 'single spots'
|
|
66
|
+
name= 'single spots',
|
|
67
|
+
features={
|
|
68
|
+
"cluster_id" : spot_cluster_id if not spot_cluster_id is None else [],
|
|
69
|
+
"end" : [True] * len(spots)
|
|
70
|
+
}
|
|
195
71
|
)
|
|
196
72
|
|
|
197
73
|
if type(clusters) != type(None) :
|
|
@@ -199,7 +75,7 @@ def correct_spots(
|
|
|
199
75
|
clusters_coordinates = clusters[:, :dim]
|
|
200
76
|
else :
|
|
201
77
|
clusters_coordinates = np.empty(shape=(0,dim), dtype=int)
|
|
202
|
-
Viewer.add_points( # cluster; this layer can be update by user.
|
|
78
|
+
cluster_layer = Viewer.add_points( # cluster; this layer can be update by user.
|
|
203
79
|
clusters_coordinates,
|
|
204
80
|
size = 10,
|
|
205
81
|
scale=scale,
|
|
@@ -207,45 +83,70 @@ def correct_spots(
|
|
|
207
83
|
opacity= 0.7,
|
|
208
84
|
symbol= 'diamond',
|
|
209
85
|
name= 'foci',
|
|
210
|
-
features= {
|
|
211
|
-
|
|
86
|
+
features= {
|
|
87
|
+
"spot_number" : clusters[:,dim],
|
|
88
|
+
"cluster_id" : clusters[:,dim+1],
|
|
89
|
+
"end" : [True] * len(clusters_coordinates)
|
|
90
|
+
},
|
|
91
|
+
feature_defaults= {"spot_number" : 0, "cluster_id" : -2, "end" : True} # napari features default will not work with np.NaN passing -2 instead.
|
|
212
92
|
)
|
|
213
93
|
|
|
214
94
|
if type(cell_label) != type(None) and not np.array_equal(nucleus_label, cell_label) : Viewer.add_labels(cell_label, scale=scale, opacity= 0.2, blending= 'additive')
|
|
215
95
|
if type(nucleus_label) != type(None) : Viewer.add_labels(nucleus_label, scale=scale, opacity= 0.2, blending= 'additive')
|
|
216
|
-
|
|
96
|
+
|
|
97
|
+
#Adding widget
|
|
98
|
+
if type(clusters) != type(None) :
|
|
99
|
+
initialize_all_cluster_wizards(
|
|
100
|
+
single_layer=single_layer,
|
|
101
|
+
cluster_layer=cluster_layer
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
widget_clusterID = ClusterIDSetter(single_layer=single_layer, cluster_layer=cluster_layer)
|
|
105
|
+
widget_cluster_merge =ClusterMerger(single_layer=single_layer, cluster_layer=cluster_layer)
|
|
106
|
+
widget_cluster_updater = ClusterUpdater(
|
|
107
|
+
single_layer=single_layer,
|
|
108
|
+
cluster_layer=cluster_layer,
|
|
109
|
+
default_cluster_radius= cluster_size,
|
|
110
|
+
default_min_spot= min_spot_number,
|
|
111
|
+
voxel_size=voxel_size
|
|
112
|
+
)
|
|
113
|
+
widget_cluster_creator = ClusterCreator(
|
|
114
|
+
cluster_layer=cluster_layer,
|
|
115
|
+
single_layer=single_layer
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
buttons_container = widgets.Container(widgets=[widget_clusterID.widget, widget_cluster_creator.widget], labels=False, layout='horizontal')
|
|
120
|
+
updater_container = widgets.Container(widgets=[widget_cluster_updater.widget, widget_cluster_merge.widget], labels=False)
|
|
121
|
+
tools_container = widgets.Container(
|
|
122
|
+
widgets = [updater_container, buttons_container],
|
|
123
|
+
labels=False,
|
|
124
|
+
)
|
|
125
|
+
Viewer.window.add_dock_widget(tools_container, name='SmallFish', area='left')
|
|
126
|
+
|
|
217
127
|
Viewer.show(block=False)
|
|
218
128
|
napari.run()
|
|
219
129
|
|
|
220
|
-
new_spots = np.
|
|
130
|
+
new_spots = np.concatenate([
|
|
131
|
+
single_layer.data,
|
|
132
|
+
single_layer.features.loc[:,["cluster_id"]].to_numpy()
|
|
133
|
+
], axis=1).astype(int)
|
|
221
134
|
|
|
222
135
|
if type(clusters) != type(None) :
|
|
223
|
-
new_clusters = np.
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
new_spots = np.concatenate([new_spots, new_cluster_id], axis=1)
|
|
228
|
-
else :
|
|
229
|
-
new_cluster_id = Viewer.layers['foci'].features.to_numpy()
|
|
230
|
-
new_clusters = np.concatenate([new_clusters, new_cluster_id], axis=1)
|
|
136
|
+
new_clusters = np.concatenate([
|
|
137
|
+
cluster_layer.data,
|
|
138
|
+
cluster_layer.features.loc[:,["spot_number","cluster_id"]].to_numpy()
|
|
139
|
+
],axis=1)
|
|
231
140
|
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
old_spots =spots,
|
|
235
|
-
spot_cluster_id = spot_cluster_id,
|
|
236
|
-
new_spots=new_spots,
|
|
237
|
-
old_clusters=clusters,
|
|
238
|
-
new_clusters=new_clusters,
|
|
239
|
-
cluster_size=cluster_size,
|
|
240
|
-
min_number_spot=min_spot_number,
|
|
241
|
-
voxel_size=voxel_size,
|
|
242
|
-
null_value= -2
|
|
243
|
-
)
|
|
244
|
-
|
|
141
|
+
new_cluster_radius = widget_cluster_updater.cluster_radius
|
|
142
|
+
new_min_spot_number = widget_cluster_updater.min_spot
|
|
245
143
|
|
|
246
|
-
else :
|
|
144
|
+
else :
|
|
145
|
+
new_clusters = None
|
|
146
|
+
new_cluster_radius = None
|
|
147
|
+
new_min_spot_number = None
|
|
247
148
|
|
|
248
|
-
return new_spots, new_clusters
|
|
149
|
+
return new_spots, new_clusters, new_cluster_radius, new_min_spot_number
|
|
249
150
|
|
|
250
151
|
|
|
251
152
|
# Segmentation
|
|
@@ -295,10 +196,10 @@ def show_segmentation(
|
|
|
295
196
|
labels_layer_list += [cyto_label_layer]
|
|
296
197
|
|
|
297
198
|
#Adding widget
|
|
298
|
-
label_eraser =
|
|
299
|
-
label_picker =
|
|
300
|
-
label_reseter =
|
|
301
|
-
changes_applier =
|
|
199
|
+
label_eraser = CellLabelEraser(labels_layer_list)
|
|
200
|
+
label_picker = FreeLabelPicker(labels_layer_list)
|
|
201
|
+
label_reseter = SegmentationReseter(labels_layer_list)
|
|
202
|
+
changes_applier = ChangesPropagater(labels_layer_list)
|
|
302
203
|
|
|
303
204
|
buttons_container = widgets.Container(widgets=[label_picker.widget, changes_applier.widget, label_reseter.widget], labels=False, layout='horizontal')
|
|
304
205
|
tools_container = widgets.Container(
|
small_fish_gui/gui/prompts.py
CHANGED
|
@@ -5,13 +5,13 @@ import numpy as np
|
|
|
5
5
|
from typing import Literal, Union, Any
|
|
6
6
|
from .layout import path_layout, parameters_layout, bool_layout, tuple_layout, combo_elmt, add_header, path_layout, radio_layout
|
|
7
7
|
from ..interface import open_image, check_format, FormatError
|
|
8
|
-
|
|
8
|
+
|
|
9
9
|
|
|
10
10
|
def prompt(layout, add_ok_cancel=True, timeout=None, timeout_key='TIMEOUT_KEY', add_scrollbar=True) :
|
|
11
11
|
"""
|
|
12
12
|
Default event : 'Ok', 'Cancel'
|
|
13
13
|
"""
|
|
14
|
-
if add_ok_cancel : layout += [[sg.Button('Ok'), sg.Button('Cancel')]]
|
|
14
|
+
if add_ok_cancel : layout += [[sg.Button('Ok', bind_return_key=True), sg.Button('Cancel')]]
|
|
15
15
|
|
|
16
16
|
if add_scrollbar :
|
|
17
17
|
size = (400,500)
|
|
@@ -20,7 +20,7 @@ def prompt(layout, add_ok_cancel=True, timeout=None, timeout_key='TIMEOUT_KEY',
|
|
|
20
20
|
else :
|
|
21
21
|
size = (None,None)
|
|
22
22
|
|
|
23
|
-
window = sg.Window('small fish', layout=layout, margins=(10,10), size=size, resizable=True)
|
|
23
|
+
window = sg.Window('small fish', layout=layout, margins=(10,10), size=size, resizable=True, location=None)
|
|
24
24
|
event, values = window.read(timeout=timeout, timeout_key=timeout_key)
|
|
25
25
|
if event == None :
|
|
26
26
|
window.close()
|
|
@@ -33,33 +33,7 @@ def prompt(layout, add_ok_cancel=True, timeout=None, timeout_key='TIMEOUT_KEY',
|
|
|
33
33
|
window.close()
|
|
34
34
|
return event, values
|
|
35
35
|
|
|
36
|
-
def prompt_with_help(layout, help =None, add_scrollbar=True, vertical_scroll_only=True) :
|
|
37
|
-
layout += [[]]
|
|
38
|
-
layout += [[sg.Button('Ok'), sg.Button('Cancel')]]
|
|
39
|
-
|
|
40
|
-
if add_scrollbar :
|
|
41
|
-
size = (400,500)
|
|
42
|
-
col_elmt = sg.Column(layout, scrollable=True, vertical_scroll_only=vertical_scroll_only, size=size)
|
|
43
|
-
layout = [[col_elmt]]
|
|
44
|
-
else :
|
|
45
|
-
size = (None,None)
|
|
46
36
|
|
|
47
|
-
window = sg.Window('small fish', layout=layout, size=size, resizable=True)
|
|
48
|
-
while True :
|
|
49
|
-
event, values = window.read()
|
|
50
|
-
if event == None :
|
|
51
|
-
window.close()
|
|
52
|
-
quit()
|
|
53
|
-
|
|
54
|
-
elif event == 'Ok':
|
|
55
|
-
window.close()
|
|
56
|
-
return event, values
|
|
57
|
-
elif event == 'Help' :
|
|
58
|
-
ask_help(chapter= help)
|
|
59
|
-
|
|
60
|
-
else:
|
|
61
|
-
window.close()
|
|
62
|
-
return event,{}
|
|
63
37
|
|
|
64
38
|
def input_image_prompt(
|
|
65
39
|
is_3D_stack_preset=False,
|
|
@@ -70,7 +44,7 @@ def input_image_prompt(
|
|
|
70
44
|
) :
|
|
71
45
|
"""
|
|
72
46
|
Keys :
|
|
73
|
-
- '
|
|
47
|
+
- 'image_path'
|
|
74
48
|
- 'is_3D_stack'
|
|
75
49
|
- 'time stack'
|
|
76
50
|
- 'is_multichannel'
|
|
@@ -81,18 +55,18 @@ def input_image_prompt(
|
|
|
81
55
|
Returns Values
|
|
82
56
|
|
|
83
57
|
"""
|
|
84
|
-
layout_image_path = path_layout(['
|
|
58
|
+
layout_image_path = path_layout(['image_path'], header= "Image")
|
|
85
59
|
layout_image_path += bool_layout(['3D stack', 'Multichannel stack'],keys= ['is_3D_stack', 'is_multichannel'], preset= [is_3D_stack_preset, multichannel_preset])
|
|
86
60
|
|
|
87
61
|
if type(do_dense_regions_deconvolution_preset) != type(None) and type(do_clustering_preset) != type(None) and type(do_Napari_correction) != type(None):
|
|
88
62
|
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")
|
|
89
63
|
|
|
90
|
-
event, values =
|
|
64
|
+
event, values = prompt(layout_image_path, add_scrollbar=False)
|
|
91
65
|
|
|
92
66
|
if event == 'Cancel' :
|
|
93
67
|
return None
|
|
94
68
|
|
|
95
|
-
im_path = values['
|
|
69
|
+
im_path = values['image_path']
|
|
96
70
|
is_3D_stack = values['is_3D_stack']
|
|
97
71
|
is_multichannel = values['is_multichannel']
|
|
98
72
|
|
|
@@ -191,8 +165,8 @@ def detection_parameters_promt(
|
|
|
191
165
|
|
|
192
166
|
#Clustering
|
|
193
167
|
if do_clustering :
|
|
194
|
-
layout += parameters_layout(['
|
|
195
|
-
layout += parameters_layout(['
|
|
168
|
+
layout += parameters_layout(['cluster_size'], unit="radius(nm)", default_values=[default_dict.setdefault('cluster_size',400)])
|
|
169
|
+
layout += parameters_layout(['min_number_of_spots'], default_values=[default_dict.setdefault('min_number_of_spots', 5)])
|
|
196
170
|
|
|
197
171
|
if is_multichannel and segmentation_done :
|
|
198
172
|
default_segmentation = [default_dict.setdefault('nucleus channel signal', default_dict.setdefault('nucleus channel',0))]
|
|
@@ -205,9 +179,10 @@ def detection_parameters_promt(
|
|
|
205
179
|
header= "Individual spot extraction",
|
|
206
180
|
preset= default_dict.setdefault('spots_extraction_folder', '')
|
|
207
181
|
)
|
|
182
|
+
default_filename = default_dict.setdefault("filename","") + "_spot_extraction"
|
|
208
183
|
layout += parameters_layout(
|
|
209
184
|
parameters=['spots_filename'],
|
|
210
|
-
default_values=[
|
|
185
|
+
default_values=[default_filename],
|
|
211
186
|
size= 13
|
|
212
187
|
)
|
|
213
188
|
layout += bool_layout(
|
|
@@ -216,13 +191,12 @@ def detection_parameters_promt(
|
|
|
216
191
|
preset= [default_dict.setdefault('do_spots_csv',False), default_dict.setdefault('do_spots_excel',False),default_dict.setdefault('do_spots_feather',False)]
|
|
217
192
|
)
|
|
218
193
|
|
|
219
|
-
event, values =
|
|
194
|
+
event, values = prompt(layout)
|
|
220
195
|
if event == 'Cancel' : return None
|
|
221
196
|
if is_3D_stack : values['dim'] = 3
|
|
222
197
|
else : values['dim'] = 2
|
|
223
198
|
return values
|
|
224
199
|
|
|
225
|
-
|
|
226
200
|
def ask_replace_file(filename:str) :
|
|
227
201
|
layout = [
|
|
228
202
|
[sg.Text("{0} already exists, replace ?")],
|
|
@@ -286,10 +260,10 @@ def hub_prompt(fov_results : pd.DataFrame, do_segmentation=False) -> 'Union[Lite
|
|
|
286
260
|
[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],
|
|
287
261
|
[sg.Button('Segment cells'), sg.Button('Add detection'), sg.Button('Compute colocalisation'), sg.Button('Batch detection')],
|
|
288
262
|
[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')],
|
|
263
|
+
[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'), sg.Button('Open wiki',button_color= 'yellow', key='wiki')],
|
|
290
264
|
]
|
|
291
265
|
|
|
292
|
-
window = sg.Window('small fish', layout= layout, margins= (10,10))
|
|
266
|
+
window = sg.Window('small fish', layout= layout, margins= (10,10), location=None)
|
|
293
267
|
|
|
294
268
|
while True :
|
|
295
269
|
event, values = window.read()
|
|
@@ -301,7 +275,7 @@ def hub_prompt(fov_results : pd.DataFrame, do_segmentation=False) -> 'Union[Lite
|
|
|
301
275
|
|
|
302
276
|
def coloc_prompt() :
|
|
303
277
|
layout = parameters_layout(['colocalisation distance'], unit= 'nm', header= 'Colocalisation', default_values= 0)
|
|
304
|
-
event, values =
|
|
278
|
+
event, values = prompt(layout)
|
|
305
279
|
|
|
306
280
|
if event == 'Ok' :
|
|
307
281
|
return values['colocalisation distance']
|
|
@@ -309,7 +283,7 @@ def coloc_prompt() :
|
|
|
309
283
|
|
|
310
284
|
def rename_prompt() :
|
|
311
285
|
layout = parameters_layout(['name'], header= "Rename acquisitions", size=12)
|
|
312
|
-
event, values =
|
|
286
|
+
event, values = prompt(layout)
|
|
313
287
|
if event == 'Ok' :
|
|
314
288
|
return values['name']
|
|
315
289
|
else : return False
|
|
@@ -341,7 +315,6 @@ def ask_cancel_detection() :
|
|
|
341
315
|
else :
|
|
342
316
|
return True
|
|
343
317
|
|
|
344
|
-
|
|
345
318
|
def ask_confirmation(question_displayed : str) :
|
|
346
319
|
layout =[
|
|
347
320
|
[sg.Text(question_displayed, font= 'bold 10')],
|
|
@@ -355,7 +328,6 @@ def ask_confirmation(question_displayed : str) :
|
|
|
355
328
|
else :
|
|
356
329
|
return True
|
|
357
330
|
|
|
358
|
-
|
|
359
331
|
def prompt_save_segmentation() -> 'dict[Literal["folder","filename","ext"]]':
|
|
360
332
|
while True :
|
|
361
333
|
relaunch = False
|
|
@@ -406,4 +378,29 @@ def prompt_load_segmentation() -> 'dict[Literal["nucleus","cytoplasm"]]':
|
|
|
406
378
|
if not relaunch : break
|
|
407
379
|
|
|
408
380
|
|
|
409
|
-
return values
|
|
381
|
+
return values
|
|
382
|
+
|
|
383
|
+
def prompt_restore_main_menu() -> bool :
|
|
384
|
+
"""
|
|
385
|
+
Warn user that software will try to go back to main menu while saving parameters, and propose to save results and quit if stuck.
|
|
386
|
+
|
|
387
|
+
Returns True if user want to save and quit else False, to raise error close window.
|
|
388
|
+
"""
|
|
389
|
+
|
|
390
|
+
|
|
391
|
+
layout = [
|
|
392
|
+
[sg.Text("An error was caught while proceeding.\nSoftware can try to save parameters and return to main menu or save results and quit.")],
|
|
393
|
+
[sg.Button("Return to main menu", key='menu'), sg.Button("Save and quit", key='save')]
|
|
394
|
+
]
|
|
395
|
+
|
|
396
|
+
window = sg.Window('small fish', layout=layout, margins=(10,10), auto_size_text=True, resizable=True)
|
|
397
|
+
event, values = window.read(close=True)
|
|
398
|
+
|
|
399
|
+
if event is None :
|
|
400
|
+
return None
|
|
401
|
+
elif event == "save" :
|
|
402
|
+
return True
|
|
403
|
+
elif event == "menu" :
|
|
404
|
+
return False
|
|
405
|
+
else :
|
|
406
|
+
raise AssertionError("Unforseen answer")
|