Interpreted ParaView

The ParaView client provides an easy to use GUI in which to visualize data with the standard window, menu, button controls. Driving ParaView with a mouse is intuitive but not easily reproducible and exact as is required for repetitive analysis and scientific result reproducibility. For this type of work it is much better to use ParaView's scripted interface. This is an an alternative control path, that works alongside of or as a replacement for the GUI.

ParaView's native scripted interface uses the Python programming language. The interface allows one to programatically control ParaView's back end data processing and rendering engines. Note that this level of control is distinct from the Python Programmable Filter discussed in the Quantitative Analysis Chapter. That is a white box filter, that runs in parallel within the server and has direct access to each individual element of the data. Here we are discussing client side python control, where you control the entire pipeline, which may or may not include Python Programmable Filters.

In this chapter we discuss first ParaView's python scripted interface, which follows the same idioms as and thus be operated similarly to the way one works, in the GUI. Next we discuss the ParaView's python tools, which make it even easier to use ParaView python scripts including the ability to record script files from GUI actions and to augment the GUI with them. Lastly we discuss batch processing with ParaView.

Python Scripting

NOTE: This document if based on ParaView 3.6 or higher. If you are using 3.4, go to the history page and select the version from May 13, 2009.

ParaView and Python

ParaView offers rich scripting support through Python. This support is available as part of the ParaView client (paraview), an MPI-enabled batch application (pvbatch), the ParaView python client (pvpython) or any other Python-enabled application. Using Python, users and developers can gain access to the ParaView engine called Server Manager.

Note: Server Manager is a library that is designed to make it easy to build distributed client-server applications.

This document is a short introduction to ParaView's Python interface. You may also visit the Python recipes page for some examples.

Quick Start - a Tutorial

Getting Started

To start interacting with the Server Manager, you have to load the "simple" module. This module can be loaded from any python interpreter as long as the necessary files are in PYTHONPATH. These files are the shared libraries located in the paraview binary directory and python modules in the paraview directory: paraview/simple.py, paraview/vtk.py etc. You can also use either pvpython (for stand-alone or client/server execution), pvbatch (for non-interactive, distributed batch processing) or the python shell invoked from Tools -> Python Shell using the ParaView client to execute Python scripts. You do not have to set PYTHONPATH when using these. In this tutorial, I will be using the python integrated development environment IDLE. My PYTHONPATH is set to the following.

/Users/berk/work/paraview3-build/bin:/Users/berk/work/paraview3-build/Utilities/VTKPythonWrapping/site-packages

Note: This for older versions of ParaView this was /Users/berk/work/paraview3-build/bin:/Users/berk/work/paraview3-build/Utilities/VTKPythonWrapping --Andy.bauer 23 July 2010.

You may also need to set your path variable for searching for shared libraries (i.e. PATH on Windows and LD_LIBRARY_PATH on Unix/Linux/Mac). The corresponding LD_LIBRARY_PATH would be:

/Users/berk/work/paraview3-build/bin



(Under WindowsXP for a debug build of paraview, I set BOTH my PATH and PYTHONPATH environment variables to include ${BUILD}/bin/Debug and ${BUILD}/Utilities/VTKPythonWrapping to make it work. --DaveDemarle 21:09, 29 June 2009 (UTC))

This is on my Mac and using the build tree. In IDLE, let’s start by loading the servermanager module.

>>> from paraview.simple import *

Note: Importing the paraview module directly is deprecated although still possible for backwards compatibility. This document refers to the simple module alone.

In this example, we will use ParaView in the stand-alone mode. Connecting to a ParaView server running on a cluster is covered later in this document.

Creating a Pipeline

The simple module contains many functions to instantiate sources, filters and other related objects. You can get a list of object this module can create from ParaView's online help (from help menu or here: http://paraview.org/OnlineHelpCurrent/)

Let’s start by creating a Cone object:

>>> cone = Cone()

You can get some documentation about the cone object using help().

>>> help(cone)
Help on Cone in module paraview.servermanager object:

class Cone(SourceProxy)
| The Cone source can be used to add a polygonal cone to the 3D scene. The output of the
Cone source is polygonal data.
|
| Method resolution order:
| Cone
| SourceProxy
| Proxy
| __builtin__.object
|
| Methods defined here:
|
| Initialize = aInitialize(self, connection=None)
|
| ----------------------------------------------------------------------
| Data descriptors defined here:
|
| Capping
| If this property is set to 1, the base of the cone will be capped with a filled polygon.
Otherwise, the base of the cone will be open.
|
| Center
| This property specifies the center of the cone.
|
| Direction
| Set the orientation vector of the cone. The vector does not have to be normalized. The cone
will point in the direction specified.
|
| Height
| This property specifies the height of the cone.
|
| Radius
| This property specifies the radius of the base of the cone.
|
| Resolution
| This property indicates the number of divisions around the cone. The higher this number, the
closer the polygonal approximation will come to representing a cone, and the more polygons it will
contain.
|
|...

This gives you a full list of properties. Let’s check what the resolution property is set to.

>>> cone.Resolution
6

You can increase the resolution as shown below.

>>> cone.Resolution = 32

Alternatively, we could have specified a value for resolution when creating the object.

>>> cone = Cone(Resolution=32)

You can assign values to any number of properties during construction using keyword arguments. Let’s also change the center.

>>> cone.Center
[0.0, 0.0, 0.0]
>>> cone.Center = [1, 2, 3]

Vector properties such as this one support setting and getting of individual elements as well as slices (ranges of elements).

>>> cone.Center[0:2] = [2, 4]
>>> cone.Center
[2.0, 4.0, 3.0]

Next, let’s apply a shrink filter to the cone:

>>> shrinkFilter = Shrink(cone)
>>> shrinkFilter.Input
<paraview.servermanager.Cone object at 0xaf701f0>

At this point, if you are interested in getting some information about the output of the shrink filter, you can force it to update (which will also cause the execution of the cone source). For details about VTK's demand-driven pipeline model used by ParaView, see one of the VTK books.

>>> shrinkFilter.UpdatePipeline()
>>> shrinkFilter.GetDataInformation().GetNumberOfCells()
33L
>>> shrinkFilter.GetDataInformation().GetNumberOfPoints()
128L

