Voxel-based diffusion metrics¶

Many voxel-based metrics can be derived from diffusion weighted imaging, including fractional anisotropy (FA) and the direction of the principal vector (V1). This notebook illustrates methods for viewing these modalities. While the images here are from FSL, you can also load voxel-based images from other tools including AFNI, MRtrix and DSI-studio. This notebook mirrors the NiiVue dti web page.

TODO: ipyniivue does not yet support isForceMouseClickToVoxelCenters

In [1]:
from ipyniivue import NiiVue, ShowRender
import ipywidgets as widgets
from IPython.display import display

nv = NiiVue(
    back_color=(1, 1, 1, 1),
    show_3d_crosshair=True,
    multiplanar_show_render=ShowRender.ALWAYS,
    height=1024
)

nv.load_volumes([
        {'path': '../images/FA.nii.gz' },
        {'path': '../images/V1.nii.gz', 'opacity': 1 }
    ])
nv.volumes[0].colorbar_visible = False
nv.opts.is_alpha_clip_dark = True
nv.set_crosshair_width(0.1)
nv.is_force_mouse_click_to_voxel_centers = True

## create widgets

# modulate_options = nv.mesh_shader_names()
modulate_options = {"FA", "V1", "V1xFA", "Lines", "LinesxFA"}


modulate_dropdown = widgets.Dropdown(
    options=modulate_options,
    value="V1",  # Default shader
    description="Shader:",
)


def on_modulate_change(change):
    """Set modulation."""
    new_value = change["new"]
    nv.volumes[0].opacity = 1.0
    nv.volumes[1].opacity = 1.0
    nv.set_modulation_image(nv.volumes[1].id, '')
    nv.opts.is_v1_slice_shader = False
    match new_value:
        case "FA":
            nv.volumes[1].opacity = 0.0      
        case "V1":
            nv.volumes[0].opacity = 0.0
            # nv.volumes[1].opacity = 1.0
        case "V1xFA":
            nv.set_modulation_image(nv.volumes[1].id,nv.volumes[0].id)
        case "Lines":
            nv.opts.is_v1_slice_shader = True
        case "LinesxFA":
            nv.opts.is_v1_slice_shader = True
            nv.set_modulation_image(nv.volumes[1].id,nv.volumes[0].id)
        case _:
            print(f"Unknown shader option: {new_value}")

modulate_dropdown.observe(on_modulate_change, names="value")

dark_check = widgets.Checkbox(value=True, description="Clip Dark")

def on_dark_check_change(change):
    """Recreate nv with new anti_alias setting and re-apply settings."""
    nv.opts.is_alpha_clip_dark = change["new"]

dark_check.observe(on_dark_check_change, names="value")

@nv.on_image_loaded
def on_image_loaded(volume):
    """Handle event after volume is loaded and ready."""
    modulate_dropdown.value = "LinesxFA"
    nv.move_crosshair_in_vox(0, 0, 0)

## Display

controls = widgets.HBox([modulate_dropdown, dark_check])

## Show widgets and view

display(controls)
display(nv)
In [ ]:
 
In [ ]: