Last active
January 17, 2024 14:48
-
-
Save MarilynKeller/2835d1d2f13a3e113b011f7b1f7a9e88 to your computer and use it in GitHub Desktop.
Pyvista wrapper functions
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import pyvista as pv | |
from pyvista import examples | |
import data_mri as dd | |
import numpy as np | |
def plot_3D_image(arr, resolution, center, p=None, interactive_slice=False, orthogonal_slices=True): | |
''' Plot of a 3D volume with orthogonal slices slices.''' | |
values = arr | |
values.shape | |
# Create the spatial reference | |
grid = pv.UniformGrid() | |
# Set the grid dimensions: shape + 1 because we want to inject our values on | |
# the CELL data | |
grid.dimensions = np.array(values.shape) + 1 | |
# Edit the spatial reference | |
# The bottom left corner of the data set | |
print(f'WARNING: a MRI can have different resolutions per slice. Here we plot with the same resolution for all slices \ | |
otherwise we cant plot the a grid of voxels. See point clouds for correct visualisation') | |
origin = np.array(resolution[0]) * np.array(arr.shape) * 0.5 | |
grid.origin = origin | |
print(f'Scan size in meter: {origin*2}') | |
grid.spacing = resolution[0] # These are the cell sizes along each axis | |
# Add the data values to the cell data | |
grid.cell_arrays["values"] = values.flatten(order="F") # Flatten the array! | |
if p is None: | |
p = pv.Plotter() | |
p.show_grid() | |
if orthogonal_slices: | |
slices = grid.slice_orthogonal() | |
p.add_mesh(slices) | |
if interactive_slice: | |
p.add_mesh_clip_plane(grid) | |
return p | |
def plot_mesh(mesh_path, is_pc=False, p=None, scale_factor=1e3): | |
''' | |
:param mesh_path: string giving the path to the mesh to load. Most common formats are supported | |
:param is_pc: If True, show the mesh as a point cloud | |
:param p: Existing pyvista plotter to plot to. One will be created if set to None. | |
:param scale_factor: To scale the mesh | |
:return: p Plotter containing the mesh | |
''' | |
mesh = pv.read(mesh_path) | |
if p==None: | |
p = pv.Plotter() | |
if is_pc: | |
mesh = pv.PolyData(mesh.points/scale_factor) | |
# mesh.plot(render_points_as_spheres=True) | |
p.add_mesh(mesh, render_points_as_spheres=True, color='red') | |
else: | |
p.add_mesh(mesh, render_points_as_spheres=True) | |
p.show_grid() | |
return | |
def plotly_volume(arr): | |
""" Not sure what this does anymore. Feel free to try X) """ | |
import time | |
import numpy as np | |
from skimage import io | |
# vol = io.imread("https://s3.amazonaws.com/assets.datacamp.com/blog_assets/attention-mri.tif") | |
vol = arr | |
volume = vol.T | |
r, c = volume[0].shape | |
# Define frames | |
import plotly.graph_objects as go | |
nb_frames = 68 | |
fig = go.Figure(frames=[go.Frame(data=go.Surface( | |
z=(6.7 - k * 0.1) * np.ones((r, c)), | |
surfacecolor=np.flipud(volume[67 - k]), | |
cmin=0, cmax=1 | |
), | |
name=str(k) # you need to name the frame for the animation to behave properly | |
) | |
for k in range(nb_frames)]) | |
# Add data to be displayed before animation starts | |
fig.add_trace(go.Surface( | |
z=6.7 * np.ones((r, c)), | |
surfacecolor=np.flipud(volume[67]), | |
colorscale='Gray', | |
cmin=0, cmax=1, | |
colorbar=dict(thickness=20, ticklen=4) | |
)) | |
def frame_args(duration): | |
return { | |
"frame": {"duration": duration}, | |
"mode": "immediate", | |
"fromcurrent": True, | |
"transition": {"duration": duration, "easing": "linear"}, | |
} | |
sliders = [ | |
{ | |
"pad": {"b": 10, "t": 60}, | |
"len": 0.9, | |
"x": 0.1, | |
"y": 0, | |
"steps": [ | |
{ | |
"args": [[f.name], frame_args(0)], | |
"label": str(k), | |
"method": "animate", | |
} | |
for k, f in enumerate(fig.frames) | |
], | |
} | |
] | |
# Layout | |
fig.update_layout( | |
title='Slices in volumetric data', | |
width=600, | |
height=600, | |
scene=dict( | |
zaxis=dict(range=[-0.1, 6.8], autorange=False), | |
aspectratio=dict(x=1, y=1, z=1), | |
), | |
updatemenus=[ | |
{ | |
"buttons": [ | |
{ | |
"args": [None, frame_args(50)], | |
"label": "▶", # play symbol | |
"method": "animate", | |
}, | |
{ | |
"args": [[None], frame_args(0)], | |
"label": "◼", # pause symbol | |
"method": "animate", | |
}, | |
], | |
"direction": "left", | |
"pad": {"r": 10, "t": 70}, | |
"type": "buttons", | |
"x": 0.1, | |
"y": 0, | |
} | |
], | |
sliders=sliders | |
) | |
fig.show() | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment