Skip to content

Zarr Viewer

py
r"""
Installation requirements:
    pip install trame trame-vuetify trame-vtk
"""

from trame.app import get_server
from trame.widgets import html, vuetify, vtk as vtk_widgets
from trame.ui.vuetify import SinglePageLayout

from vtkContourGeneratorFromZarr import vtkContourGeneratorFromZarr

from vtkmodules.vtkRenderingCore import (
    vtkActor,
    vtkPolyDataMapper,
    vtkRenderer,
    vtkRenderWindow,
    vtkRenderWindowInteractor,
)

from vtkmodules.vtkInteractionStyle import vtkInteractorStyleSwitch  # noqa
import vtkmodules.vtkRenderingOpenGL2  # noqa

# -----------------------------------------------------------------------------
# Trame setup
# -----------------------------------------------------------------------------

server = get_server(client_type="vue2")
state, ctrl = server.state, server.controller

# -----------------------------------------------------------------------------
# set up class to process zarr
# -----------------------------------------------------------------------------

DEFAULT_LEVEL = 3

server.cli.add_argument("--data", help="directory to zarr files", dest="data")
args = server.cli.parse_args()
skin_generator = vtkContourGeneratorFromZarr(args.data)
skin_generator.contourForLevel(DEFAULT_LEVEL)

MAX_LEVEL = skin_generator.getMaxLevel()

# -----------------------------------------------------------------------------
# VTK pipeline
# -----------------------------------------------------------------------------

renderer = vtkRenderer()
renderWindow = vtkRenderWindow()
renderWindow.AddRenderer(renderer)

renderWindowInteractor = vtkRenderWindowInteractor()
renderWindowInteractor.SetRenderWindow(renderWindow)
renderWindowInteractor.GetInteractorStyle().SetCurrentStyleToTrackballCamera()

mapper = vtkPolyDataMapper()
mapper.SetInputConnection(skin_generator.getContour().GetOutputPort())
actor = vtkActor()
actor.SetMapper(mapper)

renderer.AddActor(actor)
renderer.ResetCamera()
renderWindow.Render()

# -----------------------------------------------------------------------------
# Callbacks
# -----------------------------------------------------------------------------

state.points = 0
state.cells = 0
state.level = DEFAULT_LEVEL


@state.change("level")
def update_skin(level=DEFAULT_LEVEL, **kwargs):
    nb_points, nb_cells = skin_generator.contourForLevel(level)
    state.points = nb_points
    state.cells = nb_cells
    ctrl.view_update()


def update_reset_level():
    state.level = DEFAULT_LEVEL


def increase_level():
    if state.level < MAX_LEVEL:
        state.level += 1


def decrease_level():
    if 1 < state.level:
        state.level -= 1


# -----------------------------------------------------------------------------
# GUI
# -----------------------------------------------------------------------------

state.trame__title = "Zarr Skin Generator Demo"


with SinglePageLayout(server) as layout:
    layout.icon.click = "$refs.view.resetCamera()"
    layout.title.set_text("Skin Generator")
    with layout.toolbar:
        vuetify.VSpacer()
        vuetify.VBtn(
            vuetify.VIcon("mdi-minus"),
            x_small=True,
            icon=True,
            outlined=True,
            click=decrease_level,
            classes="mx-2",
        )
        vuetify.VBtn(
            vuetify.VIcon("mdi-plus"),
            x_small=True,
            icon=True,
            outlined=True,
            click=increase_level,
            classes="mx-2",
        )
        html.Div(
            "Level({{ level }}) - Points({{parseInt( points ).toLocaleString()}}) - Cells({{parseInt( cells ).toLocaleString()}})",
            style="min-width: 350px; text-align: right;",
        )
        vuetify.VDivider(vertical=True, classes="mx-2"),
        vuetify.VBtn(
            icon=True,
            click=update_reset_level,
            children=[vuetify.VIcon("mdi-undo-variant")],
        )

    with layout.content:
        with vuetify.VContainer(
            fluid=True,
            classes="pa-0 fill-height",
        ):
            html_view = vtk_widgets.VtkRemoteView(renderWindow, ref="view")
            ctrl.view_update = html_view.update
            ctrl.view_reset_camera = html_view.reset_camera

# -----------------------------------------------------------------------------
# Main
# -----------------------------------------------------------------------------

if __name__ == "__main__":
    server.start()
r"""
Installation requirements:
    pip install trame trame-vuetify trame-vtk
"""

from trame.app import get_server
from trame.widgets import html, vuetify, vtk as vtk_widgets
from trame.ui.vuetify import SinglePageLayout

from vtkContourGeneratorFromZarr import vtkContourGeneratorFromZarr

from vtkmodules.vtkRenderingCore import (
    vtkActor,
    vtkPolyDataMapper,
    vtkRenderer,
    vtkRenderWindow,
    vtkRenderWindowInteractor,
)

from vtkmodules.vtkInteractionStyle import vtkInteractorStyleSwitch  # noqa
import vtkmodules.vtkRenderingOpenGL2  # noqa

