ParaView/Python Scripting: Difference between revisions

From KitwarePublic
Jump to navigationJump to search
No edit summary
No edit summary
Line 365: Line 365:


The class hierarchy for property classes looks like this.
The class hierarchy for property classes looks like this.
[[Image:Prophierarchy.png|center]]
All Property classes define the following methods.
All Property classes define the following methods.

Revision as of 19:27, 11 September 2008

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.

Quick Start - a Tutorial

Getting Started

To start interacting with the Server Manager, you have to load the servermanager 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/servermanager.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

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

<source lang="python"> >>> from paraview import servermanager </source>

Note: Importing the paraview module directly is deprecated although still possible for backwards compatibility. This document refers to the servermanager module alone. Next, we need to connect to a server if we are not already connected.

<source lang="python"> >>> if not servermanager.ActiveConnection: ... connection = servermanager.Connect()

Connection (builtin:5) </source>

In this example, we connected to the built-in server. When using pvbatch, this is the only connection mode supported, even when pvbatch is running as an MPI task. When running pvpython or loading servermanager from an external python interpreter, we can also connect to a remote server as shown in the following example

<source lang="python"> >>> connection = servermanager.Connect('localhost') Connection (localhost:11111) </source> This assumes that you already started the server (pvserver) on the local machine. Note: Connect() returns a connection object on success and returns None on failure. You might want to check the return value to make sure connection succeeded.

<source lang="python"> >>> connection = servermanager.Connect('localhost') >>> if not connection: ... raise exceptions.RuntimeError, “Connection to localhost failed.” </source>

Note: When importing the servermanager module from the application’s python shell, Connect() should not be called as a connection already exists.

Creating a Pipeline

When first loaded, the servermanager module creates several sub-modules that can be used to create a visualization. The most important ones are listed below.

  • sources
  • filters
  • rendering

You can get a list of classes these modules contain by using dir() as shown in the following example.

<source lang="python"> >>> dir(servermanager.sources) ['AVSucdReader', 'ArrowSource', 'Axes', 'CSVReader', 'ConeSource', 'CubeSource', 'CylinderSource', 'DEMReader', 'ExodusIIReader', 'ExodusReader', 'FLUENTReader', 'Facet Reader', 'GlyphSource2D', 'HierarchicalFractal', 'ImageMandelbrotSource', 'ImageReader', ...] </source>

Let’s start by creating a ConeSource object:

<source lang="python"> >>> coneSource = servermanager.sources.ConeSource() </source>

The object assigned to coneSource is a proxy for the actual vtkConeSource. This proxy provides a set of properties and methods to control the behavior of the underlying VTK object(s). These objects may be in the same process (built-in server) or on one or more server processes (distributed remote server). The proxy will handle communication with the VTK objects in a transparent way. You can get some documentation about the proxy using help().

<source lang="python"> >>> help(coneSource) Help on ConeSource in module paraview.servermanager object:

class ConeSource(Proxy)

|  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:
|      ConeSource
|      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.
|...  

</source>

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

<source lang="python"> >>> coneSource.Resolution Property name= Resolution value = 6 </source>

You can increase the resolution as shown below.

<source lang="python"> >>> coneSource.Resolution = 32 </source>

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

<source lang="python"> >>> coneSource = servermanager.sources.ConeSource(Resolution=32) </source>

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

<source lang="python"> >>> coneSource.Center Property name= Center value = [0.0, 0.0, 0.0] >>> coneSource.Center[1] = 1 </source>

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

<source lang="python"> >>> coneSource.Center[0:3] = [1, 2, 3] >>> coneSource.Center Property name= Center value = [1.0, 2.0, 3.0] </source>

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

<source lang="python"> >>> shrinkFilter = servermanager.filters.ShrinkFilter(Input=coneSource) >>> shrinkFilter.Input Property name= Input value = <paraview.servermanager.ConeSource object at 0x2d00dd90>:0 </source>

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 pipeline model, see one of the VTK books.

<source lang="python"> >>> shrinkFilter.UpdatePipeline() >>> shrinkFilter.GetDataInformation().GetNumberOfCells() 33L >>> shrinkFilter.GetDataInformation().GetNumberOfPoints() 128L </source>

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.

