Mesh mosaics¶

A mosaic is a custom collection of perspectives for the same scene. With ipyniivue, you use the set_slice_mosaic_string to define each tile for a lightbox view. Note that the load_meshes() command is asynchronous, so we need to use the on_mesh_loaded() to set the mosaic string after the mesh is available.

This Jupyter notebook mirrors the mesh mosaic web page.

Note Atlas slider will require upgrade to NiiVue 0.66

In [1]:
import ipywidgets as widgets
from ipyniivue import NiiVue, SliceType

nv = NiiVue(
    show_3d_crosshair=True,
    back_color=(1, 1, 1, 1),
)

nv.set_slice_type(SliceType.RENDER)
nv.opts.is_colorbar = True
nv.opts.show_legend = False

mesh_layers = [
    {
        "path": "../images/lh.curv",
        "colormap": "gray",
        "cal_min": 0.49,
        "cal_max": 0.51,
        "opacity": 0.5,
    },
    {
        "path": "../images/boggle.lh.annot",
        "opacity": 0.01,
    },
    {
        "path": "../images/boggle.lh.annot",
        "opacity": 0.01,
    },
]

nv.load_meshes(
    [
        {
            "path": "../images/lh.pial",
            "layers": mesh_layers,
        },
    ]
)

kCurvLayer = 0
kAtlasLayer = 1
kStatLayer = 2

@nv.on_mesh_loaded
def on_mesh_loaded(mesh):
    nv.meshes[0].layers[kStatLayer].cal_min = 2.3
    nv.meshes[0].layers[kStatLayer].cal_max = 5
    nv.meshes[0].layers[kStatLayer].colormap = 'warm'
    nv.meshes[0].layers[kStatLayer].colormap_negative = 'winter'
    nv.meshes[0].layers[kStatLayer].atlas_values = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -3, 0, 0, 0, 0, 0, 0, 0, -5, 0, 0, 7, 0, 0, 4, 7, 0, 0, 0, 0, 0, 0, 0]    
    nv.set_mesh_shader(nv.meshes[0].id, "Rim")
    nv.meshes[0].layers[kCurvLayer].colorbar_visible = False
    nv.meshes[0].layers[kAtlasLayer].colorbar_visible = False
    nv.opts.slice_mosaic_string = "A R 0 R -0 S R 0 R -0 C R 0 R -0" 

nv.set_clip_plane(-0.1, 270, 0)

## User interface widgets

curv_slider = widgets.IntSlider(
    value=50,
    min=1,
    max=99,
    description="Curvature",
    readout=False
)

def on_curv_change(change):
    """Set curve transparency."""
    nv.set_mesh_layer_property(
        mesh_id=nv.meshes[0].id,
        layer_index=kCurvLayer,
        attribute="opacity",
        value=change["new"] * 0.01,
    )

curv_slider.observe(on_curv_change, names="value")

atlas_slider = widgets.IntSlider(
    value=1,
    min=1,
    max=99,
    description="Atlas",
    readout=False
)

def on_atlas_change(change):
    """Set atlas transparency."""
    nv.set_mesh_layer_property(
        mesh_id=nv.meshes[0].id,
        layer_index=kAtlasLayer,
        attribute="opacity",
        value=change["new"] * 0.01,
    )

atlas_slider.observe(on_atlas_change, names="value")

stat_slider = widgets.IntSlider(
    value=1,
    min=1,
    max=99,
    description="Stats",
    readout=False
)

def on_stat_change(change):
    """Set stat transparency."""
    nv.set_mesh_layer_property(
        mesh_id=nv.meshes[0].id,
        layer_index=kStatLayer,
        attribute="opacity",
        value=change["new"] * 0.01,
    )

stat_slider.observe(on_stat_change, names="value")

border_options = ["Dark border", "Transparent border", "No border", "Opaque border"]
border_dropdown = widgets.Dropdown(
    options=border_options,
    value="No border",
    description="Border",
)

def on_border_change(change):
    """Set mesh border style."""
    value_name = change["new"]

    # Default borderValue for "No border"
    borderValue = 0.0

    if value_name == "Dark border":
        borderValue = -0.01  # MRIcroGL convention: negative = dark border
    elif value_name == "Transparent border":
        borderValue = 0.01   # small positive = transparent border
    elif value_name == "Opaque border":
        borderValue = 1.0    # fully opaque border
    # else "No border" → 0.0

    # Apply to the mesh layer (assuming kAtlasLayer is defined elsewhere)
    nv.set_mesh_layer_property(nv.meshes[0].id, kAtlasLayer, "outline_border", borderValue)
    

border_dropdown.observe(on_border_change, names="value")

widgets.VBox(
    [
        widgets.HBox([curv_slider, stat_slider, border_dropdown]),
        nv,
    ]
)
Out[1]:
In [ ]: