Search code examples
pythonuser-interfacevisualizationmayavimayavi.mlab

Mayavi multiple scene selector


I need to load multiple scenes with option to switch them. Something like on the image: Image scheme

For button "1" something like mlab.points3d(x1, y1, z1, s1, color=blue)

For button "2" something like mlab.points3d(x2, y2, z2, s2, color=red)

For button "3" something like mlab.points3d(x3, y3, z3, s3, color=green)

How to manage drawing inside another scene? (I suppose that mlab.points3d should be done before option to switch between scenes). And how to define buttons for scheme switching?


Solution

  • Here is an example of how to embed a mayavi plot within pyqt with several buttons. It is based on the Qt embedding example from the mayavi website. If you want to write a relatively large application I would advise you to move the code that is now at the bottom under the if main == "main" line into several seperate classes.

    from pyface.qt import QtGui, QtCore
    from traits.api import HasTraits, Instance, on_trait_change
    from traitsui.api import View, Item
    from mayavi.core.ui.api import MayaviScene, MlabSceneModel, \
            SceneEditor
    
    
    ################################################################################
    #The actual visualization
    class Visualization(HasTraits):
        scene = Instance(MlabSceneModel, ())
    
    
        @on_trait_change('scene.activated')
        def update_plot(self):
            # This function is called when the view is opened. We don't
            # populate the scene when the view is not yet open, as some
            # VTK features require a GLContext.
    
            # We can do normal mlab calls on the embedded scene.
            self.scene.mlab.clf()
            self.scene.mlab.test_points3d()
    
        def second_plot(self):
            self.scene.mlab.clf()
    
            from numpy import sin, cos, mgrid, pi, sqrt
            u, v = mgrid[- 0.035:pi:0.01, - 0.035:pi:0.01]
    
            X = 2 / 3. * (cos(u) * cos(2 * v)
                    + sqrt(2) * sin(u) * cos(v)) * cos(u) / (sqrt(2) -
                                                             sin(2 * u) * sin(3 * v))
            Y = 2 / 3. * (cos(u) * sin(2 * v) -
                    sqrt(2) * sin(u) * sin(v)) * cos(u) / (sqrt(2)
                    - sin(2 * u) * sin(3 * v))
            Z = -sqrt(2) * cos(u) * cos(u) / (sqrt(2) - sin(2 * u) * sin(3 * v))
            S = sin(u)
    
            self.scene.mlab.mesh(X, Y, Z, scalars=S, colormap='YlGnBu', )
    
        def third_plot(self):
            self.scene.mlab.clf()
            self.scene.mlab.test_plot3d()
    
        # the layout of the dialog screated
        view = View(Item('scene', editor=SceneEditor(scene_class=MayaviScene),
                         height=250, width=300, show_label=False),
                    resizable=True # We need this to resize with the parent widget
                    )
    
    
    ################################################################################
    # The QWidget containing the visualization, this is pure PyQt4 code.
    class MayaviQWidget(QtGui.QWidget):
        def __init__(self, parent=None):
            QtGui.QWidget.__init__(self, parent)
            layout = QtGui.QVBoxLayout(self)
            layout.setContentsMargins(0,0,0,0)
            layout.setSpacing(0)
            self.visualization = Visualization()
    
            # The edit_traits call will generate the widget to embed.
            self.ui = self.visualization.edit_traits(parent=self,
                                                     kind='subpanel').control
            layout.addWidget(self.ui)
            self.ui.setParent(self)
    
    
    if __name__ == "__main__":
        # Don't create a new QApplication, it would unhook the Events
        # set by Traits on the existing QApplication. Simply use the
        # '.instance()' method to retrieve the existing one.
        app = QtGui.QApplication.instance()
        container = QtGui.QWidget()
    
        mayavi_widget = MayaviQWidget(container)
    
        container.setWindowTitle("Embedding Mayavi in a PyQt4 Application")
        # define a "complex" layout to test the behaviour
        layout = QtGui.QHBoxLayout(container)
    
        button_container = QtGui.QWidget()
        button_layout =  QtGui.QVBoxLayout(button_container)
    
        button1 = QtGui.QPushButton('1')
        button1.clicked.connect(mayavi_widget.visualization.update_plot)
        button_layout.addWidget(button1)
    
        button2 = QtGui.QPushButton('2')
        button2.clicked.connect(mayavi_widget.visualization.second_plot)
        button_layout.addWidget(button2)
    
        button3 = QtGui.QPushButton('3')
        button3.clicked.connect(mayavi_widget.visualization.third_plot)
        button_layout.addWidget(button3)
    
        layout.addWidget(button_container)
        button_container.show()
    
        layout.addWidget(mayavi_widget)
        container.show()
        window = QtGui.QMainWindow()
        window.setCentralWidget(container)
        window.show()
    
        # Start the main event loop.
        app.exec_()