Vedo: Animate different actors one at the time

Created on 17 Jun 2019  路  10Comments  路  Source: marcomusy/vedo

Hi guys. First of all, thank you so much for developing vtkPlotter. I have been a VTK user (C++ and Python) for many years now and I found amazing what can be achieved using vtkPlotter with only a few lines of code.

Here is what I am working on. I have a time sequence of an object (closed mesh) with 32 timepoints. I want to animate the movement and deformation of this object in time. Usually I would export each timepoint as a vtk polydata file, open the sequence of files in paraview and play it. However, I want to do that in vtkPlotter if possible. The code bellow is my very first attempt -- no animation so far. Could you guys help me to improve it? I can help to turn this into an official example if you think it might be of interest of others. Thanks a lot,

n = 8
vp = Plotter()
coo = np.random.rand(n*12).reshape(n,12)
for i in range(n):
    u = coo[i,3:6]
    v = coo[i,6:9]
    q = coo[i,9:12]
    ell = Ellipsoid(pos=(2.5*coo[i,0], 2.5*coo[i,1], 2.5*coo[i,2]), axis1=u, axis2=v, axis3=q)
    scals = [i] * ell.N()
    ell.pointColors(scals, vmin=0, vmax=n)
    ell.VisibilityOff()
    vp += ell
vp.show()
bug help wanted

All 10 comments

Hi @vianamp
thanks for your interest!
Actually the show() command should be inside the loop. Check out for example this:

from vtkplotter import *
import numpy as np

vp = Plotter(interactive=False)
coo = np.random.rand(32*12).reshape(32,12)

for i in range(len(coo)):
    u = coo[i,3:6]
    v = coo[i,6:9]
    q = coo[i,9:12]
    ell = Ellipsoid(pos=(2.5*coo[i,0], 2.5*coo[i,1], 2.5*coo[i,2]),
                    axis1=u, axis2=v, axis3=q)
    scals = [i] * ell.N()
    ell.pointColors(scals, vmin=0, vmax=31)
    vp += ell
    vp.show()

interactive()

ezgif com-optimize

Let me know if you need more help. Also, you can find more examples of animations in example/simulations directory which may fit your need.

Thanks for quick reply. What if I need only one timepoint to be shown at the time? And also to keep the bounding box fixed at the largest size that fits all the objects?

Also, I got this error when I tried to run your code on a jupyter notebook:

AttributeError                            Traceback (most recent call last)
<ipython-input-12-4b069e1c07cd> in <module>()
     13     vp.show()
     14 
---> 15 interactive()

~/anaconda3/envs/qcb/lib/python3.6/site-packages/vtkplotter/plotter.py in interactive()
    259     if settings.plotter_instance:
    260         if hasattr(settings.plotter_instance, 'interactor'):
--> 261             settings.plotter_instance.interactor.Start()
    262     return settings.plotter_instance
    263 

AttributeError: 'NoneType' object has no attribute 'Start'

There are 2 ways of doing it:

  • either you create an invisible box that contains the object that you want to create afterwards or
  • render the scene once outside the loop with e.g. vp.show(world, ell, resetcam=False)
from vtkplotter import *
import numpy as np

vp = Plotter(interactive=False)
coo = np.random.rand(32*12).reshape(32,12)
world = Box([1,1,1], 5,5,5).wireframe().alpha(0) ##########

for i in range(len(coo)):
    u = coo[i,3:6]
    v = coo[i,6:9]
    q = coo[i,9:12]
    ell = Ellipsoid(pos=(2.5*coo[i,0], 2.5*coo[i,1], 2.5*coo[i,2]),
                    axis1=u, axis2=v, axis3=q)
    scals = [i] * ell.N()
    ell.pointColors(scals, vmin=0, vmax=31)
    vp.show(world, ell)

interactive()

About the jupyter thing indeed this a current limitation (or ... bug) due to how the K3D backend works...
One needs to collect the object returned by show() and then just expose it outside the loop...

image

I see what you mean. My final code looks like this:

np.random.seed(1234)
n = 8
vp = Plotter(interactive=False)
coo = np.random.rand(n*12).reshape(n,12)
world = Box([1,1,1], 5,5,5).wireframe().alpha(0)
for i in range(n):
    u = coo[i,3:6]
    v = coo[i,6:9]
    q = coo[i,9:12]
    ell = Ellipsoid(pos=(2.5*coo[i,0], 2.5*coo[i,1], 2.5*coo[i,2]), axis1=u, axis2=v, axis3=q)
    scals = [i] * ell.N()
    ell.pointColors(scals, vmin=0, vmax=n)
    vp += ell
    plt = vp.show(world, ell, resetcam=False)
plt

However, I don't actually see the animation. Only the last timepoint is shown.

Yes.. the jupyter functionality is still experimental and at the moment is not working well with loops.
It' s on my to-do list..
If you need to work in notebooks you still have the option of setting:

from vtkplotter import *
embedWindow(False)

then the normal vtk rendering window will pop up.

How to fix the viewing angle to the first frame. The object moves a little bit in the following gif.

Thanks~
@marcomusy

you can either add an invisible box:
vp += Box((1,1,1), length=5, width=5, height=5).wireframe().alpha(0)
or avoid resetting the camera later with
vp.show(resetcam=False)

in the ex. above, as the the object are added randomly, the first solution is probably the best.

Hi, marcomusy~

How to add a description for each frame like: "frame: {}/{}.format(current, all)"?

If I set by txt = Text(...) with background, it seems to get slower and slower, if I use vp.clear(txt), there will be flashes.

@LogWell
thanks for spotting the problem, I'll investigate that.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

hmralavi picture hmralavi  路  7Comments

RubendeBruin picture RubendeBruin  路  3Comments

CMengich picture CMengich  路  5Comments

kemo993 picture kemo993  路  6Comments

m-albert picture m-albert  路  7Comments