Python Programmable Filter

From KitwarePublic
Jump to navigationJump to search

ParaView3's python programmable filter.

The python programmable filter is a general purpose filter that the end user can program within the paraview GUI to manipulate datasets as needed. To use the filter, turn the PARAVIEW_ENABLE_PYTHON_FILTER cmake option on. This causes the make process to wrap paraview's classes into python callable format. The wrapping process is identical to that for the PARAVIEW_EMBED_PYTHON option and the two share the same sets of libraries at run time.

The filter is a wrapper around VTK's vtkProgrammableFilter class and adds to it:

  • a string containing the user's script for the filter to execute
  • an instance of the python interpreter with the wrapped paraview libraries imported
  • the ability to easily change the output dataset type.

When the user selects "PythonScript" from the Filters menu, an empty programmable filter is created. The default behavior of the empty script is create a dataset if the same type as its input and to copy through the input dataset's structure. The GUI provides a selection menu where the user can choose from the five primary vtk dataset types for the output. The GUI also provides a text entry area where the user can type, edit or paste in a python script.

The following figure shows a python script that modifies the geometry of its input dataset. PyScriptFig1.jpg

#reads a poly data and modifies the geometry
pdi = self.GetPolyDataInput()
pdo = self.GetPolyDataOutput()
newPts = paraview.vtkPoints()
numPts = pdi.GetNumberOfPoints()
for i in range(0, numPts):
  coord = pdi.GetPoint(i)
  x,y,z = coord[:3]
  x = x * 2
  y = y * 0.5
  z = 1
  newPts.InsertPoint(i, x,y,z)
pdo.SetPoints(newPts)


The following figure shows a python script that produces an image data output with one cell per point in its input polygonal dataset. PyScriptFig2.jpg

#this example creates an Nx1x1 imagedata output
#and populates its cells with the point centered
#scalars of the input dataset

#get a hold of the input
pdi = self.GetInput()
numPts = pdi.GetNumberOfPoints()

#create the output dataset with one cell per point
ido = self.GetOutput()
ido.SetDimensions(numPts 1,2,2)
ido.SetOrigin(-1,-1,-1)
ido.SetSpacing(.1,.1,.1)
ido.SetWholeExtent(0,numPts,0,1,0,1)
ido.AllocateScalars()

#choose an input point data array to copy
ivals = pdi.GetPointData().GetScalars()
ca = paraview.vtkFloatArray()
ca.SetName(ivals.GetName())
ca.SetNumberOfComponents(1)
ca.SetNumberOfTuples(numPts)
#add the new array to the output
ido.GetCellData().AddArray(ca)

#copy the values over element by element
for i in range(0, numPts):
  ca.SetValue(i, ivals.GetValue(i))


The following is a 'Programmable Source' example that generates a Helix curve. HelixExample.jpg

#This script generates a helix curve.
#This is intended as the script of a 'Programmable Source'
import math

numPts = 80.0 # Points along Helix
length = 8.0 # Length of Helix
rounds = 3.0 # Number of times around

#Get a paraview.vtk.PolyData object for the output
pdo = self.GetPolyDataOutput()

#This will store the points for the Helix
newPts = paraview.vtkPoints()
for i in range(0, numPts):
   #Generate the Points along the Helix
   x = i*length/numPts
   y = math.sin(i*rounds*2*math.pi/numPts)
   z = math.cos(i*rounds*2*math.pi/numPts)
   #Insert the Points into the vtkPoints object
   #The first parameter indicates the reference.
   #value for the point. Here we add the sequentially.
   #Note that the first point is at index 0 (not 1).
   newPts.InsertPoint(i, x,y,z)

#Add the points to the vtkPolyData object
#Right now the points are not associated with a line - 
#it is just a set of unconnected points. We need to
#create a 'cell' object that ties points together
#to make, in this case, a curve. This is done below.
#A 'cell' is just an object that tell how points are
#connected to make a 1D, 2D, or 3D object.
pdo.SetPoints(newPts)