<source lang="python"> >>> view = servermanager.CreateRenderView() >>> rep = servermanager.CreateRepresentation(shrinkFilter, view) >>> view.StillRender() </source>

Oops, nothing is visible. We need to reposition the camera to contain the entire scene.

<source lang="python"> >>> view.ResetCamera() >>> view.StillRender() </source>

Et voila:

Servermanager snapshot.png

CreateRenderView() and CreateRepresentation() are special methods in the servermanager module to facilitate the creation of representations and views. CreateRepresentation() automatically adds the new representation to the view.

<source lang="python"> >>> view.Representations Property name= Representations value = [<paraview.servermanager.UnstructuredGridRepresentation object at 0x2d0170f0>] </source>

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

paraview.servermanager Module

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

  • pvpython: The pvpython application, distributed with the ParaView application suite, is a Python client to the ParaView servers. It supports interactive execution as well as batch execution.
  • pvbatch: The pvbatch application, also distributed with the ParaView application suite, is a Python application designed to run batch scripts on distributed servers. When ParaView is compiled with MPI,
  • pvbatch can be launched as an MPI program. In this mode, the first node will load a Python script specified as a command-line argument and execute it using a special built-in connection on all nodes. This application does not support interactive execution.
  • paraview: Python scripts can be run from the paraview client using the Python shell that is invoked from Tools -> Python Shell. The Python shell supports interactive mode as well as loading of scripts from file.
  • External Python interpreter: Any Python-capable application can load the paraview.servermanager module if the right environment is configured. For this to work, you either have to install the paraview Python modules (including the right shared libraries) somewhere in sys.path or you have to set PYTHONPATH to point to the right locations.

Overview

The paraview.servermanager module contains several Python classes designed to be Python-friendly as well as all classes wrapped from the C++ Server Manager library. The most important classes are as follows.

  • Proxy
  • ProxyManager
  • Property and sub-classes

We will cover these classes in detail in following sections. When first loaded, the servermanager module creates several sub-modules. The most important ones are as follows.

  • sources
  • filters
  • rendering

