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