We will cover the DataInformation class in more detail later.

Rendering

Now that we created a small pipeline, let’s render the result. You will need two objects to render the output of an algorithm in a scene: a representation and a view. A representation is responsible for taking a data object and rendering it in a view. A view is responsible for managing a render context and a collection of representations. Simple creates a view by default. The representation object is created automatically with Show().

>>> Show(shrinkFilter)
>>> Render()

Et voila:

In the example above, we assigned the value returned by Cone() and Shrink() to Python variables and used them to build our pipeline. ParaView keeps track of the last pipeline object created by the user. This allows us to accomplish everything we did above using the following code.

>>> from paraview.simple import *
# Create a cone and assign it as the active object
>>> Cone()
<paraview.servermanager.Cone object at 0x2910f0>
# Set a property of the active object
>>> SetProperties(Resolution=32)
# Apply the shrink filter to the active object
# Shrink is now active
>>> Shrink()
<paraview.servermanager.Shrink object at 0xaf64050>
# Show shrink
>>> Show()
<paraview.servermanager.UnstructuredGridRepresentation object at 0xaf57f90>
# Render the active view
>>> Render()
<paraview.servermanager.RenderView object at 0xaf57ff0>

This was a quick introduction to the paraview.simple module. In the following sections, we will discuss the Python interface in more detail and introduce more advanced concepts.

paraview.simple Module

The simple module is a ParaView component written using Python on top of the Server Manager C++ library. Its purpose is to make it easier to create ParaView data analysis and visualization pipelines using Python. The simple module can be loaded from Python interpreters running in several applications.

Overview

The paraview.simple module contains several Python classes designed to be Python-friendly as well as all classes wrapped from the C++ Server Manager library. The following sections cover the usage of this module and occasionally the paraview.servermanager module which is lower level.

Connecting to a Server

ParaView can run in two modes: stand-alone and client/server where the server is usually a visualization cluster. In this section, we discuss how to establish a connection to a server when using ParaView in the client/server mode. If you are using the ParaView graphical interface, you should use Connect from the File menu to connect to a server. If you are using ParaView from a Python shell (not the Python console that is part of the graphical interface), you need to use servermanager.Connect() to connect a server. Note: you cannot connect to the ParaView application from a stand-alone Python shell. You can only connect to a server. This method takes 4 arguments, all of which have default values.

def Connect(ds_host=None, ds_port=11111, rs_host=None, rs_port=11111)

When connecting to a server (pvserver), specify only the first 2 arguments. These are the server name (or IP address) and port number.

When connecting to a data-server/render-server pair, you have to specify all four arguments. The first 2 are the host name (or IP address) and port number of the data server, the last 2 those of the render server. Here are some examples.

# Connect to pvserver running on amber1 (first node of our test cluster)
# using the default port 11111
>>> Connect(‘amber1’)

# Connect to pvdataserver running on the amber cluster, pvrenderserver
# running on Berk’s desktop
>>> Connect(‘amber1’, 12000, ‘kamino’, 11111)

Note: Connect() will return None on failure. To be safe, you should check the return value of Connect().

Getting Help

You can access the documentation of all Proxy types by using Python's built-in help.

>>> help(paraview.simple.Cone)
Help on function CreateObject in module paraview.simple:

CreateObject(*input, **params)
The Cone source can be used to add a polygonal cone to the 3D scene. The output of the
Cone source is polygonal data.

To get the full documentation, you have to create an instance.

>>> c = Cone()
>>> help(c)

This documentation is automatically generated from the Server Manager configuration files and is identical to the class documentation found under the paraview Help menu as well as here http://paraview.org/OnlineHelpCurrent/. Beyond this document and the online help, there are a few useful documentation sources.

If you are interested in learning more about the Visualization Toolkit that is at the foundation of ParaView, visit http://vtk.org.

Proxies and Properties

Proxies

The VTK Server Manager design uses the Proxy design pattern (See Design Patterns: Elements of Reusable Object-Oriented Software by Erich Gamma, Richard Helm, Ralph Johnson and John Vlissides for details). Quoting from Wikipedia: “A proxy, in its most general form, is a class functioning as an interface to another thing. The other thing could be anything: a network connection, a large object in memory, a file, or some other resource that is expensive or impossible to duplicate”. In the case of Server Manager, a Proxy object acts as a proxy to one or more VTK objects. Most of the time, these are server-side objects and are distributed to the server nodes. Proxy objects allow you to interact with these object as if you directly have access to them, manipulate them and obtain information about them. When creating visualization pipelines, you create proxies instead of VTK objects.

>>> sphereSource = vtk.vtkSphereSource() # VTK-Python script

>>> sphereSourceP = Sphere() # ParaView script

A proxy also provides an interface to modify the properties of the objects it maintains. For example, instead of

>>> sphereSource.SetCenter(1.0, 1.0, 0.0)

you can write the following.

>>> sphere.Center = [1.0, 1.0, 0.0]

When a pipeline object proxy is created, it is set as the active object. You can also set an object as the active one. This is equivalent to clicking on an object in the pipeline browser.

>>> c = Cone()
<paraview.servermanager.Cone object at 0xaf73090>
>>> GetActiveSource()
<paraview.servermanager.Cone object at 0xaf73090>
>>> Shrink()
<paraview.servermanager.Shrink object at 0xb4f8610>
# Make the cone active
>>> SetActiveSource(c)

When dealing with objects created through the graphical interface or by loading a state, it is useful to be able to search through existing pipeline objects. To accomplish this, you can use GetSources() and FindSource(). GetSources() returns a dictionnary of (name, id), object pairs. Since multiple objects can have the same name, the (name,id) pair identifies objects uniquely. FindSource() returns an object given its name. If there are more than one objects with the same name, the first one is returned.

>>> Cone()
<paraview.servermanager.Cone object at 0xaf73090>
>>> GetActiveSource()
<paraview.servermanager.Cone object at 0xaf73090>
>>> Shrink()
<paraview.servermanager.Shrink object at 0xb4f8610>
>>> SetActiveSource(c)