#Make a vtkPolyLine which holds the info necessary
#to create a curve composed of line segments. This
#really just hold constructor data that will be passed
#to vtkPolyData to add a new line.
aPolyLine = paraview.vtkPolyLine()

#Indicate the number of points along the line
aPolyLine.GetPointIds().SetNumberOfIds(numPts)
for i in range(0,numPts):
   #Add the points to the line. The first value indicates
   #the order of the point on the line. The second value
   #is a reference to a point in a vtkPoints object. Depends
   #on the order that Points were added to vtkPoints object.
   #Note that this will not be associated with actual points
   #until it is added to a vtkPolyData object which holds a
   #vtkPoints object.
   aPolyLine.GetPointIds().SetId(i, i)

#Allocate the number of 'cells' that will be added. We are just
#adding one vtkPolyLine 'cell' to the vtkPolyData object.
pdo.Allocate(1, 1)

#Add the poly line 'cell' to the vtkPolyData object.
pdo.InsertNextCell(aPolyLine.GetCellType(), aPolyLine.GetPointIds())

#The Helix is ready to plot! Click 'Apply'.


An example that draws a double helix with connecting lines (like DNA). Provides an example of using multiple drawing objects 'cells' in the same vtkPolyData output object.

#This script generates a helix double.
#This is intended as the script of a 'Programmable Source'
import math

numPts = 80.0 # Points along each Helix
length = 8.0 # Length of each Helix
rounds = 3.0 # Number of times around
phase_shift = math.pi/1.5 # Phase shift between Helixes

#Get a paraview.vtk.PolyData object for the output
pdo = self.GetPolyDataOutput()

#This will store the points for the Helix
newPts = paraview.vtkPoints()
for i in range(0, numPts):
   #Generate Points for first Helix
   x = i*length/numPts
   y = math.sin(i*rounds*2*math.pi/numPts)
   z = math.cos(i*rounds*2*math.pi/numPts)
   newPts.InsertPoint(i, x,y,z)
   
   #Generate Points for second Helix. Add a phase offset to y and z.
   y = math.sin(i*rounds*2*math.pi/numPts+phase_shift)
   z = math.cos(i*rounds*2*math.pi/numPts+phase_shift)
   #Offset Helix 2 pts by 'numPts' to keep separate from Helix 1 Pts
   newPts.InsertPoint(i+numPts, x,y,z)

#Add the points to the vtkPolyData object
pdo.SetPoints(newPts)

#Make two vtkPolyLine objects to hold curve construction data
aPolyLine1 = paraview.vtkPolyLine()
aPolyLine2 = paraview.vtkPolyLine()

#Indicate the number of points along the line
aPolyLine1.GetPointIds().SetNumberOfIds(numPts)
aPolyLine2.GetPointIds().SetNumberOfIds(numPts)
for i in range(0,numPts):
   #First Helix - use the first set of points
   aPolyLine1.GetPointIds().SetId(i, i)
   #Second Helix - use the second set of points
   #(Offset the point reference by 'numPts').
   aPolyLine2.GetPointIds().SetId(i,i+numPts)

#Allocate the number of 'cells' that will be added. 
#Two 'cells' for the Helix curves, and one 'cell'
#for every 3rd point along the Helixes.
links = range(0,numPts,3)
pdo.Allocate(2+len(links), 2+len(links))

#Add the poly line 'cell' to the vtkPolyData object.
pdo.InsertNextCell(aPolyLine1.GetCellType(), aPolyLine1.GetPointIds())
pdo.InsertNextCell(aPolyLine2.GetCellType(), aPolyLine2.GetPointIds())

for i in links:
   #Add a line connecting the two Helixes.
   aLine = paraview.vtkLine()
   aLine.GetPointIds().SetId(0, i)
   aLine.GetPointIds().SetId(1, i+numPts)
   pdo.InsertNextCell(aLine.GetCellType(), aLine.GetPointIds())

Examples

Here are some more examples of simple ParaView 3 python filters.