Examples/ParaviewAnimating – vis
wiki:Examples/ParaviewAnimating

Animating Data with ParaView Python Scripting

Some information on how to write Python scripts to animate your data with ParaView can be found here:
https://www.paraview.org/Wiki/ParaView/Python_Scripting
https://kitware.github.io/paraview-docs/latest/python/paraview.simple.html
https://kitware.github.io/paraview-docs/latest/python/_modules/paraview/servermanager.html

On this page, we would like to share our own experience with you. DISCLAIMER: our knowledge about all this is limited and maybe even incorrect. So take all this with a grain of salt.

ParaView Gui: Animation View

As usual, when you want to write a Python script for ParaView from scratch, and have no idea where to start, it makes sense to open the ParaView GUI, start a Python trace, and prototype the desired setup in the GUI interactively. When you want to generate an animation, you have to deal with the Animation View, obviously.

ParaView Animtion View

Unfortunately, ParaView is not willing to show you all settings in the trace. Some are just skipped, e.g. settings regarding the "TimeKeeper1 - Time" are NOT reflected in the trace. For this reason it makes sense to take a more closer look at the mechanisms and Python classes working behind the scene.

Basic Concept

The basic concept of how to animate "something", in this case parameters (so called properties) of the ParaView scene, is quite easy to understand. The central element of any animation is a timeline with a start and end time and a mechanism to determine a number of descrete timesteps (frames). in ParaView all this is implemented in the Python class paraview.simple.AnimationScene. Within the time interval defined in the timeline, properties of the scene can be changed. In the ParaView GUI this concept is reflected by so called "tracks" (or "cues") in the Animation View. Basically, each track defines the temporal change of one (or more) properties of the scene.

In ParaView-Python, different kinds (classes) of tracks/cues are available. We will deal with four of them, which are implemented in the following Python classes:

  • paraview.simple.KeyFrameAnimationCue: basic cue to animate general properties of objects (readers, sources, filters) in the render pipeline
  • paraview.simple.CameraAnimationCue: cue to change camera parameters (e.g. position, focal point, up direction, view angle, parallel scale)
  • paraview.simple.PythonAnimationCue: cue to execute a Python script at a certain point in time
  • paraview.simple.TimeAnimationCue: cue to determine what data timesteps are loaded depending on the animation clock time

In general, each cue is connected to one or more properties of a ParaView object and has a number of keyframes attached to it, each defining certain values valid for a specific point in time. Therefore the key elements :) of a keyframe are KeyTime and KeyValues. The value(s) of the referred property is set to the keyvalues at the specified keytime. The most types of keyframes have the ability to interpolate keyvalues from one keyframe to the next (se below). In the next paragraphs we are going to explain the basic mechanisms of the relevat Python classes and we give examples of typical use cases.

AnimationScene

The AnimationScene is responsible to steer the animation clock time. For this purpose, the AnimationScene has a StartTime, an EndTime, and a mechanism to calculate the discrete points in time between StartTime and EndTime. These descrete timesteps are determined by the Mode (called PlayMode in Python) of the AnimationScene. Three different PlayModes are available:

  • 'Sequence': the timesteps are defined by the property NumberOfFrames
  • 'Snap To TimeSteps': only useful if you have time dependent data. The descrete timesteps are identical to the timesteps of the data. The AnimationScene has knowledge about the available data timesteps by the help of a seperate object, the TimeKeeper.
  • 'RealTime': given a specified duration, the timesteps are calculated on the fly (while rendering) in order to guarantee that the animated sequence will take this duration. This mode is not useful for typical Python scripting, though.

Important properties of AnimationScene:

  • StartTime: the start time of the animation
  • EndTime: the end time of the animation
  • PlayMode: either 'Sequence', 'Snap To TimeSteps' or 'RealTime'
  • NumberOfFrames: number of frames, only used when PlayMode is set to 'Sequence'
  • Duration: duration of the animation in seconds, only used when PlayMode is set to 'RealTime'
  • AnimationTime: the actual animation clock time. Can be get or set.
  • TimeKeeper: the TimeKeeper-object
  • Cues: List of attached cues (=tracks)

Important methods of AnimationScene:

  • GoToFirst(): goto first frame
  • GoToLast(): goto last frame
  • GoToNext(): goto next frame
  • GoToPrevious(): goto previous frame
  • Play(): renders all timesteps one after another in a window
  • Stop(): stops the rendering

AnimationScene Use Cases

Get the animation scene and play a sequence of 100 timesteps:

