Module: GraphKit::VTK

Included in:
GraphKit
Defined in:
lib/graphkit-vtk.rb

Overview

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

Instance Method Summary collapse

Instance Method Details

#vtk_object_group(filename = nil) ⇒ Object

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



146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
# 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| ... } ⇒ Object

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.

Yields:

  • (vtk_og)


219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
# 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| ... } ⇒ Object

puts ‘LOADING’

Yields:

  • (vtk_og)


385
386
387
388
389
390
391
# 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 = {}) ⇒ Object

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



257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
# 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) ⇒ Object



393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
# 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