pythonanimationsurfacemayavi

I can't animate a surface with Mayavi


I'm trying to do a simple animation of a surface with Mayavi, but due to the lack of online examples (the few are extremely unclear or not useful) and official documentation, I'm struggling a lot. I wrote a very simple code to show where I've gone so far

import numpy as np
from mayavi import mlab
import time

#Meshgrid + u + Surface

x = np.arange(0,1,0.1)
y = np.arange(0,1,0.1)
X,Y = np.meshgrid(x,y)
u = np.ones((10,10))
surf = mlab.mesh(X,Y,u)

#Surface animation

@mlab.animate(delay=1000)
def anim():
    for n in range(1,10):
        global u
        print(n)

        u = u+1
        surf.mlab_source.scalars = u
        yield
anim()
mlab.show()

So very simple, every iteration I pass from a 10x10 matrix of ones to a 10x10 matrix of twos and so on.

The problems I've encountered are 3

I really can't get my head around, it's weeks I'm trying, hope somebody helps. Thanks in advance.

Edit:

I tried to extend @E.Klahn code in a case resembling more mine

import numpy as np
from mayavi import mlab

s = 0.01
x = np.arange(0,1,0.1)
y = np.arange(0,1,0.1)
X,Y = np.meshgrid(x,y)
Z = np.ones((10,10))

m = mlab.mesh(X, Y, Z)

@mlab.animate(delay=20)
def anim():
     for i in range(1,100):
         m.mlab_source.z = np.ones((10,10))*s*i
         yield

 anim()
 mlab.show()

But I obtain only a flat surface going up, not a tridimensional object evolving, such as in his code.

Edit2:

Here the working code just copying the example of @E.Klahn, which I thank very very much

import numpy as np
from mayavi import mlab

x = np.arange(0,1,0.1)
y = np.arange(0,1,0.1)
X,Y = np.meshgrid(x,y)
X,Y=X.T,Y.T            #seems an important command
u = np.ones((10,10))
surf = mlab.surf(X,Y,u)

@mlab.animate(delay=500)
def anim():
    for n in range(1,10):
        print(n)

        surf.mlab_source.scalars = 1+np.sin(X)*np.sin(Y)*np.sin(n)
        yield
anim()
mlab.show()

I just print it to give continuity to code above and to spot the differences.


Solution

  • Here I've shown the code to plot a cube and animate it so that it grows out from a height of 0.01 to a height of 1 using mlab.mesh. What yield does is that it returns control to the decorator so that the scene can be updated.

    import numpy as np
    from mayavi import mlab
    
    s = 0.01
    X = np.array([[0,0,1,1],[0,0,1,1],[0,0,0,0],[1,1,1,1]])
    Y = np.array([[0,1,1,0],[0,1,1,0],[1,0,0,1],[1,0,0,1]])
    Z = np.array([[0,0,0,0],[s,s,s,s],[0,0,s,s],[0,0,s,s]])
    
    m = mlab.mesh(X, Y, Z)
    
    @mlab.animate(delay=20)
    def anim():
        for i in range(1,101):
            print(i, end='\r')
            m.mlab_source.z = np.array([[0,0,0,0],[s*i,s*i,s*i,s*i],[0,0,s*i,s*i],[0,0,s*i,s*i]])
            yield
    
    anim()
    mlab.show()
    

    scalars is one way to access the underlying data structure if that data structure has the scalars attribute. However, for mesh that attribute is not used, rather you want to access z and set those values. I would not know what your specific issue with u if unless there is a traceback to work from. The same with yield - I see no reason why that keyword would stop the animation at any particular step.

    The code below shows, instead of a box evolving over time, a surface evolving with time.

    import numpy as np
    from mayavi import mlab
    
    def evolving_function(X, Y, t, Lx=1, Ly=1):
        
        return np.sin(X+Lx*t)*np.sin(Y+Ly*t)
    
    Lx, Ly = 1,2
    
    x = np.linspace(-10,10,100)
    y = np.linspace(-10,10,100)
    X,Y = np.meshgrid(x,y)
    X, Y = X.T, Y.T
    s = evolving_function(X, Y, 0, Lx=Lx, Ly=Ly)
    
    m = mlab.surf(X, Y, s)
    
    dt = 50
    t = 10
    steps = int(10*1000/dt)
    
    @mlab.animate(delay=dt)
    def anim():
         for i in range(1,steps):
             m.mlab_source.scalars = evolving_function(X, Y, dt*i, Lx=Lx, Ly=Ly)
             yield
    
    anim()
    mlab.show()