from paraview.simple import *
renderView = GetActiveViewOrCreate('RenderView')
animationScene = GetAnimationScene()
animationScene.StartTime = 0
animationScene.EndTime = 1
animationScene.NumberOfFrames = 100
animationScene.PlayMode = 'Sequence'
animationScene.GoToFirst()
i = 0
while True:
   imageName = "image_%04d.jpg" % (i)
   i = i + 1
   renderView.Update()
   SaveScreenshot(imageName, renderView, ImageResolution=[1920, 1080])
   if animationScene.AnimationTime == animationScene.EndTime:
      break
   anmationScene.GoToNext()

Get the animation scene and play all available timesteps of time dependent data:

from paraview.simple import *
renderView = GetActiveViewOrCreate('RenderView')
animationScene = GetAnimationScene()
animationScene.PlayMode = 'Snap To TimeSteps'
animationScene.GoToFirst()
i = 0
while True:
   imageName = "image_%04d.jpg" % (i)
   i = i + 1
   renderView.Update()
   SaveScreenshot(imageName, renderView, ImageResolution=[1920, 1080])
   if animationScene.AnimationTime == animationScene.EndTime:
      break
   anmationScene.GoToNext()

Key Frames

Before we start our explantion of cues, we give an overview about keyframes, as keyframes are an integral part of cues. Keyframes define what value(s) a cue passes to the property of the connected pipeline object at a give point in time. Without keyframes, a cue is more or less useless (with the exception of the TimeAnimationCue, see below). A cue stores the list of attached keyframes in its KeyFrame property.

The two basic keyframe classes are:

  • paraview.simple.KeyFrame
  • paraview.simple.BooleanKeyFrame

These two keyframes have only two intersting properties: KeyTime and KeyValues (which is a Python-list of values).

Keyframes used to interpolate values are:

  • paraview.simple.RampKeyFrame: linear interpolation
  • paraview.simple.SinusoidKeyFrame: sinusoidal interpolation
  • paraview.simple.ExponentialKeyFrame: exponential interpolation
  • paraview.simple.CompositeKeyFrame: composite of four types of keyframes. 'Interpolation' property can be set to 'Boolean', 'Ramp', 'Exponential', or 'Sinusoid'

The keyframe for interpolating camera parameters is:

  • paraview.simple.CameraKeyFrame

KeyFrameAnimationCue

As already mentioned, a KeyFrameAnimationCue connects the property of a pipeline object to the cue. This connection is defined via the attributes AnimatedProxy (proxy of the pipeline object) and AnimatedPropertyName (name of the connected property), though typically you do not have to set these attributes on your own. Instead they are set when constructing a KeyFrameAnimationCue by calling GetAnimationTrack(...) (see use case below). Similar to the AnimationScene, every cue also has the properties StartTime and EndTime. Typically these properties do not have to be identical to the corresponding ones of AnimationScene. When TimeMode is set to 'Normalize' (which is the default), the start and end time of the animation scene is linearly interpolated to the interval [StartTime, EndTime]. Default values are StartTime=0 and EndTime=1.

KeyFrameAnimationCue Use Case

Create three different animation cues for three different properties of a sphere:

from paraview.simple import *
sphere = Sphere()
Show(sphere)
track1 = GetAnimationTrack("Visibility") # property of active source
track2 = GetAnimationTrack("Center", 0, sphere)
track3 = GetAnimationTrack(sphere.GetProperty("Radius"))
# set keyframes, in this example only for track1:
kf0 = CompositeKeyFrame()
kf0.Interpolation = 'Ramp'
# At time = 0, value = 0
kf0.KeyTime = 0
kf0.KeyValues = [0]
kf1 = CompositeKeyFrame()
# At time = 1.0, value = 200
kf1.KeyTime = 1.0
kf1.KeyValues = [200]
# attach keyframes to track1
track1.KeyFrames = [kf0, kf1]

TimeAnimationCue

This type of cue is very special somehow: while all other kind of cues are absolutely useless without attached keyframes, this one can fullfill a special task without any: it can directly hand over the animation clock time (coming from AnimationScene) to the property of a connected object. The typical use case within ParaView is as follows: the AnimationScene sets the value of the TimeAnimationCue directly to its clock time. The TimeAnimationCue passes this value to the Time property of the TimeKeeper object, which in turn requests all data objects to load just this time step of the data. This way the clock time of the animation scene can be kept in sync with the data timsteps. Nevertheless you can override this behaviour by attaching keyframes to this cue and setting "UseAnimationTime=0". This way you can control what data timesteps are loaded/rendered independent from the animation clock time.