# -----------------------------------------------------------------------------
# Trame setup
# -----------------------------------------------------------------------------

server = get_server(client_type="vue2")
state, ctrl = server.state, server.controller

# -----------------------------------------------------------------------------
# set up class to process zarr
# -----------------------------------------------------------------------------

DEFAULT_LEVEL = 3

server.cli.add_argument("--data", help="directory to zarr files", dest="data")
args = server.cli.parse_args()
skin_generator = vtkContourGeneratorFromZarr(args.data)
skin_generator.contourForLevel(DEFAULT_LEVEL)

MAX_LEVEL = skin_generator.getMaxLevel()

# -----------------------------------------------------------------------------
# VTK pipeline
# -----------------------------------------------------------------------------

renderer = vtkRenderer()
renderWindow = vtkRenderWindow()
renderWindow.AddRenderer(renderer)

renderWindowInteractor = vtkRenderWindowInteractor()
renderWindowInteractor.SetRenderWindow(renderWindow)
renderWindowInteractor.GetInteractorStyle().SetCurrentStyleToTrackballCamera()

mapper = vtkPolyDataMapper()
mapper.SetInputConnection(skin_generator.getContour().GetOutputPort())
actor = vtkActor()
actor.SetMapper(mapper)

renderer.AddActor(actor)
renderer.ResetCamera()
renderWindow.Render()

# -----------------------------------------------------------------------------
# Callbacks
# -----------------------------------------------------------------------------

state.points = 0
state.cells = 0
state.level = DEFAULT_LEVEL


@state.change("level")
def update_skin(level=DEFAULT_LEVEL, **kwargs):
    nb_points, nb_cells = skin_generator.contourForLevel(level)
    state.points = nb_points
    state.cells = nb_cells
    ctrl.view_update()


def update_reset_level():
    state.level = DEFAULT_LEVEL


def increase_level():
    if state.level < MAX_LEVEL:
        state.level += 1


def decrease_level():
    if 1 < state.level:
        state.level -= 1


# -----------------------------------------------------------------------------
# GUI
# -----------------------------------------------------------------------------

state.trame__title = "Zarr Skin Generator Demo"


with SinglePageLayout(server) as layout:
    layout.icon.click = "$refs.view.resetCamera()"
    layout.title.set_text("Skin Generator")
    with layout.toolbar:
        vuetify.VSpacer()
        vuetify.VBtn(
            vuetify.VIcon("mdi-minus"),
            x_small=True,
            icon=True,
            outlined=True,
            click=decrease_level,
            classes="mx-2",
        )
        vuetify.VBtn(
            vuetify.VIcon("mdi-plus"),
            x_small=True,
            icon=True,
            outlined=True,
            click=increase_level,
            classes="mx-2",
        )
        html.Div(
            "Level({{ level }}) - Points({{parseInt( points ).toLocaleString()}}) - Cells({{parseInt( cells ).toLocaleString()}})",
            style="min-width: 350px; text-align: right;",
        )
        vuetify.VDivider(vertical=True, classes="mx-2"),
        vuetify.VBtn(
            icon=True,
            click=update_reset_level,
            children=[vuetify.VIcon("mdi-undo-variant")],
        )

    with layout.content:
        with vuetify.VContainer(
            fluid=True,
            classes="pa-0 fill-height",
        ):
            html_view = vtk_widgets.VtkRemoteView(renderWindow, ref="view")
            ctrl.view_update = html_view.update
            ctrl.view_reset_camera = html_view.reset_camera

# -----------------------------------------------------------------------------
# Main
# -----------------------------------------------------------------------------

if __name__ == "__main__":
    server.start()
py
import os, sys
import zarr

import vtk
from vtk.util import numpy_support as np_s


