Hi Ross,

>>>>> "Ross" == rharder  <[EMAIL PROTECTED]> writes:

    Ross> Hi, I've been dying to start using Envisage and Mayavi2, but
    Ross> so far I've had the impression that I need a PhD in
    Ross> computers science instead of physics from the documentation.
    Ross> Are there any examples of simple Envisage apps that load 3D
    Ross> data, provide a set of buttons to do simple manipulations on
    Ross> it, then feed the results into Mayavi for visualization?  A
    Ross> great example would be something like an FFT app that
    Ross> performs a Fourier Transform at the touch of a button.

As a new year present and keeping in mind that I'm going to be too
busy for this all of next semester, I've written a simple example that
illustrates how you can contribute a view to mayavi.

MayaVi already allows a user to contribute to the list of extensions
that mayavi itself contributes to various extension points.  An
"extension point" is a mechanism by with plugins can be contributed
to.  These contributions are in the form of "extensions" -- this is
how you contribute menus, views (like the tree view of mayavi) etc.
Look in mayavi/examples/mayavi_custom_ui.py to see how you can
contribute a simple menu item to mayavi.  Read the documention in that
code to follow what is going on.

I've expanded on the mayavi_custom_ui.py code and am attaching three
files below -- m2_user_code.py, mayavi_custom_ui.py and
mayavi_custom_ui_no_app_obj.py. Put them all in your ~/.mayavi2/
directory.  mayavi_custom_ui_no_app_obj.py is not necessary but
perhaps handy to study later.

Read the m2_user_code.py file.  It is basically some silly code that
uses traits and creates some data and views it using mayavi.  It has a
small bit of envisage code to hook it up to mayavi.  You can feel free
to modify it and play with it.

Next, read the mayavi_custom_ui.py code.  It is very similar to the
mayavi_custom_ui.py inside "examples/" except that it instantiates the
'Worker' (yes, I dislike the name too) class using an
ApplicationObject and adds its view to MayaVi (actually to Envisage).
Thats pretty much it and as you can see, it is really not too
difficult.

mayavi_custom_ui_no_app_obj.py illustrates how to do this without
using an ApplicationObject and I do not recommend this.  I only send
it along as an example of how you can do this.  Diff the two versions
to see the essence of the difference.  Diffing the mayavi_custom_ui.py
in examples as compared to the one I attach will also be very
illustrative.

To create your own application would be somewhat similar.  For complex
examples see mayavi's mayavi_plugin_definition.py,
mayavi_ui_plugin_definitions, mayavi/app.py, mayavi/scripts/mayavi2.
For many simpler apps look at the following directories:

 1. enthought/src/apps/envisage/

 2. enthought/src/lib/enthought/developer/, specifically look at
    run.py, plugin_definitions.py, plugin_definition.py.

 3. enthought/src/lib/enthought/tvtk/examples/plugin/

These along with the code I'm sending should be enough for you to
figure things out.

Also read the docs here:

  https://svn.enthought.com/enthought/wiki/Envisage

  https://svn.enthought.com/enthought/wiki/EnvisageBestPractices


Thats all I have time for this year.  It would be great if my
ramblings above, the code and so on were put up on the Wiki for all to
read and change if needed.

Let me see if I can check a version of this code suitable for
inclusion into mayavi/examples -- hmm, maybe I'll do that.

HTH.

Happy new year!

cheers,
-- 
Prabhu Ramachandran                 http://www.aero.iitb.ac.in/~prabhu

# Author: Prabhu Ramachandran <prabhu_r at users dot sf dot net>
# Copyright (c) 2006-2007, Enthought, Inc.
# License: BSD Style.

# This code simulates something the user would like to do.  The code
# below is simply traits code with a few extra things to be able to
# grab the running mayavi instance and script it.  The envisage
# specific code only gets the application and the IMAYAVI service.

import numpy
import scipy

from enthought.traits.api import HasTraits, Range, Button, Instance, \
     View, Item
from enthought.envisage import get_application
from enthought.mayavi.services import IMAYAVI