To delete pipeline objects, you need to use the Delete() function. Simple letting a Python variable go out of scope is not enough to delete the object. Following the example above

# Delete the cone source
>>> Delete(c)
# To fully remove the cone from memory, get rid of the
# variable too
>>> del c

Properties

Property objects are used to read and modify the properties of pipeline objects. Each proxy has a list of properties defined in the Server Manager configuration files. The property interface of the Server Manager C++ library is somewhat cumbersome. Here is how you can set the radius property of a sphere source.

>>> rp = sphere.GetProperty("Radius")
>>> rp.SetElement(0, 2)
1
>>> sphere.UpdateProperty("Radius")

The servermanager module makes property access much easier by defining Python property accessors for property objects:

>>> sphere.Radius = 3

Here Radius is a Python property which, when a value is assigned to it, calls sphere.SetPropertyWithName("Radius",3). Properties can also passed to the function creating the object:

>>> cone = Cone(Radius=0.5, Center=[1, 0.5, 0])
<paraview.servermanager.Cone object at 0xaf73090>

You can also use the SetProperties() function to set property values.

>>> SetProperties(cone, Radius=0.2, Center=[2, 0.5, 0])

If the first argument is not specified, the active object is used. You also use SetDisplayProperties() and SetViewProperties() to set display (representation) and view properties respectively.

All Property classes define the following methods.

  • __len__()

  • __getitem__()

  • __setitem__()

  • __getslice__()

  • __setslice__()

  • GetData()

  • SetData().

Therefore, all of the following are supported.

>>> sphere.Center
[0.0, 0.0, 0.0]
>>> sphere.Center[0] = 1
>>> sphere.Center[0:3] = [1,2,3]
>>> sphere.Center[0:3]
[1.0, 2.0, 3.0]
>>> len(sphere.Center)
3

ProxyProperty and InputProperty also define

  • append()

  • __delitem__()

  • __delslice__()

to support del() and append(), similar to Python list objects.

VectorProperty is used for scalars, vectors and lists of integer and floating point numbers as well as strings. Most properties of this type are simple. Examples include Sphere.Radius (double scalar), Sphere.Center (vector of doubles), a2DGlyph.Filled (boolean), a2DGlyph.GlyphType (enumeration), a3DText.Text (string) and Contour.Isosurfaces (list of doubles). Some properties may be more complicated because they map to C++ methods with mixed argument types. Two good examples of this case are Glyph.Scalars and ExodusIIReader.PointVariables.

>>> reader = ExodusIIReader(FileName='.../can.ex2')
# These variables are currently selected
>>> reader.PointVariables
['DISPL', 'VEL', 'ACCL']
# These are available in the file
>>> reader.PointVariables.Available
['DISPL', 'VEL', 'ACCL']
# Enable the DISPL array only
>>> reader.PointVariables = ['DISPL']
# Force read
>>> reader.UpdatePipeline()
# Now check the output. Note: GlobalNodeId is generated automatically by the reader.
>>> reader.PointData[:]
[Array: GlobalNodeId, Array: PedigreeNodeId, Array: DISPL]

This example demonstrates the use of ExodusIIReader.PointVariables. This is a VectorProperty that represents a list of array names. The underlying C++ function has a signature of SetPointResultArrayStatus( const char* name, int flag ). This method is usually called once per array to enable or disable it (i.e. to set whether the reader will read a particular array).

Glyph.Scalars is a bit more complicated. This property allows the developer to select the scalar array with which to scale the glyphs.

>>> sph = Sphere()
>>> elev=Elevation(sph)
# Glyph the points of the sphere with spheres
>>> glyph=Glyph(elev, GlyphType='Sphere')
# Scale the glyph with the Elevation array
>>> glyph.Scalars = 'Elevation'
>>> glyph.Scalars
['POINTS', 'Elevation']
# The above shows the association of the array as well as its name.
# In this case, the array is associated with POINTS as it has to be
# since Glyph cannot scale by cell arrays. We could have done:
>>> glyph.Scalars = ['POINTS', 'Elevation']
# Enable scaling by scalars
>>> glyph.ScaleMode = 'scalar'

Here the property Scalars maps to SetInputArrayToProcess( int idx, int port, int connection, int fieldAssociation, const char *name ) which has four integer arguments (some of which are enumeration) and 1 string argument (see vtkAlgorithm documentation for details).

Properties are either regular (push) or information (pull) properties. Information properties do not have a VTK method associated with them and are responsible for getting information from the server. A good example of an information property is TimestepValues which returns all time steps available in a file (if the reader supports time).

>>> reader = ExodusIIReader(FileName='.../can.ex2')
>>> reader.TimestepValues
[0.0, 0.00010007373930420727, 0.00019990510190837085, 0.00029996439116075635, 0.00040008654468692839,
0.00049991923151537776, 0.00059993512695655227, 0.00070004, ...]

You can obtain a list of properties a proxy supports by using help(). However, this does not allow introspection programmatically. If you need to obtain information about a proxy’s properties programmatically, you can use a property iterator:

>>> for prop in glyph:
print type(prop), prop.GetXMLLabel()

<class 'paraview.servermanager.InputProperty'> Input
<class 'paraview.servermanager.VectorProperty'> Maximum Number of Points
<class 'paraview.servermanager.VectorProperty'> Random Mode
<class 'paraview.servermanager.ArraySelectionProperty'> Scalars
<class 'paraview.servermanager.ArraySelectionProperty'> Vectors
<class 'paraview.servermanager.VectorProperty'> Orient
<class 'paraview.servermanager.VectorProperty'> Set Scale Factor
<class 'paraview.servermanager.EnumerationProperty'> Scale Mode
<class 'paraview.servermanager.InputProperty'> Glyph Type
<class 'paraview.servermanager.VectorProperty'> Mask Points

The XMLLabel is the text display by the graphical user interface. Note that there is a direct mapping from the XMLLabel to the property name. If you remove all spaces from the label, you get the property name. You can use the PropertyIterator object directly.

>>> it = iter(s)
>>> for i in it:
print it.GetKey(), it.GetProperty()

Domains