class vtkContourGeneratorFromZarr(object):
    def __init__(self, basepath):
        self.zarrPath = os.path.normpath(basepath)
        if not os.path.exists(self.zarrPath):
            print(f"Path ({self.zarrPath}) is not valid")
            sys.exit(1)

        # set up zarr stuff
        self.zarrStore = zarr.open(self.zarrPath, mode="r")
        self.multiscales = self.zarrStore.attrs["multiscales"][0]
        self.datasets = self.multiscales["datasets"]
        self.root = self.zarrStore["/"]
        self.maxLevel = len(self.datasets) - 1

        self.contour = vtk.vtkFlyingEdges3D()
        self.contour.ComputeScalarsOff()
        self.contour.ComputeNormalsOn()
        self.contour.ComputeGradientsOff()

    def getVolume(self, scale, dataset):
        origin = self.getScaleOrigin(scale)
        spacing = self.getScaleSpacing(scale)

        path = dataset["path"]
        dims = self.root[path].attrs["_ARRAY_DIMENSIONS"]
        shape = self.root[path].shape
        xIdx = dims.index("x")
        yIdx = dims.index("y")
        zIdx = dims.index("z")

        ds = vtk.vtkImageData()
        ds.SetOrigin(origin)
        ds.SetSpacing(spacing)
        ds.SetDimensions(shape[xIdx], shape[yIdx], shape[zIdx])

        array = np_s.numpy_to_vtk(self.root[path][:].flatten())
        array.SetName("Content")
        ds.GetPointData().SetScalars(array)

        return ds

    def getMaxLevel(self):
        return self.maxLevel

    def getScaleOrigin(self, scale):
        origin = [0.0, 0.0, 0.0]
        origin[0] = self.root[str(scale) + "/x"][0]
        origin[1] = self.root[str(scale) + "/y"][0]
        origin[2] = self.root[str(scale) + "/z"][0]
        return origin

    def getScaleSpacing(self, scale):
        spacing = [0.0, 0.0, 0.0]
        spacing[0] = self.root[str(scale) + "/x"][1] - self.root[str(scale) + "/x"][0]
        spacing[1] = self.root[str(scale) + "/y"][1] - self.root[str(scale) + "/y"][0]
        spacing[2] = self.root[str(scale) + "/z"][1] - self.root[str(scale) + "/z"][0]
        return spacing

    def contourForLevel(self, level, contours=[1]):
        # Update contours values
        ctrIdx = 0
        self.contour.SetNumberOfContours(len(contours))
        for value in contours:
            self.contour.SetValue(ctrIdx, value)
            ctrIdx += 1

        if level > self.maxLevel:
            print(f"level {level} > max level {self.maxLevel}")

        volume = self.getVolume(level, self.datasets[level])
        self.contour.SetInputData(volume)
        self.contour.Update()

        _ds = self.contour.GetOutput()
        nb_points = _ds.GetNumberOfPoints()
        nb_cells = _ds.GetNumberOfCells()
        return nb_points, nb_cells

    def getContour(self):
        return self.contour
import os, sys
import zarr

import vtk
from vtk.util import numpy_support as np_s


class vtkContourGeneratorFromZarr(object):
    def __init__(self, basepath):
        self.zarrPath = os.path.normpath(basepath)
        if not os.path.exists(self.zarrPath):
            print(f"Path ({self.zarrPath}) is not valid")
            sys.exit(1)

        # set up zarr stuff
        self.zarrStore = zarr.open(self.zarrPath, mode="r")
        self.multiscales = self.zarrStore.attrs["multiscales"][0]
        self.datasets = self.multiscales["datasets"]
        self.root = self.zarrStore["/"]
        self.maxLevel = len(self.datasets) - 1

        self.contour = vtk.vtkFlyingEdges3D()
        self.contour.ComputeScalarsOff()
        self.contour.ComputeNormalsOn()
        self.contour.ComputeGradientsOff()

    def getVolume(self, scale, dataset):
        origin = self.getScaleOrigin(scale)
        spacing = self.getScaleSpacing(scale)

        path = dataset["path"]
        dims = self.root[path].attrs["_ARRAY_DIMENSIONS"]
        shape = self.root[path].shape
        xIdx = dims.index("x")
        yIdx = dims.index("y")
        zIdx = dims.index("z")

        ds = vtk.vtkImageData()
        ds.SetOrigin(origin)
        ds.SetSpacing(spacing)
        ds.SetDimensions(shape[xIdx], shape[yIdx], shape[zIdx])

        array = np_s.numpy_to_vtk(self.root[path][:].flatten())
        array.SetName("Content")
        ds.GetPointData().SetScalars(array)

        return ds

    def getMaxLevel(self):
        return self.maxLevel

    def getScaleOrigin(self, scale):
        origin = [0.0, 0.0, 0.0]
        origin[0] = self.root[str(scale) + "/x"][0]
        origin[1] = self.root[str(scale) + "/y"][0]
        origin[2] = self.root[str(scale) + "/z"][0]
        return origin

    def getScaleSpacing(self, scale):
        spacing = [0.0, 0.0, 0.0]
        spacing[0] = self.root[str(scale) + "/x"][1] - self.root[str(scale) + "/x"][0]
        spacing[1] = self.root[str(scale) + "/y"][1] - self.root[str(scale) + "/y"][0]
        spacing[2] = self.root[str(scale) + "/z"][1] - self.root[str(scale) + "/z"][0]
        return spacing

    def contourForLevel(self, level, contours=[1]):
        # Update contours values
        ctrIdx = 0
        self.contour.SetNumberOfContours(len(contours))
        for value in contours:
            self.contour.SetValue(ctrIdx, value)
            ctrIdx += 1

        if level > self.maxLevel:
            print(f"level {level} > max level {self.maxLevel}")

        volume = self.getVolume(level, self.datasets[level])
        self.contour.SetInputData(volume)
        self.contour.Update()

        _ds = self.contour.GetOutput()
        nb_points = _ds.GetNumberOfPoints()
        nb_cells = _ds.GetNumberOfCells()
        return nb_points, nb_cells

    def getContour(self):
        return self.contour