######################################################################
# A test class.
class Worker(HasTraits):
    """This class basically allows you to create a data set, view it
    and modify the dataset.  This is a rather crude example but
    demonstrates how things can be done.

    """
    
    # Set by envisage if this is instantiated as an application
    # object.
    application = Instance  

    create_data = Button('Create data')
    reset_data = Button('Reset data')
    view_data = Button('View data')
    scale = Range(0.0, 1.0)
    source = Instance

    # Our UI view.
    view = View(Item('create_data', show_label=False),
                Item('view_data', show_label=False),
                Item('reset_data', show_label=False),
                Item('scale'),
                )

    def __init__(self, **traits):
        super(Worker, self).__init__(**traits)

    def get_mayavi(self):

        # This cruft exists to support both versions of the
        # customization code -- the one with application objects and
        # one without.
        if self.application is not None:
            app = self.application
        else: # When we are not instantiated using an ApplicationObject.
            # get_application() is deprecated!  So the moral of the
            # story is to have Worker instantiated using an
            # ApplicationObject.  In this case the 'application' trait
            # will be automatically setup for us.
            app = get_application()
        return app.get_service(IMAYAVI)

    def _make_data(self):
        dims = [64, 64, 64]
        np = dims[0]*dims[1]*dims[2]
        x, y, z = scipy.ogrid[-5:5:dims[0]*1j,-5:5:dims[1]*1j,-5:5:dims[2]*1j]
        x = x.astype('f')
        y = y.astype('f')
        z = z.astype('f')        
        s = (scipy.sin(x*y*z)/(x*y*z))
        s = s.transpose().copy() # This makes the data contiguous.
        return s
    
    def _create_data_fired(self):
        mayavi = self.get_mayavi()
        from enthought.mayavi.sources.array_source import ArraySource
        s = self._make_data()
        src = ArraySource(transpose_input_array=False, scalar_data=s)
        self.source = src
        mayavi.add_source(src)        

    def _reset_data_fired(self):
        self.source.scalar_data = self._make_data()

    def _view_data_fired(self):
        mayavi = self.get_mayavi()
        from enthought.mayavi.modules.outline import Outline
        from enthought.mayavi.modules.image_plane_widget import ImagePlaneWidget
        # Visualize the data.
        o = Outline()
        mayavi.add_module(o)
        ipw = ImagePlaneWidget()
        mayavi.add_module(ipw)
        ipw.module_manager.scalar_lut_manager.show_scalar_bar = True

        ipw_y = ImagePlaneWidget()
        mayavi.add_module(ipw_y)
        ipw_y.ipw.plane_orientation = 'y_axes'        
  
    def _scale_changed(self, value):
        src = self.source
        data = src.scalar_data
        data += value*0.01
        numpy.mod(data, 1.0, data)
        src.update()
"""This module allows us to extend the MayaVi2 UI.  It defines two
lists: `extensions` and `requires` as expected by the
`enthought.envisage.api.PluginDefinition` class.

`extensions` must be a list of plugin extension contributions that we
want to add.  `requires` specifies a list of plugins that we'd like to
have started.  The `requires` does not ensure that the plugin is
actually loaded but only ensures that the "required" plugins are
started (if loaded) before the mayavi2 ui plugin.  For most common
tasks it unlikely we will need to use a non-empty requires.

This file must be placed inside the `~/.mayavi2` directory.

Please note that `~/.mayavi2` is placed in `sys.path` so make sure
that you choose your module names carefully (so as not to override any
common module names).

"""
# Author: Prabhu Ramachandran <prabhu_r at users dot sf dot net>
# Copyright (c) 2006-2007, Enthought, Inc.
# License: BSD Style.

######################################################################
# The customization specific code that hooks the envisage app, mayavi
# and the users code together.
from enthought.envisage.workbench.action.action_plugin_definition import \
     Action, Location, WorkbenchActionSet
from enthought.envisage.workbench.workbench_plugin_definition import \
     Workbench, View
from enthought.envisage.core.core_plugin_definition import \
     ApplicationObject
from enthought.mayavi.action.common import WorkbenchAction, get_imayavi     

######################################################################
# Workbench actions.

class AddModuleManager(WorkbenchAction):
    """Adds a module manager to the tree.
    """
    def perform(self):
        """ Performs the action.
        """
        from enthought.mayavi.core.module_manager import ModuleManager
        mm = ModuleManager()
        mv = get_imayavi(self.window)        
        mv.add_module(mm)


######################################################################
# The extension items.

# The menu bar action extension item.
add_mm = Action(
    id            = "user.ModuleManager",
    class_name    = "mayavi_custom_ui.AddModuleManager",
    name          = "&User Defined ModuleManager",
    tooltip       = "Add a user defined ModuleManager to the current source",
    description   = "Add a user defined ModuleManager to the current source",
    locations = [Location(path="MenuBar/VisualizeMenu/additions"),]
)

