module GraphKit::VTK

This module contains methods for rendering GraphKits using the Visualization Toolkit (VTK). It uses the Python interface to VTK via the RubyPython bridge (see rubygems.org/gems/rubypython).

It should work with vtk and vtk-python installed on any Linux distro.

If you want to use it on a supercomputer you will almost certainly have to build Python and VTK yourself.

The instructions below have been tested on Hector but can be easily adapted to work anywhere.

First you need to configure your system to use the GNU compilers and with dynamic linking enabled. The instructions for configuring your system for installing CodeRunner should work well. See the CodeRunner wiki (coderunner.sourceforge.net).

Choose a directory to install everything: myprefix.

Download the source for Python 2.x (2.7 works as of Dec 2012), extract it and build it (with shared libraries) as follows.

$ cd Python-2.7.3
$ ./configure  --prefix=<myprefix> --enable-shared LDFLAGS="-Wl,-rpath <myprefix/lib"
$ make && make install

Download the VTK source (tested with VTK 5.10) and extract it.

Make a directory at the same level as the VTK source folder, e.g. VTK-bin. Make sure CMake is available (e.g. module load CMake). Configure like this:

1. $ cd VTK-bin
2. $ ccmake -i ../VTK5.10.1   # (replace with appropriate folder)

You will now enter the CMake interactive configuration. Press ‘c’ to run the initial configuration. Press ‘t’ to get to the advanced options. Make sure the settings below are as follows

CMAKE_INSTALL_PREFIX <myprefix>
VTK_WRAP_PYTHON on
        VTK_USE_RENDERING on
VTK_USE_X off
        VTK_OPENGL_HAS_OSMESA on

The last two settings mean that VTK won't try to pop up windows when 
it is rendering: instead it will write them straight to file. 
OSMESA stands for Off Screen Mesa, where Mesa is the open source
graphics library. 

Press 'c' to update the configuration. 
Now update the following settings:
        PYTHON_EXECUTABLE <myprefix>/bin/python
        PYTHON_INCLUDE_DIR <myprefix>/include/python2.x
        PYTHON_LIBRARY <myprefix>/lib/libpython2.x.so
        VTK_USE_OFFSCREEN on

Here is the funky bit: we don’t want to use the standard hardware-enabled OpenGL libraries because we want to render offscreen. The standard OpenGL conflicts with OSMESA and makes SEGFAULTS (yuk). Instead we can have OSMESA replace all their functionality by setting

OPENGL_glu_LIBRARY
OPENGL_gl_LIBRARY

to the same value as

OSMESA_LIBRARY

This will of course not be as fast, but that’s OK because we are going to parallelise over the supercomputer when we write our rendering scripts!

Press ‘c’ to configure once more, and ‘g’ to generate the makefiles. Now build

$ make     # This will take about 40 mins.
$ make install

Finally we need to setup python: add these lines to your .bashrc

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:<myprefix>/lib/vtk-5.10/
export PYTHONPATH=$PYTHONPATH:<myprefix>/lib/python2.7/site-packages/
export PATH=<myprefix>/bin:$PATH

Public Instance Methods

vtk_object_group(filename = nil) click to toggle source

This method returns a VTKObjectGroup object, which contains references to the VTK/Python objects which are necessary to plot the graph.

# File lib/graphkit-vtk.rb, line 146
def vtk_object_group(filename = nil)
        # If we are not given a filename, need to write the
        # data in VTK format... can change at some point?
        temp_write = false
        unless filename
                temp_write = true
                filename = (Time.now.to_i).to_s +  $$.to_s + rand(1000000).to_s + ".tmp.vtk"
                to_vtk_legacy_fast(file_name: filename)
        end

        vtk_og = VTKObjectGroup.new
        vtk  = vtk_og.vtk_module = RubyPython.import('vtk')
        file_name = filename

        vtk_og.reader = reader = vtk.vtkUnstructuredGridReader
        reader.SetFileName(file_name)
        reader.Update

        if temp_write
                FileUtils.rm(filename)
        end

        vtk_og.output = output = reader.GetOutput
        scalar_range = output.GetScalarRange

        vtk_og.mapper = mapper = vtk.vtkDataSetMapper
        mapper.SetInput(output)
        mapper.SetScalarRange(scalar_range)

        look_up_table = vtk.vtkLookupTable
        look_up_table.SetNumberOfColors(64)
        look_up_table.SetHueRange(0.0, 0.667)
        mapper.SetLookupTable(look_up_table)
        mapper.SetScalarModeToDefault
        #mapper.CreateDefaultLookupTable
        mapper.ScalarVisibilityOn
        #mapper.SelectColorArray('myvals')


        vtk_og.actor = actor = vtk.vtkActor
        actor.SetMapper(mapper)
        actor.VisibilityOn

        vtk_og.renderer = renderer = vtk.vtkRenderer
        renderer.AddActor(actor)
        #renderer.SetBackground(0,0,0)

        vtk_og.renderer_window = renderer_window = vtk.vtkRenderWindow
        renderer_window.SetSize(640,480)
        renderer_window.AddRenderer(renderer)

        render_large = vtk_og.large_image_renderer =  vtk.vtkRenderLargeImage
        render_large.SetInput(vtk_og.renderer)
        render_large.SetMagnification(4)

        vtk_og.interactor =  interactor = vtk.vtkRenderWindowInteractor
        interactor.SetRenderWindow(renderer_window)
        interactor.Initialize
        #interactor.Start

        return vtk_og
