Improved VTK - numpy integration (part 2)
31 Jul 2014This is my second blog about the recently introduced numpy_interface
module. In the first one, I gave a brief overview of the module and shared a few teasers. In this one, I will go over the dataset_adapter
module which is part of numpy_interface
. This module was designed to simplify accessing VTK datasets and arrays from Python and to provide a numpy-style interface.
The first step to use the dataset_adapter
module is to convert an existing VTK dataset object to a dataset_adapter.VTKObjectWrapper
. Let's see how this is done by examining the teaser from the last blog:
import vtk
from vtk.numpy_interface import dataset_adapter as dsa
s = vtk.vtkSphereSource()
e = vtk.vtkElevationFilter()
e.SetInputConnection(s.GetOutputPort())
e.Update()
sphere = dsa.WrapDataObject(e.GetOutput())
print sphere
print isinstance(sphere, dsa.VTKObjectWrapper)
will print:
<vtk.numpy_interface.dataset_adapter.PolyData object at 0x1101fbb50>
True
What we did here is to create an instance of the dataset_adapter.PolyData
class, which refers to the output of the vtkElevationFilter
filter. We can access the underlying VTK object using the VTKObject
member:
>> print type(sphere.VTKObject)
<type 'vtkobject'>
Note that the WrapDataObject()
function will return an appropriate wrapper class for all vtkDataSet
subclasses, vtkTable
and all vtkCompositeData
subclasses. Other vtkDataObject
subclasses are not currently supported.
VTKObjectWrapper
forwards VTK methods to its VTKObject
so the VTK API can be accessed directy as follows:
>> print sphere.GetNumberOfCells()
96L
However, VTKObjectWrapper
s cannot be directly passed to VTK methods as an argument.
>> s = vtk.vtkShrinkPolyData()
>> s.SetInputData(sphere)
TypeError: SetInputData argument 1: method requires a VTK object
>> s.SetInputData(sphere.VTKObject)
Dataset Attributes
So far, pretty boring, right? We have a wrapper for VTK data objects that partially behaves like a VTK data object. This gets a little bit more interesting when we start looking how one can access the fields (arrays) contained within this dataset.
>> sphere.PointData
<vtk.numpy_interface.dataset_adapter.DataSetAttributes at 0x110f5b750>
>> sphere.PointData.keys()
['Normals', 'Elevation']
>> sphere.CellData.keys()
[]
>> sphere.PointData['Elevation']
VTKArray([ 0.5 , 0. , 0.45048442, 0.3117449 , 0.11126047,
0. , 0. , 0. , 0.45048442, 0.3117449 ,
0.11126047, 0. , 0. , 0. , 0.45048442,
...,
0.11126047, 0. , 0. , 0. , 0.45048442,
0.3117449 , 0.11126047, 0. , 0. , 0. ], dtype=float32)
>> elevation = sphere.PointData['Elevation']
>> elevation[:5]
VTKArray([0.5, 0., 0.45048442, 0.3117449, 0.11126047], dtype=float32)
Note that this works with composite datasets as well:
>> mb = vtk.vtkMultiBlockDataSet()
>> mb.SetNumberOfBlocks(2)
>> mb.SetBlock(0, sphere.VTKObject)
>> mb.SetBlock(1, sphere.VTKObject)
>> mbw = dsa.WrapDataObject(mb)
>> mbw.PointData
<vtk.numpy_interface.dataset_adapter.CompositeDataSetAttributes instance at 0x11109f758>
>> mbw.PointData.keys()
['Normals', 'Elevation']
>> mbw.PointData['Elevation']
<vtk.numpy_interface.dataset_adapter.VTKCompositeDataArray at 0x1110a32d0>
It is possible to access PointData, CellData, FieldData, Points (subclasses of vtkPointSet only), Polygons (vtkPolyData only) this way. We will continue to add accessors to more types of arrays through this API.
This is it for now. In my next blog in this series, I will talk about the array API and various algorithms the numpy_interface
module provides.
Note: This article was originally published on the Kitware blog. Please see the Kitware web site, the VTK web site and the ParaView web site for more information.