These modules are automatically populated (at load time) with various Proxy sub-classes as defined in the Server Manager configuration files (ParaView3/Servers/ServerManager/Resources/*.xml). This allows direct instantiation of actual Proxy sub-classes (for example, SphereSource) instead of having to use vtkSMProxyManager::CreateProxy(). Furthermore, the documentation for each class can be obtained using help().

Connecting to a Server

Unless you are using the Python shell that is in the paraview application, the first step to any Server Manager Python script is connecting to a server. Even when running in stand-alone mode, you have to connect to a built-in server. To connect to a server, use servermanager.Connect(). This method takes 4 arguments, all of which have default values.

<source lang="python"> def Connect(ds_host=None, ds_port=11111, rs_host=None, rs_port=11111) </source>

When connecting to the built-in server and running pvbatch, do not specify any of these arguments. The default values work well.

When connecting to a hybrid 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.

<source lang="python">

  1. Connect to built-in

>>> connection = servermanager.Connect()

  1. Connect to pvserver running on amber1 (first node of our test cluster)
  2. using the default port 11111

>>> connection = servermanager.Connect(‘amber1’)

  1. Connect to pvdataserver running on the amber cluster, pvrenderserver
  2. running on Berk’s desktop

>>> connection = servermanager.Connect(‘amber1’, 12000, ‘kamino’, 11111) </source>

Although not fully implemented yet, the servermanager supports multiple connection. The module keeps track of the active connection with the ActiveConnection variable. By default, all communication is sent to the server to which the ActiveConnection points. The first time Connect() is called, servermanager automatically sets ActiveConnection. After the first time, unless Disconnect() is called first, ActiveConnection is not set. If you want to set the ActiveConnection to another connection, use the return value from Connect().

<source lang="python"> >>> servermanager.ActiveConnection = servermanager.Connect(‘amber1’) </source>

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

Getting Help

The servermanager module is well documented. You can access it’s online documentation using help().

<source lang="python"> >>> from paraview import servermanager >>> help(servermanager) </source>

You can also access the documentation of all Proxy types using the sources, filters and rendering modules.

<source lang="python"> >>> dir(servermanager.filters) ['AllToN', 'Append', 'AppendAttributes', 'AppendPolyData', 'ArbitrarySourceGlyph', 'ArbitrarySourceStreamTracer', 'Balance', 'BrownianPoints', 'CTHPart', 'Calculator', 'CellCenters', 'CellDataToPointData', 'CleanPolyData', 'CleanUnstructuredGrid', 'ClientServerMoveData', 'Clip', 'Contour', 'Curvatures', 'Cut', 'D3', 'DataSetSurfaceFilter', 'DataSetTriangleFilter', 'DecimatePro', 'Delaunay2D', ...] >>> help(servermanager.filters.Calculator) </source>

This documentation is automatically generated from the Server Manager configuration files and is identical to the class documentation found under the paraview Help menu. 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 pattern2. 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.

<source lang="python"> >>> sphereSource = vtk.vtkSphereSource() # VTK-Python script

>>> sphereSourceP = servermanager.SphereSource() # servermanager script </source>

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

<source lang="python"> >>> sphereSource.SetCenter(1.0, 1.0, 0.0) </source>

you can write the following.

<source lang="python"> >>> sphereSourceP.Center = [1.0, 1.0, 0.0] </source>

Properties are covered in detail in the next section. In the VTK Server Manager library, proxies are instances of vtkSMProxy or one of it’s sub-classes. The servermanager module wraps these classes with a set of Python classes to make them more Python-friendly. Using the Server Manager library, you create a proxy with the help of the Proxy Manager3 :

<source lang="python"> >>> pxm = servermanager.ProxyManager() >>> sphereSourceP = pxm.SMProxyManager.NewProxy("sources", "SphereSource") >>> type(sphereSourceP) <type 'vtkobject'> >>> sphereSourceP.GetClassName() 'vtkSMSourceProxy' </source>

The proxy groups (for example “sources”) and the proxy types that can be created are defined in a set of XML configuration files (e.g., ParaView3/Servers/ServerManager/Resources/*.xml). Using the servermanager module, you can directly create a proxy by instantiating the appropriate class.

<source lang="python"> >>> sphereSourceP = servermanager.sources.SphereSource() >>> type(sphereSourceP) <class 'paraview.servermanager.SphereSource'> >>> sphereSourceP.GetClassName() 'vtkSMSourceProxy' </source>

A servermanager proxy object contains a Server Manager proxy object. You can access this object directly using the SMProxy data member:

<source lang="python"> >>> type(sphereSourceP.SMProxy) <type 'vtkobject'> </source>

All unknown attribute requests made to a servermanager proxy are passed to the SMProxy so you normally should not need to access SMProxy directly.

Properties

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

<source lang="python"> >>> rp = sphereSourceP.GetProperty("Radius") >>> rp.SetElement(0, 2) 1 >>> sphereSourceP.UpdateProperty("Radius") </source>

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

<source lang="python"> >>> sphereSourceP.Radius = 3 </source>

Here Radius is a Python property which, when a value is assigned to it, calls sphereSourceP.SetPropertyWithName(Radius,3). The same property returns a servermanager Property object when accessed.

<source lang="python"> >>> type(sphereSourceP.Radius) <class 'paraview.servermanager.VectorProperty'> </source>

The class hierarchy for property classes looks like this.

Prophierarchy.png

 All Property classes define the following methods.

  • __len__()
  • __getitem__()
  • __setitem__()
  • __getslice__()
  • __setslice__()
  • GetData()
  • SetData().

Therefore, all of the following are supported.

<source lang="python"> >>> sphereSourceP.Center Property name= Center value = [0.0, 0.0, 0.0] >>> sphereSourceP.Center[0] = 1 >>> sphereSourceP.Center[0:3] = [1,2,3] >>> sphereSourceP.Center[0:3] [1.0, 2.0, 3.0] >>> sphereSourceP.Center.SetData([2,1,3]) >>> sphereSourceP.Center.GetData() [2.0, 1.0, 3.0] >>> len(sphereSourceP.Center) 3 </source>

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 (vtkSMIntVectorProperty, vtkSMDoubleVectorProperty and vtkSMStringVectorProperty, respectively) . Most properties of this type are simple. Examples include SphereSource.Radius (double scalar), SphereSource.Center (vector of doubles), GlyphSource2D.Filled (boolean), GlyphSource2D.GlyphType (enumeration), VectorText.Text (string) and Contour.ContourValues (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.SelectInputScalars and ExodusIIReader.PointResultArrayStatus.

<source lang="python"> >>> reader = servermanager.sources.ExodusIIReader(FileName='.../disk_out_ref.ex2') >>> reader.UpdatePipelineInformation()

  1. Get information about arrays and whether they will be read. By
  2. default no arrays are read.

>>> reader.PointResultArrayInfo Property name= PointResultArrayInfo value = ['Temp', '0', 'V', '0', 'Pres', '0', 'AsH3', '0', 'GaMe3', '0', 'CH4', '0', 'H2', '0']

  1. Enable the Temp array

>>> reader.PointResultArrayStatus = ['Temp', '1']

  1. Force read

>>> reader.UpdatePipeline()

  1. Now check the output

>>> pdi = reader.GetDataInformation().GetPointDataInformation() >>> pdi.GetNumberOfArrays() 1 >>> pdi.GetArrayInformation(0).GetName() 'Temp' </source>

This example demonstrates the use of ExodusIIReader.PointResultArrayStatus. This is a VectorProperty that represents a list of tuples of strings of 2 elements: (array name, status [on|off]). 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). From the previous case, let’s enable reading of V and CH4.

<source lang="python"> >>> reader.PointResultArrayStatus = [ ‘V’ , ‘1’, ‘CH4’, ‘1’ ] </source>

Note that the property uses strings for both the array name and the flag (which is actually an integer). Properties do not directly support mixed types, thus forcing us to use strings in this situation. Glyph.SelectInputScalars is more complicated.

<source lang="python"> >>> sph= servermanager.sources.SphereSource()

  1. Glyph source producing diamond

>>> source=servermanager.sources.GlyphSource2D(GlyphType=8) >>> elev=servermanager.filters.ElevationFilter(Input=sph)

  1. Glyph the points of the sphere with diamonds

>>> glyph=servermanager.filters.Glyph(Input=elev, Source=source)

  1. Scale the glyph with the Elevation array

>>> glyph.SelectInputScalars = [ '0', '0', '0', '0', 'Elevation' ] >>> glyph.ScaleMode = 0 # Use scalars </source>

Here the property SelectInputScalars 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 argument5. A ProxyProperty can point to one or more proxies. This is equivalent to a C++ method that takes a pointer to a VTK object. Examples of ProxyProperty include Cut.CutFunction (single proxy) and RenderView.Representations (a list of proxies) . InputProperty is similar to ProxyProperty; it is used to connect pipeline objects (source proxies). It is covered in more detail in the next section. 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).

<source lang="python"> >>> reader = servermanager.sources.ExodusIIReader(FileName='.../can.ex2') >>> reader.UpdatePropertyInformation() >>> reader.TimestepValues Property name= TimestepValues value = [0.0, 0.00010007373930420727, 0.00019990510190837085, 0.00029996439116075635, 0.00040008654468692839, 0.00049991923151537776, 0.00059993512695655227, 0.00070004921872168779, ...] </source>

By default, information properties are not pulled. To force a pull, call UpdatePropertyInformation() on the proxy. 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:

<source lang="python"> >>> for prop in glyph: print prop

Property name= Input value = <paraview.servermanager.ElevationFilter>:0 Property name= MaximumNumberOfPoints value = 5000 Property name= RandomMode value = 1 Property name= SelectInputScalars value = ['0', '0', '0', '0', 'Elevation'] Property name= SelectInputVectors value = ['1', , , , ] Property name= Orient value = 1 Property name= ScaleFactor value = 1.0 Property name= ScaleMode value = 0 Property name= Source value = <paraview.servermanager.GlyphSource2D>:0 Property name= UseMaskPoints value = 1 </source>

As an alternative, you can use a PropertyIterator object.

<source lang="python"> >>> it = s.__iter__() >>> for i in it: print it.GetKey(), it.GetProperty() </source>