driftlessmap 1.1.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.
Files changed (210) hide show
  1. driftlessmap/__init__.py +16 -0
  2. driftlessmap/__main__.py +5 -0
  3. driftlessmap/about.py +24 -0
  4. driftlessmap/allen_downloader.py +908 -0
  5. driftlessmap/app.py +8085 -0
  6. driftlessmap/atlas_downloader.py +370 -0
  7. driftlessmap/atlas_loader.py +526 -0
  8. driftlessmap/atlas_processor.py +784 -0
  9. driftlessmap/atlas_transform.py +111 -0
  10. driftlessmap/atlas_view.py +1435 -0
  11. driftlessmap/cell_detection.py +27 -0
  12. driftlessmap/coordinate_validation.py +19 -0
  13. driftlessmap/czi_reader.py +236 -0
  14. driftlessmap/data/WHS_atlas_labels.pkl +0 -0
  15. driftlessmap/data/allen_mice_atlas_labels.pkl +0 -0
  16. driftlessmap/data/atlas_labels.pkl +0 -0
  17. driftlessmap/data/query.csv +1328 -0
  18. driftlessmap/download_utils.py +85 -0
  19. driftlessmap/herbs.png +0 -0
  20. driftlessmap/icons/backward.svg +15 -0
  21. driftlessmap/icons/dot.svg +11 -0
  22. driftlessmap/icons/down-arrow.svg +10 -0
  23. driftlessmap/icons/fast_backward.svg +14 -0
  24. driftlessmap/icons/fast_forward.svg +14 -0
  25. driftlessmap/icons/forward.svg +14 -0
  26. driftlessmap/icons/layers/add.png +0 -0
  27. driftlessmap/icons/layers/ai.png +0 -0
  28. driftlessmap/icons/layers/eye_off.png +0 -0
  29. driftlessmap/icons/layers/eye_on.png +0 -0
  30. driftlessmap/icons/layers/eye_white.png +0 -0
  31. driftlessmap/icons/layers/hi.png +0 -0
  32. driftlessmap/icons/layers/trash.png +0 -0
  33. driftlessmap/icons/object.svg +22 -0
  34. driftlessmap/icons/sidebar/add.png +0 -0
  35. driftlessmap/icons/sidebar/atlascontrol.png +0 -0
  36. driftlessmap/icons/sidebar/atlascontrol.svg +32 -0
  37. driftlessmap/icons/sidebar/bnd.svg +14 -0
  38. driftlessmap/icons/sidebar/c_section.png +0 -0
  39. driftlessmap/icons/sidebar/c_section2.png +0 -0
  40. driftlessmap/icons/sidebar/cell.svg +24 -0
  41. driftlessmap/icons/sidebar/check.svg +9 -0
  42. driftlessmap/icons/sidebar/compare.svg +18 -0
  43. driftlessmap/icons/sidebar/contour.svg +14 -0
  44. driftlessmap/icons/sidebar/h_section.png +0 -0
  45. driftlessmap/icons/sidebar/info.svg +14 -0
  46. driftlessmap/icons/sidebar/layers.png +0 -0
  47. driftlessmap/icons/sidebar/layers.svg +23 -0
  48. driftlessmap/icons/sidebar/line.svg +10 -0
  49. driftlessmap/icons/sidebar/link.svg +18 -0
  50. driftlessmap/icons/sidebar/link_off.svg +18 -0
  51. driftlessmap/icons/sidebar/merge.svg +11 -0
  52. driftlessmap/icons/sidebar/object.svg +13 -0
  53. driftlessmap/icons/sidebar/probe.png +0 -0
  54. driftlessmap/icons/sidebar/probe.svg +23 -0
  55. driftlessmap/icons/sidebar/rotation_horizontal.svg +14 -0
  56. driftlessmap/icons/sidebar/rotation_vertical.svg +14 -0
  57. driftlessmap/icons/sidebar/s_section.png +0 -0
  58. driftlessmap/icons/sidebar/tool.png +0 -0
  59. driftlessmap/icons/sidebar/tool.svg +19 -0
  60. driftlessmap/icons/sidebar/trash.png +0 -0
  61. driftlessmap/icons/sidebar/tree_checked.svg +10 -0
  62. driftlessmap/icons/sidebar/treeview.png +0 -0
  63. driftlessmap/icons/sidebar/treeview.svg +10 -0
  64. driftlessmap/icons/sidebar/treeview2.png +0 -0
  65. driftlessmap/icons/sidebar/virus.svg +24 -0
  66. driftlessmap/icons/tdown.svg +16 -0
  67. driftlessmap/icons/toolbar/accept.svg +18 -0
  68. driftlessmap/icons/toolbar/accept2.svg +24 -0
  69. driftlessmap/icons/toolbar/aim.svg +44 -0
  70. driftlessmap/icons/toolbar/aim_not.svg +28 -0
  71. driftlessmap/icons/toolbar/anchor.svg +14 -0
  72. driftlessmap/icons/toolbar/anticlockwise_rotation.svg +12 -0
  73. driftlessmap/icons/toolbar/atlas_icon.png +0 -0
  74. driftlessmap/icons/toolbar/boundary_register.svg +18 -0
  75. driftlessmap/icons/toolbar/cancel.svg +32 -0
  76. driftlessmap/icons/toolbar/cell_select.svg +22 -0
  77. driftlessmap/icons/toolbar/cell_select_not.svg +12 -0
  78. driftlessmap/icons/toolbar/check.svg +9 -0
  79. driftlessmap/icons/toolbar/clockwise_rotation.svg +11 -0
  80. driftlessmap/icons/toolbar/closed_path.svg +16 -0
  81. driftlessmap/icons/toolbar/closed_path2 copy.svg +19 -0
  82. driftlessmap/icons/toolbar/closed_path2.svg +20 -0
  83. driftlessmap/icons/toolbar/eraser.png +0 -0
  84. driftlessmap/icons/toolbar/eraser.svg +19 -0
  85. driftlessmap/icons/toolbar/eye.svg +17 -0
  86. driftlessmap/icons/toolbar/eye_closed.svg +19 -0
  87. driftlessmap/icons/toolbar/fill.svg +12 -0
  88. driftlessmap/icons/toolbar/gps.svg +15 -0
  89. driftlessmap/icons/toolbar/h_flip.png +0 -0
  90. driftlessmap/icons/toolbar/handle.png +0 -0
  91. driftlessmap/icons/toolbar/image_icon.png +0 -0
  92. driftlessmap/icons/toolbar/image_icon.svg +25 -0
  93. driftlessmap/icons/toolbar/info.svg +14 -0
  94. driftlessmap/icons/toolbar/inpart.png +0 -0
  95. driftlessmap/icons/toolbar/inpart.svg +17 -0
  96. driftlessmap/icons/toolbar/lasso.png +0 -0
  97. driftlessmap/icons/toolbar/lasso.svg +14 -0
  98. driftlessmap/icons/toolbar/left90.png +0 -0
  99. driftlessmap/icons/toolbar/line.svg +10 -0
  100. driftlessmap/icons/toolbar/line_sites.svg +11 -0
  101. driftlessmap/icons/toolbar/linear_silicon.png +0 -0
  102. driftlessmap/icons/toolbar/linear_silicon.svg +88 -0
  103. driftlessmap/icons/toolbar/list.svg +14 -0
  104. driftlessmap/icons/toolbar/location.svg +14 -0
  105. driftlessmap/icons/toolbar/magic-wand.svg +16 -0
  106. driftlessmap/icons/toolbar/magic_white.png +0 -0
  107. driftlessmap/icons/toolbar/mask.svg +10 -0
  108. driftlessmap/icons/toolbar/match.svg +20 -0
  109. driftlessmap/icons/toolbar/matchbnd.svg +18 -0
  110. driftlessmap/icons/toolbar/matching.svg +36 -0
  111. driftlessmap/icons/toolbar/merge.svg +11 -0
  112. driftlessmap/icons/toolbar/move_down.png +0 -0
  113. driftlessmap/icons/toolbar/move_left.png +0 -0
  114. driftlessmap/icons/toolbar/move_right.png +0 -0
  115. driftlessmap/icons/toolbar/move_up.png +0 -0
  116. driftlessmap/icons/toolbar/moving.png +0 -0
  117. driftlessmap/icons/toolbar/multi-probe.svg +119 -0
  118. driftlessmap/icons/toolbar/multi_pencil.svg +23 -0
  119. driftlessmap/icons/toolbar/multi_probe.png +0 -0
  120. driftlessmap/icons/toolbar/object.svg +13 -0
  121. driftlessmap/icons/toolbar/open_path.svg +22 -0
  122. driftlessmap/icons/toolbar/outpart.png +0 -0
  123. driftlessmap/icons/toolbar/outpart.svg +26 -0
  124. driftlessmap/icons/toolbar/pencil.png +0 -0
  125. driftlessmap/icons/toolbar/pencil.svg +19 -0
  126. driftlessmap/icons/toolbar/plasso.png +0 -0
  127. driftlessmap/icons/toolbar/probe.svg +19 -0
  128. driftlessmap/icons/toolbar/radar.svg +32 -0
  129. driftlessmap/icons/toolbar/rotation.svg +45 -0
  130. driftlessmap/icons/toolbar/rotation_clockwise.svg +18 -0
  131. driftlessmap/icons/toolbar/rotation_counter_clockwise.svg +18 -0
  132. driftlessmap/icons/toolbar/ruler.svg +27 -0
  133. driftlessmap/icons/toolbar/separate_sites.svg +13 -0
  134. driftlessmap/icons/toolbar/single_pencil.svg +16 -0
  135. driftlessmap/icons/toolbar/toa.svg +11 -0
  136. driftlessmap/icons/toolbar/toa_delete.svg +36 -0
  137. driftlessmap/icons/toolbar/toaa.svg +11 -0
  138. driftlessmap/icons/toolbar/toh.svg +11 -0
  139. driftlessmap/icons/toolbar/toh_delete.svg +36 -0
  140. driftlessmap/icons/toolbar/tohh.svg +11 -0
  141. driftlessmap/icons/toolbar/trans.png +0 -0
  142. driftlessmap/icons/toolbar/trans.svg +16 -0
  143. driftlessmap/icons/toolbar/triangulation.svg +10 -0
  144. driftlessmap/icons/toolbar/two_window.png +0 -0
  145. driftlessmap/icons/toolbar/unmerge.svg +16 -0
  146. driftlessmap/icons/toolbar/v_flip.png +0 -0
  147. driftlessmap/icons/toolbar/virus.svg +24 -0
  148. driftlessmap/icons/toolbar/virus_register.svg +31 -0
  149. driftlessmap/icons/toolbar/vis2d.svg +29 -0
  150. driftlessmap/icons/toolbar/window2.png +0 -0
  151. driftlessmap/icons/toolbar/window3.png +0 -0
  152. driftlessmap/icons/toolbar/window4.png +0 -0
  153. driftlessmap/icons/tree_close.svg +14 -0
  154. driftlessmap/icons/tree_open.svg +14 -0
  155. driftlessmap/icons/up-arrow.svg +10 -0
  156. driftlessmap/image_curves.py +579 -0
  157. driftlessmap/image_reader.py +186 -0
  158. driftlessmap/image_stacks.py +359 -0
  159. driftlessmap/image_view.py +646 -0
  160. driftlessmap/images_reader.py +5 -0
  161. driftlessmap/label_tree.py +278 -0
  162. driftlessmap/layer_validation.py +25 -0
  163. driftlessmap/layers_control.py +554 -0
  164. driftlessmap/main_window.ui +883 -0
  165. driftlessmap/movable_points.py +254 -0
  166. driftlessmap/obj_items.py +122 -0
  167. driftlessmap/object_control.py +1762 -0
  168. driftlessmap/persistence.py +376 -0
  169. driftlessmap/popup_message.py +16 -0
  170. driftlessmap/probe_csv.py +319 -0
  171. driftlessmap/probe_reconstruction.py +409 -0
  172. driftlessmap/probe_utiles.py +1442 -0
  173. driftlessmap/qss/atlas_view_group_box.qss +15 -0
  174. driftlessmap/qss/box_label.qss +7 -0
  175. driftlessmap/qss/channel_selector.qss +19 -0
  176. driftlessmap/qss/color_combo.qss +121 -0
  177. driftlessmap/qss/decor_label.qss +9 -0
  178. driftlessmap/qss/dialogs.qss +11 -0
  179. driftlessmap/qss/hidden_line_edit.qss +5 -0
  180. driftlessmap/qss/label_tree.qss +123 -0
  181. driftlessmap/qss/main_window.qss +243 -0
  182. driftlessmap/qss/menu_bar.qss +42 -0
  183. driftlessmap/qss/multi_handle_slider.qss +14 -0
  184. driftlessmap/qss/obj_ctrl_bottom_button.qss +29 -0
  185. driftlessmap/qss/object_text_button.qss +19 -0
  186. driftlessmap/qss/page_control.qss +36 -0
  187. driftlessmap/qss/rotation_button.qss +9 -0
  188. driftlessmap/qss/side_bar.qss +23 -0
  189. driftlessmap/qss/spinbox.qss +106 -0
  190. driftlessmap/qss/tabs.qss +211 -0
  191. driftlessmap/qss/tool_bar.qss +77 -0
  192. driftlessmap/resources.py +34 -0
  193. driftlessmap/roi_analysis.py +375 -0
  194. driftlessmap/run_driftlessmap.py +4 -0
  195. driftlessmap/slice_stacks.py +268 -0
  196. driftlessmap/slice_validation.py +20 -0
  197. driftlessmap/toolbox.py +569 -0
  198. driftlessmap/triangulation.py +517 -0
  199. driftlessmap/triangulation_points.py +108 -0
  200. driftlessmap/user_settings.py +92 -0
  201. driftlessmap/uuuuuu.py +1168 -0
  202. driftlessmap/version.py +3 -0
  203. driftlessmap/widgets_utils.py +140 -0
  204. driftlessmap/wtiles.py +715 -0
  205. driftlessmap-1.1.0.dist-info/METADATA +186 -0
  206. driftlessmap-1.1.0.dist-info/RECORD +210 -0
  207. driftlessmap-1.1.0.dist-info/WHEEL +5 -0
  208. driftlessmap-1.1.0.dist-info/entry_points.txt +2 -0
  209. driftlessmap-1.1.0.dist-info/licenses/LICENSE.txt +23 -0
  210. driftlessmap-1.1.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,370 @@
