5

What I want to do is to update a mayavi plot in a loop. I want the updating of the plot to be done at a time specified by me (unlike, e.g., the animation decorator).

So an example piece of code I would like to get running is:

import time
import numpy as np
from mayavi import mlab

V = np.random.randn(20, 20, 20)
s = mlab.contour3d(V, contours=[0])

for i in range(5):

    time.sleep(1) # Here I'll be computing a new V

    V = np.random.randn(20, 20, 20)

    # Update the plot with the new information
    s.mlab_source.set(scalars=V)

However, this doesn't display a figure. If I include mlab.show() in the loop, then this steals the focus and doesn't allow the code to continue.

I feel what I should be using is a traits figure (e.g. this). I can follow the example traits application to run a figure which live-updates as I update the sliders. However, I can't get it to update when my code asks it to update; the focus now is 'stolen' by visualization.configure_traits().

Any pointers, or a link to appropriate documentation, would be appreciated.


EDIT

David Winchester's answer gets a step closer to the solution.

However, as I point out in the comments, I am not able to manipulate the figure with the mouse during the time.sleep() step. It is during this step that, in the full program, the computer will be busy computing the new value of V. During this time I would like to be able to manipulate the figure, rotating it with the mouse etc.

Bill Cheatham
  • 11,396
  • 17
  • 69
  • 104
  • In my latest comment you can simplify the code and manipulate the figure during the update without the `time.sleep()`. Did that work for you? The solution should be better than using `wx` since Mayavi is being ported to `qt` :o – PerroNoob Oct 20 '16 at 09:31

2 Answers2

4

I thin Mayavi uses generators to animate data. This is working for me:

import time
import numpy as np
from mayavi import mlab

f = mlab.figure()
V = np.random.randn(20, 20, 20)
s = mlab.contour3d(V, contours=[0])

@mlab.animate(delay=10)
def anim():
    i = 0
    while i < 5:
        time.sleep(1)
        s.mlab_source.set(scalars=np.random.randn(20, 20, 20))
        i += 1
        yield

anim()

I used this post as reference ( Animating a mayavi points3d plot )

Community
  • 1
  • 1
PerroNoob
  • 843
  • 2
  • 16
  • 36
  • Thanks, this is very close to what I want. I find though that during the `sleep` step I am not able to manipulate the figure. Do you also have this problem? And any solutions? – Bill Cheatham Oct 12 '16 at 15:09
  • You actually don't need the sleep since the delay is given in the decorator I think. Where exactly are you trying to manipulate the figure? – PerroNoob Oct 12 '16 at 16:25
  • By 'manipulate' I mean rotate the image with the mouse. The sleep step is designed to simulate my program doing some processing on the data. The idea is that I want the visualiser to show data during the execution of a slow program, which may only generate new results every 10 seconds or so. – Bill Cheatham Oct 13 '16 at 12:06
  • If you comment the `time.sleep(1)` line and change the decorator to `@mlab.animate(delay=1000, ui=False)` , I get the animation and I can actually manipulate the image while it is being updated. Is this what you needed? – PerroNoob Oct 13 '16 at 14:21
1

If you use the wx backend, you can call wx.Yield() periodically if you want to interact with your data during some long-running function. In the following example, wx.Yield() is called for every iteration of some "long running" function, animate_sleep. In this case, you could start the program with $ ipython --gui=wx <program_name.py>

import time
import numpy as np
from mayavi import mlab
import wx

V = np.random.randn(20, 20, 20)
f = mlab.figure()
s = mlab.contour3d(V, contours=[0])

def animate_sleep(x):
    n_steps = int(x / 0.01)
    for i in range(n_steps):
        time.sleep(0.01)
        wx.Yield()

for i in range(5):

    animate_sleep(1)

    V = np.random.randn(20, 20, 20)

    # Update the plot with the new information
    s.mlab_source.set(scalars=V)
eqzx
  • 5,323
  • 4
  • 37
  • 54