# The action set collects all the actions, menus etc.  The id and name
# are not important but 
action_set = WorkbenchActionSet(id='user.mayavi2.action_set',
                                name='User.MayaVi2.ActionSet',
                                actions=[add_mm])

# An elegant way to publish an object for all envisagers to use via
# the UOL.
worker_app_obj = ApplicationObject(class_name='m2_user_code.Worker',
                                   uol='service://m2_user_code.Worker')

# Now add the view.
views = [View(name='Custom MayaVi2 View',
              id = 'm2_user_code.Worker',
              uol = 'service://m2_user_code.Worker',
              traits_ui_view = 'view',
              position = 'left')
         ]
workbench = Workbench(views=views)

######################################################################
# The all important extensions and requires.  These are injected into
# Envisage by the MayaVi2 UI plugin.
extensions = [worker_app_obj, action_set, workbench]
requires = []
"""This module allows us to extend the MayaVi2 UI.  It defines two
lists: `extensions` and `requires` as expected by the
`enthought.envisage.api.PluginDefinition` class.

`extensions` must be a list of plugin extension contributions that we
want to add.  `requires` specifies a list of plugins that we'd like to
have started.  The `requires` does not ensure that the plugin is
actually loaded but only ensures that the "required" plugins are
started (if loaded) before the mayavi2 ui plugin.  For most common
tasks it unlikely we will need to use a non-empty requires.

This file must be placed inside the `~/.mayavi2` directory.

Please note that `~/.mayavi2` is placed in `sys.path` so make sure
that you choose your module names carefully (so as not to override any
common module names).

"""
# Author: Prabhu Ramachandran <prabhu_r at users dot sf dot net>
# Copyright (c) 2006-2007, Enthought, Inc.
# License: BSD Style.

######################################################################
# The customization specific code that hooks the envisage app, mayavi
# and the users code together.
from enthought.envisage.workbench.action.action_plugin_definition import \
     Action, Location, WorkbenchActionSet
from enthought.envisage.workbench.workbench_plugin_definition import \
     Workbench, View
from enthought.mayavi.action.common import WorkbenchAction, get_imayavi     

######################################################################
# Workbench actions.

class AddModuleManager(WorkbenchAction):
    """Adds a module manager to the tree.
    """
    def perform(self):
        """ Performs the action.
        """
        from enthought.mayavi.core.module_manager import ModuleManager
        mm = ModuleManager()
        mv = get_imayavi(self.window)        
        mv.add_module(mm)


######################################################################
# The extension items.

# The menu bar action extension item.
add_mm = Action(
    id            = "user.ModuleManager",
    class_name    = "mayavi_custom_ui.AddModuleManager",
    name          = "&User Defined ModuleManager",
    tooltip       = "Add a user defined ModuleManager to the current source",
    description   = "Add a user defined ModuleManager to the current source",
    locations = [Location(path="MenuBar/VisualizeMenu/additions"),]
)

# The action set collects all the actions, menus etc.  The id and name
# are not important but 
action_set = WorkbenchActionSet(id='user.mayavi2.action_set',
                                name='User.MayaVi2.ActionSet',
                                actions=[add_mm])

# Instantiate the worker instance.
from m2_user_code import Worker
worker = Worker()

# Now add the view.
views = [View(name='Custom MayaVi2 View',
              id = 'mayavi_custom_ui.Worker',
              # The UOL will import the module (this one!) and get
              # hold of the instantiated Worker instance.  If you put
              # the code for the Worker class in another module, the
              # module name below will change.
              uol = 'import://mayavi_custom_ui.worker',
              traits_ui_view = 'view',
              position = 'left')
         ]
workbench = Workbench(views=views)

# In the above we instantiated the Worker instance.  If you want you
# can register this object automatically as a service by using an
# ApplicationObject.  For details on this look at the other
# implementation of this mayavi_custom_ui.py code or at
# mayavi_plugin_definition.py.  Please note that ApplicationObjects
# are highly recommended.  They allow others to communicate with your
# application objects through their UOL.  Also, if an application
# object (Worker) in this case has an 'application' trait then it is
# set to the running application -- this eliminates the need for a
# deprecated get_application() call.
              

######################################################################
# The all important extensions and requires.  These are injected into
# Envisage by the MayaVi2 UI plugin.
extensions = [action_set, workbench]
requires = []
-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys - and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
_______________________________________________
MayaVi-users mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/mayavi-users

Reply via email to