The Server Manager provides information about values that are valid for properties. The main use of this information is for the user interface to provide good ranges and choices in enumeration. However, some of this information is also very useful for introspection. For example, enumeration properties look like simple integer properties unless a (value, name) pair is associated with them. The Server Manager uses Domain objects to store this information. The contents of domains may be loaded from xml configuration files or computed automatically. Let’s look at an example.

>>> s = Sphere()
>>> Show(s)
>>> dp = GetDisplayProperties(s)
>>> dp.Representation
'Surface'
# The current representation type is Surface. What other types
# are available?
>>> dp.GetProperty("Representation").Available
['Outline', 'Points', 'Wireframe', 'Surface', 'Surface With Edges']
# Choose outline
>>> dp.Representation = 'Outline'

Source Proxies

Source proxies are proxies that represent pipeline objects (For more information about VTK pipelines, see the VTK books: http://vtk.org/buy-books.php''). They have special properties to connect them as well as special method to query the meta-data of their output. To connect a source proxy to another, use one of its input properties.

# Either
>>> glyph = Glyph(elev)
# or
>>> glyph.Input = elev

The SourceProxy class provides several additional properties and methods that are specific to pipelines (See vtkSMSourceProxy documentation for a full list).

  • UpdatePipelineInformation(): This method calls UpdateInformation() on the VTK algorithm. It also calls UpdatePropertyInformation() to update any information properties.

  • UpdatePipeline(): This method calls Update() on the VTK algorithm causing a pipeline execution if the pipeline changed. Another way of causing pipeline updates is to render. The render view updates all connected pipelines.

  • GetDataInformation(): This method is used to obtain meta-data about one output. It is discussed further below.

  • PointData and CellData properties discussed below.



There are two common ways of getting meta-data information from a proxy: information properties and DataInformation. Information properties are updated automatically every time UpdatePropertyInformation() and UpdatePipelineInformation() are called. All you have to do is read the data from the property as usual. To get a DataInformation object from a source proxy use GetDataInformation(port=0). By default, this method returns data information for the first output. You can pass an optional port number to get information for another output. You can get detailed documentation on DataInformation by using help() and by reading online documentation for vtkPVDataInformation (http://www.paraview.org/doc/nightly/html/classvtkPVDataInformation.html''). Here are the use of some common methods.

>>> di = glyph.GetDataInformation(0)
>>> di
<paraview.servermanager.DataInformation object at 0x2d0920d0>
>>> glyph.UpdatePipeline()
# Get the data type.
>>> di.GetDataClassName()
'vtkPolyData'
# Get information about point data.
>>> pdi = di.PointData
# We are now directly accessing the wrapper for a VTK class
>>> len(pdi)
1
# Get information for a point array
>>> ai = pdi[0]
>>> ai.GetRange(0)
(0.0, 0.5)

When meta-data is not enough and you need access to the raw data, you can use Fetch() to bring it to the client side. Note that this function is provided by the servermanager module. Fetch() has three modes:

  • Append all of the data together and bring it to the client (only available for polygonal and unstructured datasets). Note: Do not do this if data is large otherwise the client will run out of memory.

  • Bring data from a given process to the client.

  • Use a reduction algorithm and bring its output to the client. For example, find the minimum value of an attribute.

Here is a demonstration.

>>> from paraview.simple import *
>>> Connect("kamino")
Connection (kamino:11111)
>>> s = Sphere()
# Get the whole sphere. DO NOT DO THIS IF THE DATA IS LARGE otherwise
# the client will run out of memory.
>>> allsphere = servermanager.Fetch(s)
getting appended
use append poly data filter
>>> allsphere.GetNumberOfPolys()
96
# Get the piece of the sphere on process 0.
>>> onesphere = servermanager.Fetch(s, 0)
getting node 0
>>> onesphere.GetNumberOfPolys()
48
# Apply the elevation filter so that we have a useful scalar array.
>>> elev = Elevation(s)
# We will use the MinMax algorithm to compute the minimum value of
# elevation. MinMax will be first applied on each processor. The results
# will then be gathered to the first node. MinMax will be then applied
# to the gathered results.
# We first create MinMax without an input.
>>> mm = MinMax(None)
# Set it to compute min
>>> mm.Operation = "MIN"
# Get the minimum
>>> mindata = servermanager.Fetch(elev, mm, mm)
applying operation
# The result is a vtkPolyData with one point
>>> mindata.GetPointData().GetNumberOfArrays()
2
>>> a0 = mindata.GetPointData().GetArray(1)
>>> a0.GetName()
'Elevation'
>>> a0.GetTuple1(0)
0.0

Representations and Views

Once a pipeline is created, it can be rendered using representations and views. A view is essentially a “window” in which multiple representations can be displayed. When the view is a VTK view (such as RenderView), this corresponds to a collection of objects including vtkRenderers and a vtkRenderWindow. However, there is no requirement for a view to be a VTK view or to render anything. A representation is a collection of objects, usually a pipeline, that takes a data object, converts it to something that can be rendered and renders it. When the view is a VTK view, this corresponds to a collection of objects including geometry filters, level-of-detail algorithms, vtkMappers and vtkActors. The simple module automatically creates a view after connecting to a server (including the built-in connection when using the stand-alone mode). Furthermore, the simple module creates a representation the first time a pipeline object is displayed with Show(). It is easy to create new views.

>>> view = CreateRenderView()

CreateRenderView() is a special method that creates the render view appropriate for the ActiveConnection (or for another connection specified as an argument). It returns a sub-class of Proxy. Like the constructor of Proxy, it can take an arbitrary number of keyword arguments to set initial values for properties. Note that ParaView makes the view that was created last the active view. When using Show() without a view argument, the pipeline is shown in the active view. You can get a list of views as well as the active view as follows

>>> GetRenderViews()
[<paraview.servermanager.RenderView object at 0xaf64ef0>, <paraview.servermanager.RenderView object at 0xaf64b70>]
>>> GetActiveView()
<paraview.servermanager.RenderView object at 0xaf64b70>

You can also change the active view using SetActiveView().

Once you have a render view, you can use pass it to show in order to select in which view a pipeline object is displayed. You can also pass it to Render() to select which view is rendered.

>>> Show(elev, GetRenderViews()[1])
<paraview.servermanager.GeometryRepresentation object at 0xaf64e30>
>>> Render(GetRenderViews()[1])

Notice that Show() returns a representation object (aka DisplayProperties in the simple module). This object can be used to manipulate how the pipeline object is displayed in the view. You can also access the display properties of an object using GetDisplayProperties().

>>> dp = GetDisplayProperties(elev)
>>> dp
<paraview.servermanager.GeometryRepresentation object at 0xaf649d0>

Display properties and views have a large number of documented properties some of which are poorly documented. We will cover some them here.

>>> from paraview.simple import *
# Create a simple pipeline
>>> sph = Sphere()
>>> elev = Elevation(sph)
>>> Show(elev)
>>> Render()
# Set the representation type of elev
>>> dp = GetDisplayProperties(elev)
>>> dp.Representation = 'Points'
# Here is how you get the list of representation types
>>> dp.GetProperty("Representation").Available
['Outline', 'Points', 'Wireframe', 'Surface', 'Surface With Edges']
>>> Render()
# Change the representation to wireframe
>>> dp.Representation = 'Wireframe'
>>> Render()
# Let’s get some information about the output of the elevation
# filter. We want to color the representation by one of it’s
# arrays.
# Second array = Elevation. Interesting. Let’s use this one.
>>> ai = elev.PointData[1]
>>> ai.GetName()
'Elevation'
# What is its range?
>>> ai.GetRange()
(0.0, 0.5)
# To color the representation by an array, we need to first create
# a lookup table. We use the range of the Elevation array
>>> dp.LookupTable = MakeBlueToRedLT(0, 0.5)
>>> dp.ColorAttributeType = 'POINT_DATA'
>>> dp.ColorArrayName = 'Elevation' # color by Elevation
>>> Render()

Here is the result: 

Once you create a scene, you will probably want to interact with the camera and ResetCamera() is likely to be insufficient. In this case, you can directly get the camera from the view and manipulate it. GetActiveCamera() returns a VTK object (not a proxy) with which you can interact.

>>> camera = GetActiveCamera()
>>> camera
<libvtkCommonPython.vtkCamera vtkobject at 0xe290>
>>> camera.Elevation(45)
>>> Render()

Another common thing to do is to save the view as an image. For this purpose, you can use the WriteImage() method provided by the view:

>> WriteImage("/Users/berk/image.png")

The resulting image.png looks like this. See the documentation for WriteImage() for details on choosing file type as well as a magnification factor to save images larger than the view size.

Advanced Concepts

Dealing with lookup tables

As shown earlier, you can use MakeBlueToRedLt(min, max) to create a lookup table. However this simply creates a new lookup table which the GUI won't be aware of. In ParaView Qt application, we have special lookup table management that ensures that the same lookup table is used for all arrays with same name and number of components. To reproduce the same behavior in Python, use GetLookupTableForArray().

def GetLookupTableForArray(arrayname, num_components, **params):
"""Used to get an existing lookuptable for a array or to create one if none
exists. Keyword arguments can be passed in to initialize the LUT if a new
one is created. Returns the lookup table."""
....

This will create a new lookup table and associate it with that array, if none already exists. Any default arguments to be passed to the lookup table if a new one is created, can be specified as additional parameters. You can always change the properties on the lookup table returned by this function.

# To color the representation by an array, we need to first create
# a lookup table. We use the range of the Elevation array
>>> dp.LookupTable = GetLookupTableForArray("Elevation", 1,
RGBPoints = [min, 0, 0, 1, max, 1, 0, 0],
ColorSpace = "HSV")
>>> dp.ColorAttributeType = 'POINT_DATA'
>>> dp.ColorArrayName = 'Elevation' # color by Elevation
>>> Render()

Loading State and Manipulating It

Let’s say you created a complicated visualization using the paraview application and now you want to make slight changes to it and run it in a loop as a batch script. What do you do? The best way of dealing with this is to save your visualization state and then load it from Python. Let’s say you have a state file saved as myteststate.pvsm:

>>> from paraview.simple import *
# Load the state
>>> servermanager.LoadState("/Users/berk/myteststate.pvsm")
# Make sure that the view in the state is the active one
>>> SetActiveView(GetRenderView())
# Now render
>>> Render()
# Get the list of sources
>>> GetSources()
{('Sphere1', '5'): <paraview.servermanager.Sphere object at 0xaf80e30>,
('Shrink1', '11'): <paraview.servermanager.Shrink object at 0xaf80df0>,
('Cone1', '8'): <paraview.servermanager.Cone object at 0xaf80cf0>}
# Change the resolution of the cone and render again
>>> FindSource("Cone1").Resolution = 32
>>> Render()

You can also save state.

>>> from paraview.simple import *
>>> sph = Sphere()
>>> Render()
>>> servermanager.SaveState("/Users/berk/pythonstate.pvsm")

Dealing with Time

If a reader or a filter supports time, it is easy to request a certain time step from Python. All time requests are set on views, which then propagate them to the representations which then propagate them to the visualization pipeline. Here is an example demonstrating how a time request can be made.

>>> Show(ExodusIIReader(FileName=".../can.ex2"))
>>> Render()
# Get a nice view angle
>>> cam = GetActiveCamera()
>>> cam.Elevation(45)
>>> Render()
# Check the current view time
>>> view = GetActiveView()
>>> view.ViewTime
0.0
>>> reader = GetActiveSource()
>>> reader.TimestepValues
[0.0, 0.00010007373930420727, 0.00019990510190837085,
0.00029996439116075635, 0.00040008654468692839,
...]
>>> tsteps = reader.TimestepValues
# Let’s be fancy and use a time annotation filter. This will show the
# current time value of the reader as text in the corner of the view.
>>> annTime = AnnotateTimeFilter(reader)
# Show the filter
>>> Show(annTime)
# Look at a few time steps. Note that the time value is requested not
# the time step index.
>>> view.ViewTime = tsteps[2]
>>> Render()
>>> view.ViewTime = tsteps[4]
>>> Render()

Animating

Server Manager has a complicated animation engine based on keyframes and scenes. This section will introduce a few simple ways of animating your visualization. If you have a time-aware reader, you can animate it with AnimateReader().

>>> reader = ExodusIIReader(FileName=“.../can.ex2”)
>>> Show(reader)
>>> Render()
>>> c = GetActiveCamera()
>>> c.Elevation(95)
# Animate over all time steps. Note that we are not passing the optional
# 3rd argument here. If you pass a filename as the 3rd argument,
# AnimateReader will create a movie.
>>> AnimateReader(reader)
# Save the animation to an avi file
>>> AnimateReader(reader, filename=".../movie.avi")

To animate properties other than time, you can use regular keyframes.

ParaView 3.8.0 and earlier



Although the following script will work with 3.8.1 and later, it's not the recommended way since the changes done so will not be reflected in the GUI. Refer to the following sub-section for the recommended style for 3.8.1 and later versions.

>>> Sphere()
>>> Show()
>>> Render()

# Create an animation scene
>>> scene = servermanager.animation.AnimationScene()
# Add one view
>>> scene.ViewModules = [GetActiveView()]

# Create a cue to animate the StartTheta property
>>> cue = servermanager.animation.KeyFrameAnimationCue()
>>> cue.AnimatedProxy = GetActiveSource()
>>> cue.AnimatedPropertyName = "StartTheta"
# Add it to the scene's cues
>>> scene.Cues = [cue]

# Create 2 keyframes for the StartTheta track
>>> keyf0 = servermanager.animation.CompositeKeyFrame()
>>> keyf0.Interpolation = 'Ramp'
# At time = 0, value = 0
>>> keyf0.KeyTime = 0
>>> keyf0.KeyValues= [0]

>>> keyf1 = servermanager.animation.CompositeKeyFrame()
# At time = 1.0, value = 200
>>> keyf1.KeyTime = 1.0
>>> keyf1.KeyValues= [200]

# Add keyframes.
>>> cue.KeyFrames = [keyf0, keyf1]

>>> scene.Play()

# Some properties you can change
#
# Number of frames used in Sequence mode
# scene.NumberOfFrames = 100
#
# Or you can use real time mode
# scene.PlayMode = 'Real Time'
# scene.Duration = 20

ParaView 3.8.1 onwards



The following script will only work with ParaView versions 3.8.1 and later. It is now the recommended way for accessing animation scene and animation tracks since the updates are reflected in the GUI when running through the python shell from the ParaView application is used.

>>> Sphere()
>>> Show()
>>> Render()

# Get the application-wide animation scene
>>> scene = GetAnimationScene()

# Get the animation track for animating "StartTheta" on the active source.
# GetAnimationTrack() creates a new track if none exists.
>>> cue = GetAnimationTrack("StartTheta")

# Create 2 keyframes for the StartTheta track
>>> keyf0 = CompositeKeyFrame()
>>> keyf0.Interpolation = 'Ramp'
# At time = 0, value = 0
>>> keyf0.KeyTime = 0
>>> keyf0.KeyValues= [0]

>>> keyf1 = CompositeKeyFrame()
# At time = 1.0, value = 200
>>> keyf1.KeyTime = 1.0
>>> keyf1.KeyValues= [200]

# Add keyframes.
>>> cue.KeyFrames = [keyf0, keyf1]

>>> scene.Play()

# Some properties you can change
#
# Number of frames used in Sequence mode
# scene.NumberOfFrames = 100
#
# Or you can use real time mode
# scene.PlayMode = 'Real Time'
# scene.Duration = 20

GetAnimationTrack Usages



# Typical usage
>>> track = GetAnimationTrack("Center", 0, sphere) or
>>> track = GetAnimationTrack(sphere.GetProperty("Radius")) or

# this returns the track to animate visibility of the active source in
# all views.
>>> track = GetAnimationTrack("Visibility")

# For animating properties on implicit planes etc., use the following
# signatures:
>>> track = GetAnimationTrack(slice.SliceType.GetProperty("Origin"), 0) or
>>> track = GetAnimationTrack("Origin", 0, slice.SliceType)

Loading Data Files

As seen throughout this document, you can always load a data file by explicitly creating the reader that can read the data file as follows:

>>> reader = ExodusIIReader(FileName=“.../can.ex2”)

Alternatively, starting with ParaView 3.8, you can use OpenDataFile() function to let ParaView pick a reader using the extension of the file.

>>> reader = OpenDataFile(“.../can.ex2”)

Writing Data Files (ParaView 3.9 or later)

To create a writer to write the output from a source, one can use the following:

from paraview.simple import *

# Specifying the source explicitly
>>> writer= CreateWriter("/.../filename.vtk", source)

# Using the active source
>>> writer= CreateWriter("/.../filename.vtk")

# Writing data from a particular output port
>>> writer= CreateWriter("/.../filename.vtk", servermanager.OutputPort(source, 1))

# Now one change change the ivars on the writer

# To do the actual writing, use:
>>> writer.UpdatePipeline()

Exporting CSV Data

To export a csv from the cell or point data associated with a source, one can use the following:

>>> writer = CreateWriter(".../foo.csv", source)
>>> writer.FieldAssociation = "Points" # or "Cells"
>>> writer.UpdatePipeline()
>>> del writer









ParaView: [Welcome | Site Map]




Tools for Python Scripting

New tools with python

If ParaView has been compiled with the Python wrapping, some advanced features become available to the user such as:

Those features can be reached from the Tools menu for the Shell and Trace access.

The management of macros is done inside the Macros menu.

To save the state as a Python script, just go to the File menu and choose Save state without forgetting to switch the file type to be Python *.py.

Macros

Macros allow the user to define a Python script as built-in actions that become accessible from the Macros menu or directly inside the Toolbar.

Once a local file is defined as a Macro (by clicking on Create New Macro) the given file is copied inside the user specific ParaView directory. No reference is kept to the original file. Therefore, if you keep editing the original file, the changes won't affect the macro itself.

The macros list is build dynamically at the ParaView startup by listing the content of the ParaView/Macros directory as well as the user specific ParaView/Macros directory. Note: if you want to rename a macro just rename the file in one of the given directory.

Deleted Macro DO NOT delete the file, but just renamed with a "." before the original filename and the file stay in the same directory.

Macros are displayed in the macros menu and the macros toolbar. The macros toolbar can be shown/hidden from the paraview main menu: View --> Toolbars --> Macro Toolbar. The toolbar may be hidden by default.

Note: python is not initialized until you open the python shell for the first time. If you run a macro from the macro toolbar or menu before the python shell has been opened for the first time, you will notice a slight delay as python initializes itself. You should see a wait cursor while python is initializing.

CAUTION: If this section is not relevant for your ParaView version, please read the previous version of that page in history. This is for ParaView 3.10

Trace

Trace as been introduced in ParaView 3.6.2 as a new module. It can be imported with 'from paraview import smtrace', but normally the user never needs to directly use the trace module. The trace menu items provides everything for controlling trace:

  • Start trace - starts trace. If an active trace was previously started, it will be stopped, cleared, and restarted.

  • Stop trace- stops trace. The trace output generated so far will not be cleared until trace is started again or the python shell is reset. Some internal trace data structures hold references to c++ objects, so if you want to make sure everything is cleaned up try resetting the shell.

  • Edit trace- opens the built in editor, creates a new document and fills it with the current trace output

  • Save trace- opens a prompt for the user to specify a filename and saves trace to disk.

TIP: It's a good idea to stop trace before executing a trace script you just recorded. What I do is click the Disconnect server button in the paraview toolbar. This will clear the current pipeline objects, stop trace, and reset the python interpreter.

TIP: Trace only records property values as they are modified. If you have initialized a render view or a color lookup table prior to starting trace then the generated trace script may not perfectly reflect the state of the view or lookup table. For best results, start trace before performing any other actions. Also, see the CaptureAllProperties flag in the Trace Verbosity section below.

Trace verbosity

Because of the way the GUI initializes certain proxies, some parts of the trace will be more verbose than others. For example, every time a data representation is created, seven or eight properties related to selection are modified. It might be a nice feature to provide the user with a way to specify property suppressions.

Trace can run with different verbose levels. In full property verbose mode, trace records all properties of a proxy when the proxy is registered. Normally, trace only records properties when they are modified from their default values. Control over the verbosity level is not currently available in the gui, but you can start trace manually in verbose mode using the python shell:

from paraview import smtracesmtrace.start_trace(CaptureAllProperties=True)# actions in the guismtrace.stop_trace()

Known issues with trace

It is possible to perform actions in the GUI that do not translate properly to trace. Here is a list of things that do not currently work:

  • views other than 3D render view (also have not tested mpi render view)

  • time

  • the start/stop trace buttons are not synced if trace is started manually from python

New built in editor

For convenience there is a new built in script editor. When the editor is opened on OSX, the editor's menubar temporarily replaces paraview's menubar. If this becomes too obtrusive the menu could be replaced by toolbar buttons. It might be a nice feature to allow the user to specify a command to launch an external editor.

New C++ API

New classes have been introduced under Qt/Python. They depend on classes in Qt/Core but not Qt/Components. A new class named pqPythonManager is available globally through the pqApplicationCore instance:

pqPythonManager* manager = qobject_cast<pqPythonManager*>( pqApplicationCore::instance()->manager("PYTHON_MANAGER"));

The python manager has a public method:

pqPythonDialog* pythonShellDialog();

Calling this method will return the python shell. Python will be initialized on the first call to this method and the returned pqPythonDialog will be ready to use. pqPythonDialog offers public methods for executing python files and strings of python code.

If you plan to call methods in the python c api, you must make the python interpreter active:

pqPythonDialog* dialog = manager->pythonShellDialog(); dialog->shell()->makeCurrent(); // Calls to python c api dialog->shell()->releaseControl();

When the python interpreter is reset, pqPythonDialog emits a signal 'interpreterInitialized()'. The pqPythonManager listens for this signals and imports the paraview modules. So when this signal is triggered, it is not guaranteed that paraview python modules have been imported yet. After the paraview python modules are imported, the pqPythonManager emits a signal 'paraviewPythonModulesImported()'.

Batch Processing

Batch Processing

ParaView's pvbatch and pvpython command line executables substitute a python interpreter for the Qt GUI interface that most users control ParaView's back end data processing and rendering engine through. Either may be used for batch processing, that is to replay Visualization sessions in an exact, easily repeated way. The input to either comes in the form of the same python script that was described in the previous section.

Of the two, pvbatch is more specialized for batch processing and suited to running in an offline mode on dedicated data processing supercomputers because:

Therefore you must supply a filename of the script you want pvbatch to execute.



Therefore in the scripts that you give to pvbatch it is not possible to Disconnect() from the paired server or Connect() to a different one.



Therefore you typically start pvbatch like this:

[mpiexec -N <numprocessors>] pvbatch [args-for-pvbatch] script-filename [args-for-script]



Creating the Input Deck

There are at least three ways to create a batch script.

The hardest one is writing it by hand using the syntax described in the previous section. You can of course use any text editor for this but you will probably be more productive if you set up a more fully featured python IDE like Idle or the python shell within the ParaView GUI so that you have access to interactive documentation, tab completion and quick preview capabilities. Another alternative is to let the ParaView GUI client record all of your actions into a python script by using the Python Trace feature. Later you can easily tweak the recorded script once you become familiar with ParaView's python syntax. The third, and to longtime ParaView users the most traditional way, is to instead record a ParaView state file and then load that via a small python script as demonstrated in the first example below.

Examples

Loading a state file and saving a rendered result

>>> from paraview.simple import *
# Load the state
>>> servermanager.LoadState("/Users/berk/myteststate.pvsm")

At this point you have a working pipeline instantiated on the server which you can use introspection on to access and then arbitrarily control anything within. At the core ParaView's is a visualization engine so we will demonstrate by simply generate and saving an image.

# Make sure that the view in the state is the active one so we don't have to refer to it by name.
>>> SetActiveView(GetRenderView())
# Now render and save.
>>> Render()
>>> WriteImage("/Users/berk/image.png")

parameter study

Parameter studies are one example of how batch processing can be extremely useful. In a parameter study one or more pipeline parameters (a filename, a timestep, or a filter property for example) are varied across some range but an otherwise identical script is replayed numerous times and results are saved. After the suite of sessions complete the set of results are easy to compare. For this type of work I recommend writing a higher level script that varies the parameter and for each value spawns off a pvbatch session where the parameter gets passed in as an argument to the ParaView python script.

The following is a slightly condensed version of a hierarchical set of scripts written during a benchmark study. This benchmark is an example of a parameter study in which the number of triangles rendered in the scene is varied and afterward we examine the output to determine how the rendering rate differs as a function of that parameter change.

This top level script varies the number of triangles and then submits parallel jobs to the cluster's PBS batch queue. See the qsub manpages or ask your system administrators for the exact syntax of the submission command.

RUNID=0
NNODES=8
TLIMIT=10
for NUMTRIS in 10 20 30 40 50
do
mkdir ~/tmp/run${RUNID}

qsub -N run${RUNID} \
-l "walltime=0:${TLIMIT}:0.0 select=${NNODES}:ncpus=8:arch=wds024c" \
-j eo -e ~/tmp/run${ID}/outstreams.log \
-v "RUNID=${ID} NNODES=${NNODES} NUMTRIS=${NUMTRIS}" \
~/level2.sh

let RUNID+=1
done

The second level script is executed whenever it gets to the top of PBS's priority queue. It examines the parameters it is given and then runs paraview's pvbatch executable with them. It also does some bookkeeping tasks that are helpful when debugging the batch submission process.

echo "RUN NUMBER=${RUNID}"

#setup MPI environment
source ${HOME}/openmpipaths.sh

#prepare and run the parallel pvbatch program for the parameter value we are given
batch_command="${HOME}/ParaView-3.8.1/build/bin/pvbatch ${HOME}/level3.py -# ${RUNID} -nt ${NUMTRIS}"
mpirun -np $NNODES --hostfile $PBS_NODEFILE $batch_command

#move the results to more permanent storage
mv /tmp/bench* ${HOME}/tmp/run${DDM_RUNNUM}

The final level is the script that is executed by pvbatch.

from paraview.simple import *
from optparse import OptionParser
import paraview.benchmark
import math
import sys
import time

parser = OptionParser()
parser.add_option("-#", "--runid", action="store", dest="runid",type="int",
default=-1, help="an identifier for this run")
parser.add_option("-nt", "--triangles", action="store", dest="triangles",type="int",
default=1, help="millions of triangles to render")
(options, args) = parser.parse_args()

print "########################################"
print "RUNID = ", options.runid
print "START_TIME = ", time.localtime()
print "ARGS = ", sys.argv
print "OPTIONS = ", options
print "########################################"

paraview.benchmark.maximize_logs()

TS = Sphere()
side=math.sqrt(options.triangles*1000000/2)
TS.PhiResolution = side
TS.ThetaResolution = side

dr = Show()
view.UseImmediateMode = 0
view = Render()

cam = GetActiveCamera()
for i in range(0,50):
cam.Azimuth(3)
Render()
WriteImage('/tmp/bench_%d_image_%d.jpg' % (options.runid, i))

print "total Polygons:" + str(dr.SMProxy.GetRepresentedDataInformation(0).GetPolygonCount())
print "view.ViewSize:" + str(view.ViewSize)

paraview.benchmark.get_logs()
logname="/tmp/bench_" + str(options.runid) + "_rawlog.txt"
paraview.benchmark.dump_logs(logname)

print "#######"
print "END_TIME = ", time.localtime()

large data example

Another important example is for visualizing extremely large datasets that can not be easily worked with interactively. In this setting, the user first constructs a visualization of a small but representative data set. Typically this takes place by recording a session in the standard GUI client running on some small and easily accessed machine. Later, the user changed the filename property of the reader in the recorded session file. Finally the user submits the script to a larger machine which performs the visualization offline and saves results for later inspection.

The essential thing that you need to be able to do for this is to substitute the filename and location of the original small dataset with the name and locations of the large one. There are two ways to do this.

The first way is to directly edit the filename in either the ParaView state file or the python script where it is loaded. The task is made easier by the fact that all readers conventionally name the input file name property "FileName". Standard python scripts are well described in other sections so we will describe paraview state files here instead. A paraview state file has the extension .pvsm and the internal format is a text based XML file. Simply open the pvsm file in a text editor, search for FileName and replace all occurances of the old with the new.

For reference, the portion of a pvsm file that specifies a reader's input file is:

<Proxy group="sources" type="LegacyVTKFileReader" id="160" servers="1">
<Property name="FileNameInfo" id="160.FileNameInfo" number_of_elements="1">
<Element index="0" value="/Data/molar.vtk"/>
</Property>
<Property name="FileNames" id="160.FileNames" number_of_elements="1">
<Element index="0" value="/Data/molar.vtk"/>
<Domain name="files" id="160.FileNames.files"/>
</Property>
<Property name="TimestepValues" id="160.TimestepValues"/>
<SubProxy name="Reader" servers="1"/>
</Proxy>

The second way is to set up the pipeline and then use introspection to find and then change the filename. This approach is easier to parameterize but somewhat more fragile since not all readers respond well to having their names changed once established. You should at least use caution and try to change the filename before the pipeline first runs. Otherwise more readers will be confused and you will also waste time processing the smaller file. When loading state files the proper place to do this is immediately after the LoadState command. For python scripts the place to do this is as near to the creation of the reader as possible, and certainly before any Update or Render commands. An example of how to do this follows:

>>> from paraview.simple import *
# Load the state
>>> servermanager.LoadState("/Users/berk/myteststate.pvsm")
# Now the pipeline will be instantiated but it will not have updated yet.
# You can programmatically obtain the reader from the pipeline starting with this command, which lists all readers, sources and filters in the pipeline.
>>> GetSources()
#{('box.ex2', '274'): <paraview.servermanager.ExodusIIReader object at 0x21b3eb70>}
# But it is easier if you note that readers are typically named according to the name of the file that they are created for.
>>> reader = FindSource('box.ex2')
#Now you can change the filename with these two commands:
>>> reader.FileName = ['/path_to/can.ex2']
>>> reader.FileNameChanged()