Draw a color cube in Mayavi
Today I want to tell you about what Mayavi is and what
Mayavi is a cross-platform application for visualization of scientific data (and not only). Distributed under the BSD license, which allows its use in commercial applications.

What can?
- Build 2D and 3D models based on scalar / vector data
- Open VTK, PLOT3D files
- Save render results in various graphic formats
- May even render MRI (Magnetic Resonance Imaging) results
There are three ways to work with it:
1) Work directly in the Mayavi interface.
2) Upload / transfer ready-made data to Mayavi.
3) Write a python script in which you can set for Mayavi all the desired features.
After launching the stand-alone version, we get such a nice window: The

screen is divided into 4 parts:
- The upper left part stores objects
- In the lower left part the properties of objects are changed
- In the upper right there is a render
- In the lower right corner is the terminal
Let me explain what the terminal is for:
Create some object and select it in the list of objects. Select and, without releasing the left mouse button, drag it into the terminal window. We will get something like
Now let's write:
explore(_)and then a window with all the parameters of the object will appear. This is a very useful thing that can help in learning and creating your own scripts. I learned some properties of objects in this way, not finding in the documentation. In this window, the Drag'N'Drop rule works similarly.

There are many ( examples ) in the Mayavi documentation that generally explain what and how to do.
I will try to describe the rake that I stepped on. For the most part, they will relate to embedding the Mayavi frame in the PyQt widget (well, or PySide, which is already aboutwrote .
- Do not read the documentation from pdf files. True, do not read. A waste of time.
- Do not replace class constructors out of habit. Create some methods to which variables / objects will be passed, which are then used for rendering in the update_plot () functions.
- Try to pinpoint what you want to see. TVTK classes may not support the functions that mlab classes have (for example, Volume).
- When working with numpy arrays, cast them to float32 type, as by default, a 64-bit system creates a float64 array that Mayavi will not work with.
- Let me give you one example of building a regular cube with embedding it in the PyQT widget.
- # To embed in PyQt4 widget, you need to set the ETS_TOOLKIT variable to qt4.
- import os
- os.environ ['ETS_TOOLKIT'] = 'qt4'
- from PySide import QtGui, QtCore
- from enthought.mayavi import mlab
- from enthought.tvtk.api import tvtk
- from enthought.tvtk.pyface.api import Scene
- from numpy import arange, nonzero, float32, min, max, median, copy, random, shape
- from numpy.core.numeric import ravel
- from enthought.traits.api import HasTraits, Instance, on_trait_change, \
- Int, dict
- from enthought.traits.ui.api import View, Item
- from enthought.mayavi.core.ui.api import MayaviScene, MlabSceneModel, \
- Sceneeditor
- #The actual visualization
- class Visualization (HasTraits):
- scene = Instance (MlabSceneModel, ())
- view = View (Item ('scene',
- editor = SceneEditor (scene_class = MayaviScene),
- # Instead of MayaviScene, you can write just Scene
- # and then we get a clean window without a toolbar.
- height = 250,
- width = 300,
- show_label = False),
- resizable = True
- )
- needUpdate = None
- def takePlotParametres (self, grid):
- self.grid = grid
- # The clf () method clears the current scene. It CANNOT be called in the update_plot () method
- self.scene.mlab.clf ()
- self.needUpdate = True
- self.update_plot ()
- @on_trait_change ('scene.activated')
- def update_plot (self):
- # This method is called for rendering.
- # Everything that needs to be drawn is written here and nowhere else
- # While there is no data, we will draw the standard model
- if not self.needUpdate:
- self.scene.mlab.test_points3d ()
- else:
- # Here we write all our rice cookers
- # Everything that is rendered via mlab needs to be called
- # like self.scene.mlab. *, otherwise the Mayavi window gets out of control
- # and starts to draw everything in a separate window.
- # opacity greatly affects rendering performance!
- surf = self.scene.mlab.pipeline.surface (self.grid, opacity = 1)
- # You can also display the internal grid by uncommenting the lines
- #edges = mlab.pipeline.extract_edges (surf)
- #edgesSurf = mlab.pipeline.surface (edges)
- # edgesSurf.actor.property.interpolation = 'flat'
- # We remove the interpolation of the color of the surface of the cube. Let each cell be seen clearly.
- surf.actor.property.interpolation = 'flat'
- self.scene.mlab.orientation_axes ()
- self.scene.background = (0, 0, 0)
- self.scene.mlab.colorbar (orientation = 'vertical')
- ####################################################### #################################
- # Widget in which to embed the scene. We use it as a regular PyQt widget.
- class MayaviQWidget (QtGui.QWidget):
- def __init __ (self, parent = None):
- QtGui.QWidget .__ init __ (self, parent)
- layout = QtGui.QVBoxLayout (self)
- layout.setMargin (0)
- layout.setSpacing (0)
- self.visualization = Visualization ()
- # Ideally, this is where you can call the takePlotParametres method with the initial data, but this is not necessary
- # self.visualization.takePlotParametres ()
- # The edit_traits method generates the window in which the scene is built.
- # This window needs to be made Qt'sh, for which we call the .control method
- self.ui = self.visualization.edit_traits (parent = self,
- kind = 'subpanel'). control
- layout.addWidget (self.ui)
- self.ui.setParent (self)
- def create_cube (self):
- grid = self.createGrid ()
- self.visualization.takePlotParametres (grid)
- def createGrid (self):
- x, y, z = (10, 10, 10)
- # Create a grid for our cube
- grid = tvtk.RectilinearGrid ()
- # It is important to cast data to float32, as on a 64-bit OS, numpy creates float64 by default,
- # and Mayavi does not know how to work with it.
- # Create random data
- scalars = float32 (random.random ((x * y * z)))
- # scalars is the value that will be stored in each cell of our cube.
- # It is on this value that the surface color of the cells is determined
- grid.point_data.scalars = scalars
- grid.point_data.scalars.name = 'scalars'
- grid.dimensions = (x, y, z)
- grid.x_coordinates = float32 (arange (x))
- grid.y_coordinates = float32 (arange (y))
- grid.z_coordinates = float32 (arange (z))
- return grid
- if __name__ == "__main__":
- # It’s important not to create a new application, but to use something
- # which Mayavi creates automatically, otherwise you will hit all Traits signals / slots,
- # and we just don’t need it.
- # To get the link, call the instance () method.
- # Do not write out of habit QtGui.QApplication (sys.argv) .instance (),
- # I already stepped on this rake.
- app = QtGui.QApplication.instance ()
- container = QtGui.QWidget ()
- container.setWindowTitle ("Hello Habrahabr!")
- layout = QtGui.QVBoxLayout (container)
- mayavi_widget = MayaviQWidget ()
- button = QtGui.QPushButton ('Create cube')
- button.clicked.connect (mayavi_widget.create_cube)
- layout.addWidget (mayavi_widget)
- layout.addWidget (button)
- container.show ()
- app.exec_ ()
We start and get this window:

Click the button and get a colored cube:

If you want to see something more scientific, you can take a look at this:

Well, you can also create something futuristic (inside one box with internal faces turned on):

On this I complete my topic. If you want to see something else, then I am waiting for comments.
PS A little later I will write a topic about Chaco. I hope you are just as interested in reading about him?