Monday, February 8, 2010

Dynamic Real-time Data Plotting with VTK

It is possible to interact with a dataset and generate a plot dynamically by probing the dataset. In VTK, you can do this with a few useful classes: vtkLineWidget, vtkSplineWidget, vtkProbeFilter, and vtkXYPlotActor.

Here is video of the dynamic plot in action:



It's impressive but simple. You can expand this capability by adding additional probes and using a spline instead of a line for probing, but to get the functionality you see in the video here's a python script.

The class interactionEvent will be used as a callback function for the lineWidget (or splineWidget):

#!/bin/python

from vtk import *;

#callbacks
class interactionEvent():
        def execute(self, obj, event):
                self.spline.GetPolyData(self.poly)
                self.probe.Update()

This just sets up the pipeline for reading in the dataset and all of the rendering window classes, etc...:

#Read in and set up dataset
reader = vtkDataSetReader()
reader.SetFileName("/Users/brandt/Work/pythonVTK/mummy.128.vtk")
reader.ReadAllScalarsOn()
reader.ReadAllVectorsOn()
reader.Update()

#set up rendering pipeline
renderer = vtkRenderer()
renWin = vtkRenderWindow()
iren = vtkRenderWindowInteractor()
renWin.SetSize(800,480)
renWin.AddRenderer(renderer)
iren.SetRenderWindow(renWin)

Here we set up out vtkXYPlotActor, which just controls how the plot will look:

plotActor = vtkXYPlotActor()
plotActor.SetPosition(0.6,.0)
plotActor.SetWidth(.40)
plotActor.SetHeight(.3)
plotActor.GetXAxisActor2D().SizeFontRelativeToAxisOn()
plotActor.GetYAxisActor2D().SizeFontRelativeToAxisOn()
plotActor.SetNumberOfYLabels(5)
plotActor.SetNumberOfXLabels(6)
plotActor.SetAdjustYLabels(0)
plotActor.SetNumberOfYMinorTicks(2)
plotActor.SetNumberOfXMinorTicks(2)
plotActor.AddInput(probe.GetOutput())
plotActor.SetXValuesToNormalizedArcLength()
plotActor.SetTitle( "Scalar Data" )
plotActor.SetXRange(0,1)

We set up our splineWidget here to probe the data, and add the interactionEvent class as the callback for any interaction event:

poly = vtkPolyData()
probe = vtkProbeFilter()
spline = vtkSplineWidget()
spline.GetPolyData(poly)
probe.SetInput(poly)
probe.SetSource(reader.GetOutput()) 
spline.SetInteractor(iren)
spline.SetInput(reader.GetOutput())
spline.PlaceWidget()
spline.On()
spline.SetNumberOfHandles(2)
probe.Update()
renderer.AddActor(plotActor)

Next we assign our probe, widget, and polydata to the interactionEvent class and add the class as the callback function:

#set up callback
cb = interactionEvent()
cb.spline = spline
cb.probe = probe
cb.poly = poly
spline.AddObserver("InteractionEvent", cb.execute)

Finally we create a contour of the mummy skull so we have something pretty to look at!

#draw contour
isoMapper = vtkPolyDataMapper()
isoActor = vtkActor()
iso = vtkContourFilter()
isoMapper.SetInput(iso.GetOutput())
iso.SetInput(reader.GetOutput())
iso.SetValue(0, 125)
isoActor.SetMapper(isoMapper)
renderer.AddActor(isoActor)

iren.Initialize()
iren.Start()

No comments:

Post a Comment