Mayavi Cookbook
=================

These are a collection of useful hints and recipes for various tasks.


Animating a visualization
--------------------------

.. currentmodule:: enthought.mayavi.mlab

Often users like to animate a visualization without affecting the
interactive capabilities of the view.  For example you may want to
rotate the camera continuously, take a snapshot while continuing to
interact with the Mayavi UI.  To do this one can use the very convenient
:func:`animate` decorator provided with Mayavi.  Here is a simple
example::

    from enthought.mayavi import mlab
    @mlab.animate
    def anim():
        f = mlab.gcf()
        while 1:
            f.scene.camera.azimuth(10)
            f.scene.render()
            yield
    
    a = anim() # Starts the animation.

Notice the use of ``yield`` in the above, this is *very* crucial to this
working.  This example will continuously rotate the camera without
affecting the UI's interactivity.  It also pops up a little UI that lets
you start and stop the animation and change the time interval between
calls to your function.  For more specialized use you can pass arguments
to the decorator::

    from enthought.mayavi import mlab
    @mlab.animate(delay=500, ui=False)
    def anim():
        # ...
    
    a = anim() # Starts the animation without a UI.

Note that if you don't want to import all of ``mlab``, the animate
decorator is available from::

    from enthought.mayavi.tools.animator import animate

For more details check the documentation of the :func:`animate`
decorator available in the :ref:`mlab-reference`.


Animating a series of images
-----------------------------

Lets say you have a stack of PNG or JPEG files that are numbered
serially that you want to animate on a mayavi scene.  Here is a simple
script (called ``img_movie.py``)::
    
    # img_movie.py
    from enthought.pyface.timer.api import Timer

    def animate(src, N=10):
        for j in range(N):
            for i in range(len(src.file_list)):
                src.timestep = i
                yield

    if __name__ == '__main__':
        src = mayavi.engine.scenes[0].children[0]
        animator = animate(src)
        t = Timer(250, animator.next)

The ``Timer`` class lets you call a function without blocking the
running user interface.  The first argument is the time after which the
function is to be called again in milliseconds.  The ``animate``
function is a generator and changes the timestep of the source.  This
script will animate the stack of images 10 times.  The script animates
the first data source by default.  This may be changed easily.

To use this script do this::
    
    $ mayavi2 -d your_image000.png -m ImageActor -x img_movie.py


Making movies from a stack of images
-------------------------------------

This isn't really related to mayavi but is a useful trick nonetheless.
Lets say you generate a stack of images using mayavi say of the form
``anim%03d.png`` (i.e. ``anim000.png``, ``anim001.png`` and so on), you
can make this into a movie.  If you have ``mencoder`` installed try
this::

  $ mencoder "mf://anim%03d.png" -mf fps=10 -o anim.avi \
    -ovc lavc -lavcopts vcodec=msmpeg4v2:vbitrate=500

If you have ffmpeg installed you may try this::

  $ ffmpeg -f image2 -r 10 -i anim%03d.png -sameq anim.mov -pass 2

.. _mencoder: http://www.mplayerhq.hu/
.. _ffmpeg: http://ffmpeg.mplayerhq.hu/


Scripting from the command line
--------------------------------

The mayavi application allows for very powerful
:ref:`command-line-arguments` that lets you build a complex
visualization from your shell.  What follow is a bunch of simple
examples illustrating these.

The following example creates a ``ParametricSurface`` source and then
visualizes glyphs on its surface colored red::

    $ mayavi2 -d ParametricSurface -m Glyph \
    -s"glyph.glyph.scale_factor=0.1" \
    -s"glyph.color_mode='no_coloring'" \
    -s"actor.property.color = (1,0,0)"

Note that ``-s"string"`` applies the string on the last object (also
available as ``last_obj``), which is the glyph. 

This example turns off coloring of the glyph and changes the glyph to
display::

    $ mayavi2 -d ParametricSurface -m Glyph\
    -s"glyph.glyph.scale_factor=0.1" \
    -s"glyph.color_mode='no_coloring'" \
    -s"glyph.glyph_source.glyph_source = last_obj.glyph.glyph_source.glyph_list[-1]"

Note the use of ``last_obj`` in the above.


Texture mapping actors
-----------------------

Here is a simple example showing how to texture map an iso-surface with
the data that ships with the mayavi sources (the data files are in the
examples directory)::

    $ mayavi2 -d examples/tvtk/images/masonry.jpg \
     -d examples/mayavi/data/heart.vti \
     -m IsoSurface \
     -s"actor.mapper.scalar_visibility=False" \
     -s"actor.enable_texture=True"\
     -s"actor.tcoord_generator_mode='cylinder'"\
     -s"actor.texture_source_object=script.engine.current_scene.children[0]"

It should be relatively straightforward to change this example to use a
``ParametricSurface`` instead and any other image of your choice.
Notice how the texture image (``masonry.jpg``) is set in the last line
of the above.  The image reader is the first child of the current scene
and we set it as the ``texture_source_object`` of the isosurface actor.


Shifting data and plotting
---------------------------

Sometimes you need to shift/transform your input data in space and
visualize that in addition to the original data.  This is useful when
you'd like to do different things to the same data and see them on the
same plot.  This can be done with Mayavi using the ``TransformData`` filter
for ``StructuredGrid``, ``PolyData`` and ``UnstructuredGrid`` datasets.
Here is an example using the ``ParametricSurface`` data source::

   $ mayavi2 -d ParametricSurface \
     -m Outline -m Surface \
     -f TransformData -s "transform.translate(1,1,1)" \
     -s "widget.set_transform(last_obj.transform)" \
     -m Outline -m Surface

If you have an ``ImageData`` dataset then you can change the origin,
spacing and extents alone by using the ``ImageChangeInformation``
filter.  Here is a simple example with the standard mayavi image data::

    $ mayavi2 -d examples/mayavi/data/heart.vti -m Outline \
    -m ImagePlaneWidget \
    -f ImageChangeInformation \ 
    -s "filter.origin_translation=(20,20,20)" \
    -m Outline -m ImagePlaneWidget


Using the ``UserDefined`` filter
---------------------------------

The ``UserDefined`` filter in mayavi lets you wrap around existing VTK
filters easily.  Here are a few examples::

    $ mayavi2 -d ParametricSurface -s "function='dini'" \
    -f UserDefined:GeometryFilter \
    -s "filter.extent_clipping=True" \
    -s "filter.extent = [-1,1,-1,1,0,5]" \
    -f UserDefined:CleanPolyData \
    -m Surface \
    -s "actor.property.representation = 'p'" \
    -s "actor.property.point_size=2"

This one uses a ``tvtk.GeometryFilter`` to perform extent based clipping of
the parametric surface generated.  Note the specification of the ``-f
UserDefined:GeometryFilter``.  This data is then cleaned using the
``tvtk.CleanPolyData`` filter.