end
vtk_render(output_file='window', input_file=nil) { |vtk_og| ... } click to toggle source

Visualise the Graph using the Visualization Toolkit (VTK). If output_file is “window”, display it in a window; otherwise, write to the file, e.g. my_graph.jpg, my_graph.gif If input_file is given it sould be a VTK data file. Otherwise it will write the data to a temporary VTK legacy data file.

The optional block yields a VTKObjectGroup which contains references to all the VTK objects for arbitrary manipulation before rendering.

# File lib/graphkit-vtk.rb, line 219
def vtk_render(output_file='window', input_file=nil, &block)
        #RubyPython.start
        vtk_og = vtk_object_group(filename)
        yield(vtk_og) if block
        write_file(output_file, vtk_og)
        #vtk = vtk_og.vtk_module
        ##filter = vtk.vtkWindowToImageFilter
        ##vtk_og.renderer_window.SetOffScreenRendering(1)
        ##gf = vtk.vtkGraphicsFactory
        ##gf.SetOffScreenOnlyMode(1)
        #vtk_og.renderer_window.Start
        ##vtk_og.reader.Update
        ##vtk_og.renderer.Update
        ##filter.SetInput(vtk_og.renderer_window)
        ###########case File.extname(output_file)
        ###########when '.jpeg', '.jpg'
                ###########jpeg_writer = vtk.vtkJPEGWriter
                ############vtk_og.renderer.DeviceRender
                ############jpeg_writer.SetInput(vtk_og.renderer.GetOutput)
                ############jpeg_writer.SetInput(render_large.GetOutput)
                ###########jpeg_writer.SetInput(vtk_og.large_image_renderer.GetOutput)
                ############filter.Update
                ###########jpeg_writer.SetFileName(output_file)
                ###########jpeg_writer.Write
        ###########end
        #vtk_og.renderer_window.Finalize
        #RubyPython.stop

end
vtk_render_volume(output_file='window', function = :raycast, input_file=nil) { |vtk_og| ... } click to toggle source

puts ‘LOADING’

# File lib/graphkit-vtk.rb, line 385
def vtk_render_volume(output_file='window', function = :raycast, input_file=nil, &block)
        puts 'HERE'
        vtk_og = vtk_volume_object_group(function, filename)
        yield(vtk_og) if block
        write_file(output_file, vtk_og)
        #vtk_og.delete
end
vtk_volume_object_group( function = :raycast, filename = nil, options={}) click to toggle source

This method returns a VTKObjectGroup object, which contains references to the VTK/Python objects which are necessary to plot a graph using volume rendering.

function can be :raycast or :tetrahedra