1
+ import numpy as np
2
+ import os
3
+ from os.path import dirname, join
4
+ from PyQt6.QtWidgets import *
5
+ from PyQt6.QtGui import *
6
+ from PyQt6.QtCore import *
7
+
8
+ import pickle
9
+ import shutil
10
+ from .atlas_loader import process_atlas_raw_data
11
+ from .obj_items import render_volume, render_small_volume
12
+ from .download_utils import DownloadCancelled, download_file
13
+
14
+
15
+ class DownloadThread(QThread):
16
+ download_process_signal = pyqtSignal(int)
17
+ download_error_signal = pyqtSignal(str)
18
+ download_finished_signal = pyqtSignal(str)
19
+
20
+ def __init__(self, url, destination, expected_sha256=None, parent=None):
21
+ super(DownloadThread, self).__init__(parent)
22
+ self.url = url
23
+ self.destination = destination
24
+ self.expected_sha256 = expected_sha256
25
+
26
+ def run(self):
27
+ try:
28
+ download_file(
29
+ self.url,
30
+ self.destination,
31
+ progress=self.download_process_signal.emit,
32
+ cancelled=self.isInterruptionRequested,
33
+ expected_sha256=self.expected_sha256,
34
+ )
35
+ except DownloadCancelled:
36
+ return
37
+ except Exception as exc:
38
+ self.download_error_signal.emit(str(exc))
39
+ return
40
+ self.download_finished_signal.emit(self.destination)
41
+
42
+
43
+ class WorkerProcessData(QObject):
44
+ finished = pyqtSignal()
45
+ progress = pyqtSignal(int)
46
+
47
+ def __init__(self):
48
+ super(WorkerProcessData, self).__init__()
49
+ self.saving_folder = None
50
+ self.data_local = None
51
+ self.segmentation_local = None
52
+ self.mask_local = None
53
+ self.b_val = None
54
+ self.l_val = None
55
+ self.vox_size = None
56
+
57
+ self.atlas_data = None
58
+ self.atlas_info = None
59
+ self.segmentation_data = None
60
+ self.unique_label = None
61
+ self.label_info = None
62
+ self.boundary = None
63
+ self.small_mesh_list = None
64
+ self.mesh_data = None
65
+ self.success = False
66
+ self.message = None
67
+
68
+ def set_data(self, saving_folder, data_local, segmentation_local, mask_local, b_val, l_val, vox_size):
69
+ self.saving_folder = saving_folder
70
+ self.data_local = data_local
71
+ self.segmentation_local = segmentation_local
72
+ self.mask_local = mask_local
73
+ self.b_val = b_val
74
+ self.l_val = l_val
75
+ self.vox_size = vox_size
76
+
77
+ def run(self):
78
+ target = os.path.join(self.saving_folder, 'atlas_labels.pkl')
79
+ if not os.path.exists(target):
80
+ shutil.copyfile(join(dirname(__file__), "data/atlas_labels.pkl"), target)
81
+
82
+ self.progress.emit(1)
83
+
84
+ infile = open(os.path.join(self.saving_folder, 'atlas_labels.pkl'), 'rb')
85
+ self.label_info = pickle.load(infile)
86
+ infile.close()
87
+
88
+ self.progress.emit(5)
89
+
90
+ self.atlas_data, self.atlas_info, self.segmentation_data, self.unique_label, self.boundary, msg = \
91
+ process_atlas_raw_data(self.saving_folder, data_file=self.data_local,
92
+ segmentation_file=self.segmentation_local, mask_file=self.mask_local,
93
+ bregma_coordinates=self.b_val, lambda_coordinates=self.l_val,
94
+ voxel_size=self.vox_size)
95
+ self.message = msg
96
+
97
+ if msg == 'Atlas loaded successfully.':
98
+ self.progress.emit(40)
99
+ self.mesh_data = render_volume(self.atlas_data, self.saving_folder, factor=2, level=0.1)
100
+ self.progress.emit(50)
101
+ save_path = os.path.join(self.saving_folder, 'meshes')
102
+ if not os.path.exists(save_path):
103
+ os.mkdir(save_path)
104
+
105
+ n_label = len(self.unique_label)
106
+ progress_step = np.linspace(50, 95, n_label)
107
+
108
+ for i in range(n_label):
109
+ self.progress.emit(int(progress_step[i]))
110
+ label_id = int(self.unique_label[i])
111
+
112
+ if label_id == 0:
113
+ continue
114
+ render_small_volume(label_id, save_path, self.atlas_data, self.segmentation_data, factor=2, level=0.1)
115
+
116
+ self.small_mesh_list = {}
117
+ file_list = os.listdir(save_path)
118
+ for da_file in file_list:
119
+ file_name = os.path.basename(da_file)
120
+ da_name, file_extension = os.path.splitext(file_name)
121
+ if file_extension == '.pkl':
122
+ infile = open(os.path.join(save_path, da_file), 'rb')
123
+ md = pickle.load(infile)
124
+ infile.close()
125
+
126
+ self.small_mesh_list[str(da_name)] = md
127
+
128
+ self.progress.emit(97)
129
+ outfile = open(os.path.join(self.saving_folder, 'atlas_small_meshdata.pkl'), 'wb')
130
+ pickle.dump(self.small_mesh_list, outfile)
131
+ outfile.close()
132
+
133
+ self.progress.emit(100)
134
+ self.success = True
135
+
136
+ self.finished.emit()
137
+
138
+
139
+ class AtlasDownloader(QDialog):
140
+ def __init__(self, *args, **kwargs):
141
+ super().__init__(*args, **kwargs)
142
+ layout = QVBoxLayout(self)
143
+
144
+ self.setWindowTitle("Waxholm Rat Atlas Downloader")
145
+
146
+ self.continue_process = True
147
+
148
+ self.label_url = "https://www.nitrc.org/frs/download.php/12261/WHS_SD_rat_atlas_v4.label"
149
+ self.data_url = "https://www.nitrc.org/frs/downloadlink.php/9423/WHS_SD_rat_T2star_v1.01.nii.gz"
150
+ self.mask_url = "https://www.nitrc.org/frs/downloadlink.php/9425/WHS_SD_rat_brainmask_v1.01.nii.gz"
151
+ self.segmentation_url = "https://www.nitrc.org/frs/download.php/12260/WHS_SD_rat_atlas_v4.nii.gz"
152
+
153
+ self.label_local = "WHS_SD_rat_atlas_v4.label"
154
+ self.data_local = "WHS_SD_rat_T2star_v1.01.nii.gz"
155
+ self.mask_local = "WHS_SD_rat_brainmask_v1.01.nii.gz"
156
+ self.segmentation_local = "WHS_SD_rat_atlas_v4.nii.gz"
157
+
158
+ self.saving_folder = None
159
+
160
+ self.thread = QThread()
161
+ self.worker = WorkerProcessData()
162
+
163
+ self.b_val = (246, 653, 440)
164
+ self.l_val = (244, 442, 464)
165
+ self.vox_size = 39.0625
166
+
167
+ self.finish = [False, False, False, False]
168
+ self.process_finished = False
169
+ self.download_threads = {}
170
+ self.download_errors = {}
171
+
172
+ self.label_bar = QProgressBar()
173
+ self.label_bar.setMinimumWidth(400)
174
+ self.label_bar.setValue(0)
175
+
176
+ self.data_bar = QProgressBar()
177
+ self.data_bar.setMinimumWidth(400)
178
+ self.data_bar.setValue(0)
179
+
180
+ self.mask_bar = QProgressBar()
181
+ self.mask_bar.setMinimumWidth(400)
182
+ self.mask_bar.setValue(0)
183
+
184
+ self.segmentation_bar = QProgressBar()
185
+ self.segmentation_bar.setMinimumWidth(400)
186
+ self.segmentation_bar.setValue(0)
187
+
188
+ self.download_btn = QPushButton()
189
+ self.download_btn. setMinimumWidth(100)
190
+ self.download_btn.setText("Download")
191
+
192
+ self.process_btn = QPushButton()
193
+ self.process_btn.setMinimumWidth(100)
194
+ self.process_btn.setText("Process")
195
+
196
+ self.process_label = QLabel()
197
+ self.process_label.setMinimumWidth(100)
198
+ self.process_label.setText("")
199
+
200
+ self.progress = QProgressBar(self)
201
+ self.progress.setMinimumWidth(100)
202
+
203
+ self.process_info = QLabel('The whole process takes around 40 min - 1 hour. \n'
204
+ 'This window will be closed automatically when processing finished.\n')
205
+
206
+ # ok button, used to close window
207
+ ok_btn = QDialogButtonBox(QDialogButtonBox.StandardButton.Ok)
208
+ ok_btn.accepted.connect(self.accept)
209
+
210
+ layout.addWidget(self.label_bar)
211
+ layout.addWidget(self.data_bar)
212
+ layout.addWidget(self.mask_bar)
213
+ layout.addWidget(self.segmentation_bar)
214
+ layout.addWidget(self.download_btn)
215
+ layout.addWidget(self.process_info)
216
+ layout.addWidget(self.process_btn)
217
+ layout.addWidget(self.progress)
218
+ layout.addWidget(self.process_label)
219
+ # layout.addWidget(ok_btn)
220
+
221
+ # Binding Button Event
222
+ self.download_btn.clicked.connect(self.download_start)
223
+ self.process_btn.clicked.connect(self.process_start)
224
+
225
+ # Download button event
226
+ def download_start(self):
227
+ self.saving_folder = str(QFileDialog.getExistingDirectory(self, "Select Folder to Save Atlas"))
228
+
229
+ if self.saving_folder != '':
230
+ self.download_btn.setVisible(False)
231
+ target = os.path.join(self.saving_folder, 'atlas_labels.pkl')
232
+ if not os.path.exists(target):
233
+ shutil.copyfile(join(dirname(__file__), "data/atlas_labels.pkl"), target)
234
+
235
+ self.start_thread(self.label_url, self.label_local, self.set_label_bar_value)
236
+ self.start_thread(self.mask_url, self.mask_local, self.set_mask_bar_value)
237
+ self.start_thread(self.segmentation_url, self.segmentation_local, self.set_segmentation_bar_value)
238
+ self.start_thread(self.data_url, self.data_local, self.set_data_bar_value)
239
+
240
+ #
241
+ def start_thread(self, url, local, func):
242
+ destination = os.path.join(self.saving_folder, local)
243
+ self.download_errors.pop(local, None)
244
+ thread = DownloadThread(url, destination, parent=self)
245
+ self.download_threads[local] = thread
246
+ thread.download_process_signal.connect(func)
247
+ thread.download_error_signal.connect(
248
+ lambda message, name=local: self.download_failed(name, message)
249
+ )
250
+ thread.finished.connect(
251
+ lambda name=local: self.download_thread_finished(name)
252
+ )
253
+ thread.start()
254
+
255
+ def download_failed(self, local, message):
256
+ self.download_errors[local] = message
257
+ self.process_info.setText('Download failed for {}: {}'.format(local, message))
258
+
259
+ def download_thread_finished(self, local):
260
+ thread = self.download_threads.pop(local, None)
261
+ if thread is not None:
262
+ thread.deleteLater()
263
+
264
+ def has_active_downloads(self):
265
+ return any(thread.isRunning() for thread in self.download_threads.values())
266
+
267
+ # Setting progress bar
268
+ def set_label_bar_value(self, value):
269
+ self.label_bar.setValue(value)
270
+ if value == 100:
271
+ self.finish[0] = True
272
+ return
273
+
274
+ def set_data_bar_value(self, value):
275
+ self.data_bar.setValue(value)
276
+ if value == 100:
277
+ self.finish[1] = True
278
+ return
279
+
280
+ def set_mask_bar_value(self, value):
281
+ self.mask_bar.setValue(value)
282
+ if value == 100:
283
+ self.finish[2] = True
284
+ return
285
+
286
+ def set_segmentation_bar_value(self, value):
287
+ self.segmentation_bar.setValue(value)
288
+ if value == 100:
289
+ self.finish[3] = True
290
+ return
291
+
292
+ def report_progress(self, i):
293
+ self.progress.setValue(i)
294
+
295
+ def process_start(self):
296
+ if self.has_active_downloads():
297
+ self.process_info.setText('Please wait until all downloads finish.')
298
+ return
299
+ if self.saving_folder is not None:
300
+ saving_folder = self.saving_folder
301
+ else:
302
+ saving_folder = str(QFileDialog.getExistingDirectory(self, "Select Atlas Folder"))
303
+
304
+ if saving_folder != '':
305
+ required_files = (
306
+ self.data_local,
307
+ self.segmentation_local,
308
+ self.mask_local,
309
+ )
310
+ missing_files = [
311
+ name
312
+ for name in required_files
313
+ if not os.path.isfile(os.path.join(saving_folder, name))
314
+ or os.path.getsize(os.path.join(saving_folder, name)) == 0
315
+ ]
316
+ if missing_files:
317
+ self.process_info.setText(
318
+ 'Missing or empty atlas files: {}'.format(', '.join(missing_files))
319
+ )
320
+ return
321
+ self.process_btn.setVisible(False)
322
+ self.worker.set_data(saving_folder, self.data_local, self.segmentation_local, self.mask_local,
323
+ self.b_val, self.l_val, self.vox_size)
324
+ self.worker.moveToThread(self.thread)
325
+ self.thread.started.connect(self.worker.run)
326
+ self.worker.finished.connect(self.on_finish)
327
+ # self.worker.finished.connect(self.worker.deleteLater)
328
+ self.thread.finished.connect(self.thread.deleteLater)
329
+ self.worker.progress.connect(self.report_progress)
330
+ self.thread.start()
331
+
332
+ def on_finish(self):
333
+ self.thread.quit()
334
+ if not self.worker.success:
335
+ self.continue_process = False
336
+ QMessageBox.warning(
337
+ self,
338
+ 'Atlas processing failed',
339
+ self.worker.message or 'Atlas processing did not complete.',
340
+ )
341
+ self.reject()
342
+ return
343
+ self.process_finished = True
344
+ self.continue_process = True
345
+ self.accept()
346
+
347
+ def closeEvent(self, event):
348
+ if self.process_finished:
349
+ event.accept()
350
+ return
351
+ if self.has_active_downloads() or self.thread.isRunning():
352
+ QMessageBox.information(
353
+ self, 'Operation in progress', 'Please wait for the active operation to finish.'
354
+ )
355
+ event.ignore()
356
+ return
357
+ reply = QMessageBox.question(self, 'Message',
358
+ "Do you want to leave?", QMessageBox.StandardButton.Yes, QMessageBox.StandardButton.No)
359
+
360
+ if reply == QMessageBox.StandardButton.Yes:
361
+ self.continue_process = False
362
+ event.accept()
363
+ else:
364
+ event.ignore()
365
+
366
+ # def accept(self) -> None:
367
+ # if self.process_finished:
368
+ # self.close()
369
+ # else:
370
+ # return