TimeAnimationCue Use Cases

Whatever the AnimationScene clock time is, set the time of the timetrack to 100. This setup can be useful e.g. to generate an animated camera flight of one single data timestep (100 in this example).

from paraview.simple import *
timeTrack = GetTimeTrack()
timeTrack.StartTime = 0
timeTrack.EndTime = 1
timeTrack.UseAnimationTime = 0
keyFrame = CompositeKeyFrame()
keyFrame.Interpolation = "Ramp"
keyFrame.KeyValues=[100] # set time step to 100
keyFrame.KeyTime = 0
timeTrack.KeyFrames=[keyFrame]

Reset the timetrack to use the AnimationScene clock time again:

timeTrack.UseAnimationTime = 1

CameraAnimationCue

The CameraAnimationCue controls severals parameters of the camera, like position, focal point, up vector and view angle. It's main purpose is to generate camera flights by controlling the position and focal point of the camera depending on the animation time. The behaviour of the camera can be set to three different modes by the property Mode:

Mode:

  • 'Interpolate Camera': each keyframe of the CameraAnimationCue stores one camera position. These positions are interpolated in the animation.
  • 'Path-based': the first keyframe of the CameraAnimationCue stores a list of camera positions (PositionPathPoints) and focal points (FocalPathPoints). These values are interpolated in the animation. The pathes may be closed to generate seamless camera rides (ClosedPositionPath, ClosedFocalPath).
  • 'Follow-data': The CameraAnimationCue is connected to a visible pipeline object and the focal point of the camera is adjusted to point at the center of this (potentially moving) object.

CameraAnimationCue Use Cases

renderView = GetActiveView()
cameraTrack = GetCameraTrack(view=renderView)
cameraTrack.Mode = 'Interpolate Camera'
To be continued

PythonAnimationCue

Also a Python script can be used in an animation cue. In the Python script three functions can be implemented:

  • start_cue: is executed once at the beginning of the animation
  • tick: is executed every time step
  • end_cue: is executed once at the end of the animation

Here is an example of such a script. In this example the value of the timestep is translated into a date string (e.g. 2018-01-01) and displayed in the scene via a text source with name "Text1".

from paraview.simple import *
from datetime import date
from datetime import timedelta

def start_cue(self): pass

def tick(self):
    view = GetActiveView()
    time = int(view.ViewTime)
    dat = date(2000,1,1) + timedelta(days=time)
    tx = FindSource("Text1")
    tx.Text = repr(dat.year) + "-" + '{:02d}'.format(dat.month) + "-" + '{:02d}'.format(dat.day)

def end_cue(self): pass

Here is an example on how to create and use a Python cue in a Python script:

############################# function call on each animation step
PythonAnimationCue1 = PythonAnimationCue()
PythonAnimationCue1.Script= """
def start_cue(self): pass

def tick(self):
#   source = FindSource("out_")
#   source.UpdatePipeline(GetAnimationScene().TimeKeeper.Time)

#   tube1 = FindSource("tube1")
#   tube1.UpdatePipeline(self.GetAnimationTime())

#   glyph1 = FindSource("glyph1")
#   glyph1.UpdatePipeline(self.GetAnimationTime())

   animationScene1 = GetAnimationScene()
   time = animationScene1.TimeKeeper.Time
   i = int(time)
   print(time, i)

   # skip if already finished
   if i > 250:

     renderView1=GetActiveView()
#     renderView1.ViewTime = i
#     animationScene1.AnimationTime = i

     # get new filename
     outname=outpath + 'out_' + str(i).zfill(5) + '.x3d'
     print(' -> ' + outname)

     # write X3D scene
     x3dExporter=exporters.X3DExporter(FileName=outname)
     print('   x3d created')
     x3dExporter.SetView(renderView1)
     print('   x3d configured')
     x3dExporter.Write()
     print('   x3d written')

def end_cue(self): pass
"""

############################## get animation scene
animationScene1 = GetAnimationScene()
animationScene1.Cues.append(PythonAnimationCue1)
animationScene1.PlayMode = 'Sequence'
animationScene1.StartTime = 0
animationScene1.NumberOfFrames = len(vtkfiles) - 0

animationScene1.Play()
Last modified 9 months ago Last modified on 03/13/19 11:46:59

Attachments (1)

Download all attachments as: .zip