unveil-python 0.0.2__tar.gz → 0.1.0__tar.gz
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.
- {unveil_python-0.0.2/src/unveil_python.egg-info → unveil_python-0.1.0}/PKG-INFO +14 -1
- unveil_python-0.1.0/README.md +15 -0
- {unveil_python-0.0.2 → unveil_python-0.1.0}/pyproject.toml +3 -1
- {unveil_python-0.0.2 → unveil_python-0.1.0}/src/unveil/__init__.py +1 -1
- {unveil_python-0.0.2 → unveil_python-0.1.0}/src/unveil/core.py +181 -53
- {unveil_python-0.0.2 → unveil_python-0.1.0/src/unveil_python.egg-info}/PKG-INFO +14 -1
- {unveil_python-0.0.2 → unveil_python-0.1.0}/src/unveil_python.egg-info/requires.txt +1 -0
- unveil_python-0.0.2/README.md +0 -4
- {unveil_python-0.0.2 → unveil_python-0.1.0}/LICENSE +0 -0
- {unveil_python-0.0.2 → unveil_python-0.1.0}/setup.cfg +0 -0
- {unveil_python-0.0.2 → unveil_python-0.1.0}/src/unveil/__main__.py +0 -0
- {unveil_python-0.0.2 → unveil_python-0.1.0}/src/unveil_python.egg-info/SOURCES.txt +0 -0
- {unveil_python-0.0.2 → unveil_python-0.1.0}/src/unveil_python.egg-info/dependency_links.txt +0 -0
- {unveil_python-0.0.2 → unveil_python-0.1.0}/src/unveil_python.egg-info/top_level.txt +0 -0
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: unveil-python
|
|
3
|
-
Version: 0.0
|
|
3
|
+
Version: 0.1.0
|
|
4
4
|
Summary: Implementation of UNVEIL
|
|
5
5
|
Author-email: Nicolas Delinte <nicolas.delinte@uclouvain.be>
|
|
6
|
+
License-Expression: GPL-3.0-only
|
|
6
7
|
Project-URL: GitHub, https://github.com/DelinteNicolas/UNVEIL
|
|
7
8
|
Keywords: tractography,viewer
|
|
8
9
|
Classifier: Intended Audience :: Science/Research
|
|
@@ -12,10 +13,22 @@ Description-Content-Type: text/markdown
|
|
|
12
13
|
License-File: LICENSE
|
|
13
14
|
Requires-Dist: dipy
|
|
14
15
|
Requires-Dist: pyvista
|
|
16
|
+
Requires-Dist: pyvistaqt
|
|
15
17
|
Requires-Dist: PyQt6
|
|
16
18
|
Dynamic: license-file
|
|
17
19
|
|
|
18
20
|
# UNVEIL
|
|
21
|
+
[](https://pypi.org/project/unveil-python/)
|
|
22
|
+
[](https://pypi.org/project/unveil-python/)
|
|
23
|
+

|
|
24
|
+
|
|
25
|
+
|
|
19
26
|
A simple tractography viewer implemented in python.
|
|
20
27
|
|
|
21
28
|

|
|
29
|
+
|
|
30
|
+
The GUI is launched with the following python command:
|
|
31
|
+
|
|
32
|
+
```
|
|
33
|
+
import unveil.__main__
|
|
34
|
+
```
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# UNVEIL
|
|
2
|
+
[](https://pypi.org/project/unveil-python/)
|
|
3
|
+
[](https://pypi.org/project/unveil-python/)
|
|
4
|
+

|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
A simple tractography viewer implemented in python.
|
|
8
|
+
|
|
9
|
+

|
|
10
|
+
|
|
11
|
+
The GUI is launched with the following python command:
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
import unveil.__main__
|
|
15
|
+
```
|
|
@@ -9,6 +9,7 @@ authors = [
|
|
|
9
9
|
]
|
|
10
10
|
readme="README.md"
|
|
11
11
|
description = "Implementation of UNVEIL"
|
|
12
|
+
license = "GPL-3.0-only"
|
|
12
13
|
keywords = ["tractography", "viewer"]
|
|
13
14
|
classifiers = ['Intended Audience :: Science/Research',
|
|
14
15
|
'Natural Language :: English',
|
|
@@ -16,6 +17,7 @@ classifiers = ['Intended Audience :: Science/Research',
|
|
|
16
17
|
]
|
|
17
18
|
dependencies = ['dipy',
|
|
18
19
|
'pyvista',
|
|
20
|
+
'pyvistaqt',
|
|
19
21
|
'PyQt6'
|
|
20
22
|
]
|
|
21
23
|
dynamic = ["version"]
|
|
@@ -27,4 +29,4 @@ version = {attr = "unveil.__version__"}
|
|
|
27
29
|
"GitHub" = "https://github.com/DelinteNicolas/UNVEIL"
|
|
28
30
|
|
|
29
31
|
[tool.setuptools.packages.find]
|
|
30
|
-
where = ["src"]
|
|
32
|
+
where = ["src"]
|
|
@@ -4,7 +4,6 @@ Created on Tue Mar 4 13:03:28 2025
|
|
|
4
4
|
|
|
5
5
|
@author: nicol
|
|
6
6
|
"""
|
|
7
|
-
|
|
8
7
|
import sys
|
|
9
8
|
import numpy as np
|
|
10
9
|
import nibabel as nib
|
|
@@ -22,9 +21,52 @@ from matplotlib.colors import LinearSegmentedColormap
|
|
|
22
21
|
# from unravel.viz import plot_trk # We'll use our local version below
|
|
23
22
|
|
|
24
23
|
|
|
24
|
+
def gifti_to_pyvista(gii_path):
|
|
25
|
+
"""
|
|
26
|
+
Load a GIFTI surface and transform coordinates into voxel space
|
|
27
|
+
using the inverse of the given NIfTI affine.
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
# Affine from MNI152 1mm template (voxel→world)
|
|
31
|
+
affine = np.array([
|
|
32
|
+
[-1.0, 0.0, 0.0, 90.0],
|
|
33
|
+
[0.0, 1.0, 0.0, -126.0],
|
|
34
|
+
[0.0, 0.0, 1.0, -72.0],
|
|
35
|
+
[0.0, 0.0, 0.0, 1.0]
|
|
36
|
+
])
|
|
37
|
+
|
|
38
|
+
# Compute inverse to go from world (mm) → voxel coordinates
|
|
39
|
+
inv_affine = np.linalg.inv(affine)
|
|
40
|
+
|
|
41
|
+
# Load GIFTI file
|
|
42
|
+
img = nib.load(gii_path)
|
|
43
|
+
coords_list = img.get_arrays_from_intent('NIFTI_INTENT_POINTSET')
|
|
44
|
+
face_list = img.get_arrays_from_intent('NIFTI_INTENT_TRIANGLE')
|
|
45
|
+
|
|
46
|
+
if len(coords_list) == 0 or len(face_list) == 0:
|
|
47
|
+
raise RuntimeError(
|
|
48
|
+
"Could not find POINTSET or TRIANGLE arrays in GIFTI file.")
|
|
49
|
+
|
|
50
|
+
# Extract data
|
|
51
|
+
coords_world = coords_list[0].data.astype(np.float32)
|
|
52
|
+
faces = face_list[0].data.astype(np.int32)
|
|
53
|
+
|
|
54
|
+
# Transform to voxel space
|
|
55
|
+
coords_voxel = nib.affines.apply_affine(inv_affine, coords_world)
|
|
56
|
+
|
|
57
|
+
# Build PyVista face array (VTK expects [3, i1, i2, i3, 3, ...])
|
|
58
|
+
faces_pv = np.hstack(
|
|
59
|
+
(np.full((faces.shape[0], 1), 3, dtype=np.int32), faces)).astype(np.int32)
|
|
60
|
+
|
|
61
|
+
# Create PolyData mesh in voxel space
|
|
62
|
+
mesh = pv.PolyData(coords_voxel, faces_pv)
|
|
63
|
+
|
|
64
|
+
return mesh
|
|
65
|
+
|
|
66
|
+
|
|
25
67
|
def plot_trk(trk_file, scalar=None, color_map='plasma', opacity: float = 1,
|
|
26
68
|
show_points: bool = False, background: str = 'black', plotter=None,
|
|
27
|
-
name=None):
|
|
69
|
+
name=None, reset_camera=False):
|
|
28
70
|
'''
|
|
29
71
|
3D render for .trk files.
|
|
30
72
|
|
|
@@ -114,18 +156,21 @@ def plot_trk(trk_file, scalar=None, color_map='plasma', opacity: float = 1,
|
|
|
114
156
|
p.add_mesh(mesh, ambient=ambient, opacity=opacity, diffuse=diffuse,
|
|
115
157
|
interpolate_before_map=False, render_lines_as_tubes=True,
|
|
116
158
|
line_width=2, point_size=point_size, rgb=rgb,
|
|
117
|
-
cmap=color_map, clim=color_lim, scalars=scalars, name=name
|
|
159
|
+
cmap=color_map, clim=color_lim, scalars=scalars, name=name,
|
|
160
|
+
reset_camera=reset_camera)
|
|
118
161
|
|
|
119
162
|
elif color_map == 'flesh':
|
|
120
163
|
p.add_mesh(mesh, opacity=opacity, diffuse=0.4, ambient=ambient,
|
|
121
164
|
interpolate_before_map=False, render_lines_as_tubes=True,
|
|
122
165
|
line_width=2, point_size=point_size, rgb=rgb,
|
|
123
|
-
color=[250, 225, 210], name=name
|
|
166
|
+
color=[250, 225, 210], name=name,
|
|
167
|
+
reset_camera=reset_camera)
|
|
124
168
|
else:
|
|
125
169
|
p.add_mesh(mesh, opacity=opacity, diffuse=diffuse, ambient=ambient,
|
|
126
170
|
interpolate_before_map=False, render_lines_as_tubes=True,
|
|
127
171
|
line_width=2, point_size=point_size, rgb=rgb,
|
|
128
|
-
cmap=color_map, scalars=scalars, name=name
|
|
172
|
+
cmap=color_map, scalars=scalars, name=name,
|
|
173
|
+
reset_camera=reset_camera)
|
|
129
174
|
|
|
130
175
|
p.background_color = background
|
|
131
176
|
# Do not call p.show() here when using an embedded interactor
|
|
@@ -147,14 +192,38 @@ class TrkViewer(QWidget):
|
|
|
147
192
|
self.background = 'white'
|
|
148
193
|
|
|
149
194
|
def initUI(self):
|
|
150
|
-
# Create the main
|
|
151
|
-
|
|
195
|
+
# Create the main layout
|
|
196
|
+
global_layout = QVBoxLayout(self)
|
|
197
|
+
|
|
198
|
+
# Camera toolbar (buttons for orientation)
|
|
199
|
+
camera_label = QLabel('Camera: ')
|
|
200
|
+
cam_layout = QHBoxLayout()
|
|
201
|
+
btn_iso = QPushButton("Isometric")
|
|
202
|
+
btn_xy = QPushButton("Axe 1")
|
|
203
|
+
btn_xz = QPushButton("Axe 2")
|
|
204
|
+
btn_yz = QPushButton("Axe 3")
|
|
205
|
+
btn_iso.clicked.connect(self.view_isometric)
|
|
206
|
+
btn_xy.clicked.connect(self.view_xy)
|
|
207
|
+
btn_xz.clicked.connect(self.view_xz)
|
|
208
|
+
btn_yz.clicked.connect(self.view_yz)
|
|
209
|
+
cam_layout.addWidget(camera_label)
|
|
210
|
+
cam_layout.addWidget(btn_iso)
|
|
211
|
+
cam_layout.addWidget(btn_xy)
|
|
212
|
+
cam_layout.addWidget(btn_xz)
|
|
213
|
+
cam_layout.addWidget(btn_yz)
|
|
214
|
+
btn_screenshot = QPushButton("Screenshot")
|
|
215
|
+
btn_screenshot.clicked.connect(self.take_screenshot)
|
|
216
|
+
cam_layout.addWidget(btn_screenshot)
|
|
217
|
+
|
|
218
|
+
global_layout.addLayout(cam_layout)
|
|
219
|
+
|
|
220
|
+
main_layout = QHBoxLayout()
|
|
221
|
+
global_layout.addLayout(main_layout)
|
|
152
222
|
|
|
153
223
|
# Left side: Control panel
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
# control_layout.addWidget(self.loadButton)
|
|
224
|
+
control_widget = QWidget()
|
|
225
|
+
control_layout = QVBoxLayout(control_widget)
|
|
226
|
+
control_widget.setMaximumWidth(250)
|
|
158
227
|
|
|
159
228
|
self.opacityLabel = QLabel('Opacity:')
|
|
160
229
|
control_layout.addWidget(self.opacityLabel)
|
|
@@ -188,6 +257,13 @@ class TrkViewer(QWidget):
|
|
|
188
257
|
self.showVolumeCheckbox.stateChanged.connect(self.update_nii_viewer)
|
|
189
258
|
control_layout.addWidget(self.showVolumeCheckbox)
|
|
190
259
|
|
|
260
|
+
self.nii_opacitySlider = QSlider(Qt.Orientation.Horizontal, self)
|
|
261
|
+
self.nii_opacitySlider.setMinimum(0)
|
|
262
|
+
self.nii_opacitySlider.setMaximum(1000)
|
|
263
|
+
self.nii_opacitySlider.setValue(45)
|
|
264
|
+
self.nii_opacitySlider.sliderReleased.connect(self.update_nii_viewer)
|
|
265
|
+
control_layout.addWidget(self.nii_opacitySlider)
|
|
266
|
+
|
|
191
267
|
self.showSlicesCheckbox = QCheckBox('Show Slices')
|
|
192
268
|
self.showSlicesCheckbox.stateChanged.connect(self.update_nii_viewer)
|
|
193
269
|
control_layout.addWidget(self.showSlicesCheckbox)
|
|
@@ -220,18 +296,26 @@ class TrkViewer(QWidget):
|
|
|
220
296
|
self.ZSlider.sliderReleased.connect(self._update_nii_z)
|
|
221
297
|
control_layout.addWidget(self.ZSlider)
|
|
222
298
|
|
|
223
|
-
#
|
|
224
|
-
|
|
225
|
-
|
|
299
|
+
# Gifti
|
|
300
|
+
self.showSurfaceCheckbox = QCheckBox('Show Surface')
|
|
301
|
+
self.showSurfaceCheckbox.stateChanged.connect(self.update_gii_viewer)
|
|
302
|
+
control_layout.addWidget(self.showSurfaceCheckbox)
|
|
303
|
+
|
|
304
|
+
self.gii_opacitySlider = QSlider(Qt.Orientation.Horizontal, self)
|
|
305
|
+
self.gii_opacitySlider.setMinimum(0)
|
|
306
|
+
self.gii_opacitySlider.setMaximum(100)
|
|
307
|
+
self.gii_opacitySlider.setValue(15)
|
|
308
|
+
self.gii_opacitySlider.sliderReleased.connect(self.update_gii_viewer)
|
|
309
|
+
control_layout.addWidget(self.gii_opacitySlider)
|
|
226
310
|
|
|
227
311
|
# Add the control panel layout to the main layout
|
|
228
|
-
main_layout.
|
|
312
|
+
main_layout.addWidget(control_widget)
|
|
229
313
|
|
|
230
314
|
# Right side: PyVista viewer embedded in the GUI using QtInteractor
|
|
231
315
|
self.plotter = QtInteractor(self)
|
|
232
316
|
main_layout.addWidget(self.plotter.interactor)
|
|
233
317
|
|
|
234
|
-
self.setLayout(
|
|
318
|
+
self.setLayout(global_layout)
|
|
235
319
|
self.setWindowTitle("Tractography Viewer")
|
|
236
320
|
|
|
237
321
|
def loadTrkFile(self):
|
|
@@ -244,7 +328,7 @@ class TrkViewer(QWidget):
|
|
|
244
328
|
self.names.append(self.trk_file)
|
|
245
329
|
self.selected_name = self.trk_file
|
|
246
330
|
|
|
247
|
-
self.update_trk_viewer()
|
|
331
|
+
self.update_trk_viewer(reset_camera=True)
|
|
248
332
|
|
|
249
333
|
def loadNiftiFile(self):
|
|
250
334
|
options = QFileDialog.Options()
|
|
@@ -253,9 +337,13 @@ class TrkViewer(QWidget):
|
|
|
253
337
|
if filePath:
|
|
254
338
|
self.nii_file = filePath
|
|
255
339
|
print(f"Loaded NIfTI file: {self.nii_file}")
|
|
256
|
-
|
|
340
|
+
img = nib.load(filePath)
|
|
341
|
+
self.nii_data = img.get_fdata()
|
|
257
342
|
grid = pv.ImageData()
|
|
258
343
|
grid.dimensions = np.array(self.nii_data.shape) + 1
|
|
344
|
+
# World coordinates
|
|
345
|
+
# grid.origin = img.affine[:3, 3]
|
|
346
|
+
# grid.spacing = np.diag(img.affine)[:3]
|
|
259
347
|
grid.cell_data['values'] = self.nii_data.flatten(order='F')
|
|
260
348
|
self.grid = grid
|
|
261
349
|
|
|
@@ -263,7 +351,18 @@ class TrkViewer(QWidget):
|
|
|
263
351
|
self.YSlider.setMaximum(self.nii_data.shape[1])
|
|
264
352
|
self.ZSlider.setMaximum(self.nii_data.shape[2])
|
|
265
353
|
|
|
266
|
-
self.update_nii_viewer()
|
|
354
|
+
self.update_nii_viewer(reset_camera=True)
|
|
355
|
+
|
|
356
|
+
def loadGiftiFile(self):
|
|
357
|
+
options = QFileDialog.Options()
|
|
358
|
+
filePath, _ = QFileDialog.getOpenFileName(
|
|
359
|
+
self, "Open .gii File", "", "Gifti Files (*.gii)", options=options)
|
|
360
|
+
if filePath:
|
|
361
|
+
self.gii_file = filePath
|
|
362
|
+
print(f"Loaded GIfTI file: {self.gii_file}")
|
|
363
|
+
self.gii_mesh = gifti_to_pyvista(filePath)
|
|
364
|
+
|
|
365
|
+
self.update_gii_viewer(reset_camera=True)
|
|
267
366
|
|
|
268
367
|
def set_background_color(self):
|
|
269
368
|
|
|
@@ -274,7 +373,40 @@ class TrkViewer(QWidget):
|
|
|
274
373
|
|
|
275
374
|
self.plotter.background_color = self.background
|
|
276
375
|
|
|
277
|
-
def
|
|
376
|
+
def view_isometric(self):
|
|
377
|
+
# equivalent to BackgroundPlotter 'iso' camera position
|
|
378
|
+
self.plotter.view_isometric()
|
|
379
|
+
self.plotter.render()
|
|
380
|
+
|
|
381
|
+
def view_xy(self):
|
|
382
|
+
# view from +Z axis, XY plane (axial)
|
|
383
|
+
self.plotter.view_xy() # pyvista method
|
|
384
|
+
self.plotter.render()
|
|
385
|
+
|
|
386
|
+
def view_xz(self):
|
|
387
|
+
# view from +Y axis, XZ plane (sagittal)
|
|
388
|
+
self.plotter.view_xz()
|
|
389
|
+
self.plotter.render()
|
|
390
|
+
|
|
391
|
+
def view_yz(self):
|
|
392
|
+
# view from +X axis, YZ plane (coronal)
|
|
393
|
+
self.plotter.view_yz()
|
|
394
|
+
self.plotter.render()
|
|
395
|
+
|
|
396
|
+
def take_screenshot(self):
|
|
397
|
+
"""Take a screenshot of the current 3D view."""
|
|
398
|
+
options = QFileDialog.Options()
|
|
399
|
+
file_path, _ = QFileDialog.getSaveFileName(
|
|
400
|
+
self,
|
|
401
|
+
"Save Screenshot",
|
|
402
|
+
"",
|
|
403
|
+
"PNG Image (*.png);;JPEG Image (*.jpg);;TIFF Image (*.tif)",
|
|
404
|
+
options=options
|
|
405
|
+
)
|
|
406
|
+
if file_path:
|
|
407
|
+
self.plotter.screenshot(file_path, transparent_background=True)
|
|
408
|
+
|
|
409
|
+
def update_trk_viewer(self, reset_camera=False):
|
|
278
410
|
|
|
279
411
|
opacity = self.opacitySlider.value() / 100.0
|
|
280
412
|
show_points = self.showPointsCheckbox.isChecked()
|
|
@@ -294,7 +426,8 @@ class TrkViewer(QWidget):
|
|
|
294
426
|
|
|
295
427
|
plot_trk(file, opacity=opacity, plotter=self.plotter, scalar=scalar,
|
|
296
428
|
show_points=show_points, color_map=color_map,
|
|
297
|
-
name=file, background=self.background
|
|
429
|
+
name=file, background=self.background,
|
|
430
|
+
reset_camera=reset_camera)
|
|
298
431
|
|
|
299
432
|
def _update_nii_x(self):
|
|
300
433
|
|
|
@@ -307,7 +440,8 @@ class TrkViewer(QWidget):
|
|
|
307
440
|
slice_x = self.grid.slice('x', center)
|
|
308
441
|
self.plotter.add_mesh(slice_x, cmap='grey', name='nii_x',
|
|
309
442
|
show_scalar_bar=False, point_size=0,
|
|
310
|
-
render_lines_as_tubes=True
|
|
443
|
+
render_lines_as_tubes=True,
|
|
444
|
+
reset_camera=False)
|
|
311
445
|
else:
|
|
312
446
|
self.plotter.remove_actor('nii_x')
|
|
313
447
|
|
|
@@ -322,7 +456,8 @@ class TrkViewer(QWidget):
|
|
|
322
456
|
slice_y = self.grid.slice('y', center)
|
|
323
457
|
self.plotter.add_mesh(slice_y, cmap='grey', name='nii_y',
|
|
324
458
|
show_scalar_bar=False, point_size=0,
|
|
325
|
-
render_lines_as_tubes=True
|
|
459
|
+
render_lines_as_tubes=True,
|
|
460
|
+
reset_camera=False)
|
|
326
461
|
else:
|
|
327
462
|
self.plotter.remove_actor('nii_y')
|
|
328
463
|
|
|
@@ -334,21 +469,18 @@ class TrkViewer(QWidget):
|
|
|
334
469
|
self.YSlider.value(), self.ZSlider.value())
|
|
335
470
|
|
|
336
471
|
if self.showZCheckbox.isChecked():
|
|
337
|
-
z_val = self.ZSlider.value()
|
|
338
472
|
slice_z = self.grid.slice('z', center)
|
|
339
473
|
self.plotter.add_mesh(slice_z, cmap='grey', name='nii_z',
|
|
340
474
|
show_scalar_bar=False, point_size=0,
|
|
341
|
-
render_lines_as_tubes=True
|
|
475
|
+
render_lines_as_tubes=True,
|
|
476
|
+
reset_camera=False)
|
|
342
477
|
else:
|
|
343
478
|
self.plotter.remove_actor('nii_z')
|
|
344
479
|
|
|
345
|
-
def update_nii_viewer(self):
|
|
480
|
+
def update_nii_viewer(self, reset_camera=False):
|
|
346
481
|
|
|
347
482
|
if self.showSlicesCheckbox.isChecked():
|
|
348
483
|
|
|
349
|
-
center = (self.XSlider.value(),
|
|
350
|
-
self.YSlider.value(), self.ZSlider.value())
|
|
351
|
-
|
|
352
484
|
self._update_nii_x()
|
|
353
485
|
self._update_nii_y()
|
|
354
486
|
self._update_nii_z()
|
|
@@ -359,34 +491,25 @@ class TrkViewer(QWidget):
|
|
|
359
491
|
self.plotter.remove_actor('nii_z')
|
|
360
492
|
|
|
361
493
|
if self.showVolumeCheckbox.isChecked():
|
|
362
|
-
|
|
363
|
-
self.plotter.add_volume(self.grid, cmap='gray', opacity=[0
|
|
364
|
-
show_scalar_bar=False, name='nii_volume'
|
|
494
|
+
opacity = self.nii_opacitySlider.value()/1000
|
|
495
|
+
self.plotter.add_volume(self.grid, cmap='gray', opacity=[0, opacity],
|
|
496
|
+
show_scalar_bar=False, name='nii_volume',
|
|
497
|
+
reset_camera=reset_camera)
|
|
365
498
|
else:
|
|
366
|
-
self.plotter.remove_actor('nii_volume')
|
|
367
|
-
|
|
368
|
-
def viewPlot(self):
|
|
369
|
-
|
|
370
|
-
# Clear previous meshes if necessary
|
|
371
|
-
self.plotter.clear()
|
|
372
|
-
|
|
373
|
-
if self.nii_data is not None and self.grid is not None:
|
|
374
|
-
# Add a slice of the NIfTI volume to the scene
|
|
375
|
-
# self.plotter.add_mesh_slice(self.grid, cmap='gray',
|
|
376
|
-
# show_scalar_bar=False)
|
|
499
|
+
self.plotter.remove_actor('nii_volume', reset_camera=reset_camera)
|
|
377
500
|
|
|
378
|
-
|
|
379
|
-
# show_scalar_bar=False,
|
|
380
|
-
# tubing=False)
|
|
501
|
+
def update_gii_viewer(self, reset_camera=False):
|
|
381
502
|
|
|
382
|
-
|
|
503
|
+
if self.showSurfaceCheckbox.isChecked():
|
|
383
504
|
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
505
|
+
opacity = self.gii_opacitySlider.value()/100
|
|
506
|
+
self.plotter.add_mesh(self.gii_mesh, color="ghostwhite",
|
|
507
|
+
culling='front', smooth_shading=True,
|
|
508
|
+
opacity=opacity, name='gii_surface',
|
|
509
|
+
reset_camera=reset_camera)
|
|
510
|
+
else:
|
|
511
|
+
# self.plotter.remove_actor('gii_surface', reset_camera=reset_camera)
|
|
512
|
+
self.plotter.actors['gii_surface'].visibility = False
|
|
390
513
|
|
|
391
514
|
|
|
392
515
|
class MainWindow(QMainWindow):
|
|
@@ -413,6 +536,11 @@ class MainWindow(QMainWindow):
|
|
|
413
536
|
loadNiftiAction.triggered.connect(self.viewer.loadNiftiFile)
|
|
414
537
|
fileMenu.addAction(loadNiftiAction)
|
|
415
538
|
|
|
539
|
+
# Action to load .gii file
|
|
540
|
+
loadGiftiAction = QAction('Load .gii File', self)
|
|
541
|
+
loadGiftiAction.triggered.connect(self.viewer.loadGiftiFile)
|
|
542
|
+
fileMenu.addAction(loadGiftiAction)
|
|
543
|
+
|
|
416
544
|
# Optional: Exit action
|
|
417
545
|
exitAction = QAction('Exit', self)
|
|
418
546
|
exitAction.triggered.connect(self.close)
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: unveil-python
|
|
3
|
-
Version: 0.0
|
|
3
|
+
Version: 0.1.0
|
|
4
4
|
Summary: Implementation of UNVEIL
|
|
5
5
|
Author-email: Nicolas Delinte <nicolas.delinte@uclouvain.be>
|
|
6
|
+
License-Expression: GPL-3.0-only
|
|
6
7
|
Project-URL: GitHub, https://github.com/DelinteNicolas/UNVEIL
|
|
7
8
|
Keywords: tractography,viewer
|
|
8
9
|
Classifier: Intended Audience :: Science/Research
|
|
@@ -12,10 +13,22 @@ Description-Content-Type: text/markdown
|
|
|
12
13
|
License-File: LICENSE
|
|
13
14
|
Requires-Dist: dipy
|
|
14
15
|
Requires-Dist: pyvista
|
|
16
|
+
Requires-Dist: pyvistaqt
|
|
15
17
|
Requires-Dist: PyQt6
|
|
16
18
|
Dynamic: license-file
|
|
17
19
|
|
|
18
20
|
# UNVEIL
|
|
21
|
+
[](https://pypi.org/project/unveil-python/)
|
|
22
|
+
[](https://pypi.org/project/unveil-python/)
|
|
23
|
+

|
|
24
|
+
|
|
25
|
+
|
|
19
26
|
A simple tractography viewer implemented in python.
|
|
20
27
|
|
|
21
28
|

|
|
29
|
+
|
|
30
|
+
The GUI is launched with the following python command:
|
|
31
|
+
|
|
32
|
+
```
|
|
33
|
+
import unveil.__main__
|
|
34
|
+
```
|
unveil_python-0.0.2/README.md
DELETED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|