# File lib/graphkit-vtk.rb, line 257
def vtk_volume_object_group( function = :raycast, filename = nil, options={})
        # If we are not given a filename, need to write the
        # data in VTK format... can change at some point?
        temp_write = false
        unless filename
                temp_write = true
                filename = (Time.now.to_i).to_s + $$.to_s + rand(1000000).to_s + ".tmp.vtk"
                to_vtk_legacy_fast(file_name: filename)
        end

        #require 'rubypython'
        #RubyPython.start
        vtk_og = VTKObjectGroup.new
        vtk  = vtk_og.vtk_module = RubyPython.import('vtk')
        file_name = filename

        vtk_og.reader = reader = vtk.vtkUnstructuredGridReader
        reader.SetFileName(file_name)
        reader.Update

        if temp_write
                FileUtils.rm(filename)
        end

        vtk_og.output = output = reader.GetOutput
        ep 'scalar_range', scalar_range = output.GetScalarRange
        #
        
        tf = vtk_og.other_objects[:tetrahedra_filter] = vtk.vtkDataSetTriangleFilter
        tf.SetInput(output)
        

        volprop = vtk_og.other_objects[:volume_property]= vtk.vtkVolumeProperty
        coltranfunc = vtk_og.other_objects[:color_transfer_function] = vtk.vtkColorTransferFunction
        opacfunc = vtk_og.other_objects[:opacity_function] = vtk.vtkPiecewiseFunction

        min, max = scalar_range.to_a
        ep scalar_range.to_a
        max = max.to_s.to_f
        min = min.to_s.to_f
        range = (max-min)
        if options[:cut_range_factor]
        min = min + range/2.0*options[:cut_range_factor]
        max = max - range/2.0*options[:cut_range_factor] 
        end
        ep 'max', max, max.class, 'min', min, min.class

        coltranfunc.AddRGBPoint(min, 0.0, 0.0, 1.0)
        coltranfunc.AddRGBPoint(min + 1.0*(max-min)/5.0, 0.0, 1.0, 1.0)
        coltranfunc.AddRGBPoint(min + 2.0*(max-min)/5.0, 1.0, 0.0, 0.0)
        coltranfunc.AddRGBPoint(min + 3.0*(max-min)/5.0, 1.0, 1.0, 0.0)
        coltranfunc.AddRGBPoint(min + 4.0*(max-min)/5.0, 0.0, 1.0, 0.0)
        coltranfunc.AddRGBPoint(min + 5.0*(max-min)/5.0, 1.0, 1.0, 1.0)

        opacfunc.AddPoint(min, 1)
        opacfunc.AddPoint(max, 1)

        volprop.SetColor(coltranfunc)
        volprop.SetScalarOpacity(opacfunc)


        case function
        when :raycast
                ep "RAYCAST"
                vtk_og.mapper = mapper = vtk.vtkUnstructuredGridVolumeRayCastMapper
                mapper.SetInput(tf.GetOutput)
                mapper.SetRayCastFunction(vtk.vtkUnstructuredGridBunykRayCastFunction)
        when :zsweep
                vtk_og.mapper = mapper = vtk.vtkUnstructuredGridVolumeZSweepMapper
                mapper.SetInput(tf.GetOutput)
                mapper.SetRayIntegrator(vtk.vtkUnstructuredGridHomogeneousRayIntegrator )
        when :tetrahedra
                vtk_og.mapper = mapper = vtk.vtkProjectedTetrahedraMapper
                mapper.SetInput(tf.GetOutput)
                #mapper.SetRayCastFunction(vtk.vtkUnstructuredGridBunykRayCastFunction)
        end
        #mapper.SetScalarRange(scalar_range)

        #look_up_table = vtk.vtkLookupTable
        #look_up_table.SetNumberOfColors(64)
        #look_up_table.SetHueRange(0.0, 0.667)
        #mapper.SetLookupTable(look_up_table)
        mapper.SetScalarModeToDefault
        #mapper.CreateDefaultLookupTable
        #mapper.ScalarVisibilityOn
        #mapper.SelectColorArray('myvals')


        vtk_og.volume = volume = vtk.vtkVolume
        volume.SetMapper(mapper)
        volume.SetProperty(volprop)
        volume.VisibilityOn

        vtk_og.renderer = renderer = vtk.vtkRenderer
        renderer.AddVolume(volume)
        #renderer.SetBackground(0,0,0)

        vtk_og.renderer_window = renderer_window = vtk.vtkRenderWindow
        renderer_window.SetSize(640,480)
        renderer_window.AddRenderer(renderer)

        render_large = vtk_og.large_image_renderer =  vtk.vtkRenderLargeImage
        render_large.SetInput(vtk_og.renderer)
        render_large.SetMagnification(4)

        vtk_og.interactor =  interactor = vtk.vtkRenderWindowInteractor
        interactor.SetRenderWindow(renderer_window)
        interactor.Initialize
        #interactor.Start

        return vtk_og
end
write_file(output_file, vtk_og) click to toggle source
# File lib/graphkit-vtk.rb, line 393
def write_file(output_file, vtk_og)
        vtk = vtk_og.vtk_module
        #filter = vtk.vtkWindowToImageFilter
        #vtk_og.renderer_window.SetOffScreenRendering(1)
        #gf = vtk.vtkGraphicsFactory
        #gf.SetOffScreenOnlyMode(1)
        vtk_og.renderer_window.Start
        #vtk_og.reader.Update
        #vtk_og.renderer.Update
        #filter.SetInput(vtk_og.renderer_window)
        case File.extname(output_file)
        when '.jpeg', '.jpg'
                jpeg_writer = vtk.vtkJPEGWriter
                #vtk_og.renderer.DeviceRender
                #jpeg_writer.SetInput(vtk_og.renderer.GetOutput)
                #jpeg_writer.SetInput(render_large.GetOutput)
                jpeg_writer.SetInput(vtk_og.large_image_renderer.GetOutput)
                #filter.Update
                jpeg_writer.SetFileName(output_file)
                jpeg_writer.Write
        when '.gif'
                gif_writer = vtk.vtkGIFWriter
                gif_writer.SetInput(vtk_og.large_image_renderer.GetOutput)
                gif_writer.SetFileName(output_file)
                gif_writer.Write
        when '.tiff'
                tiff_writer = vtk.vtkTIFFWriter
                tiff_writer.SetInput(vtk_og.large_image_renderer.GetOutput)
                tiff_writer.SetFileName(output_file)
                tiff_writer.Write
        else
                raise 'Cannot write files of this type: ' + output_file
        end
        vtk_og.renderer_window.Finalize
end