3

I am making a UI which involves embedding a Mayavi view in a wx frame with controls, and I'm running into some problems. To strip down the issue, I've put together a working script which is a combination of their wx embedding and red ball picker examples; my project is a more sophisticated version of this.

I have two questions:

  1. If the user selects a different number of balls, I'd like to clear the figure and re-draw with a new set of balls. However, from what I've gathered from googling, I'd need to reset the picker after the clf() call. The similar examples I've seen use the @on_trait_change decorator for the scene.activated trait, but I'm not sure how to do this when the scene is not activated, but merely updated.
  2. If the user selects a different ball color, I'd like to simply change the color in-place without re-creating the scene. It appears that I can do so by using the set method of the glyph's mlab_source, and I imagine that it would be best to call this using @on_trait_change. However, I don't know how to best connect the wx triggering event to a trait type that allows for @on_trait_change to be fired.

Thanks in advance.

P.S. I wanted to post this instead at the enthought mailing list but the site appears to be down and has been for some time. Anyone noticed the same?

braymp
  • 241
  • 2
  • 11
  • From: https://support.enthought.com/home -- > Yes, our mailman lists (enthought-dev, epd-users, etc) are down Sorry for the inconvenience; we are upgrading our servers. Most of our public support now is on stackoverflow, as described above, though we do plan to restore the mailman lists when the server upgrades are complete. – Jonathan March May 02 '14 at 20:32

1 Answers1

2

I'm not sure I understand what the problem is. To get your code working it seems like a simple matter of calling the scene in the wx notifiers (which you have a reference to) and making the necessary adjustments. Like so:

def on_number_of_balls_selected():
  n = self.get_selected_ball_number()
  clear_figure()
  #mlab.clf(scene = self.mayavi_view.scene.mayavi_scene )

  # make some new points
  new_points = somehow_make_some_new_points(n)
  mlab.points3d( new_points, scene=self.mayavi_view.scene.mayavi_scene )

  # reattach the picker
  picker = self.mayavi_view.figure.on_mouse_pick(self.mayavi_view.picker_callback)

and so on, these calls might not be put together quite right but this is the basic idea.

The solution is not conceptually different if you were using traitsui, but I'm curious why if you're going to use traitsui to render the mayavi scene, why not also use it to show the enums in the GUI? This is really the intended use case of traitsui (for simple applications). If you have a reason why not -- great, there are certainly many use cases where traitsui is not the best tool and working with the toolkit (or enaml which I haven't really given a fair try personally) gives you greater flexibility to control the layout and offer a broader array of widgets. But traitsui provides a slightly nicer solution to this problem of providing notifications for when the user changes some numbers in the GUI (though you stil have to write the listeners).

Edit: It turns out the tvtk picker detaches itself on mlab.clf (reasonable) and prevents new pickers listening to the same events from being reattached (not so reasonable). I believe this is a bug in tvtk, and I could not isolate it in 30 minutes. Therefore for now I suggest to avoid mlab.clf altogether (I have adjusted the code above to reflect this). Instead, call the remove method of each source module which will cause the source to delete itself from the scene:

def clear_figure(self):
  for child in self.scene.mayavi_scene.children:
    child.remove()

After that, the picker will be disconnected, but you can create the new objects and then reattach the picker to the new objects by calling on_mouse_pick as normally.

aestrivex
  • 5,170
  • 2
  • 27
  • 44
  • Unfortunately, this simple approach doesn't work. I've updated the script at the link above with your edits, but this problem with reattaching the picker after a clf() has been noted elsewhere (e.g., [here](http://enthought-dev.117412.n3.nabble.com/Picker-problems-in-Mayavi-td3173701.html) and [here](https://www.mail-archive.com/mayavi-users@lists.sourceforge.net/msg00596.html)). This is why I'm hoping to use a @on_trait_change approach since I've seen it suggested elsewhere but without code. – braymp May 08 '14 at 20:00
  • Re: use of wx vs. traitsui - My project is part of a larger pre-existing package which structures control UI elements with wx. I'm not wedded to wx, but I'm hoping to keep things consistent if possible. – braymp May 08 '14 at 20:02
  • Okay -- it seems like this is a weird behavior of pickers. I'll try to look at how pickers are handled in `mlab.clf` in a moment. But the answer to your second question should still be straightforward. Why do you need `on_trait_change` when you already have an event? You could set up an `Event` trait to listen to this event and then act as an intermediary, but why not just set the glyph's color trait? (which you don't need to use the trait's `set` method for, by the way, you can just use python assignment). – aestrivex May 08 '14 at 21:05
  • My reason is that I've been bitten by problems such as [here](http://enthought-dev.117412.n3.nabble.com/How-to-clear-AttributeError-NoneType-object-has-no-attribute-active-camera-td2181947.html), where the order of element activation comes into play. The developers recommend the `@on_trait_change` approach [here](http://docs.enthought.com/mayavi/mayavi/building_applications.html#making-the-visualization-live), under "Visualization objects and properties created before a scene is available". I'd like to make use of it to avoid similar mistakes later. – braymp May 12 '14 at 13:52
  • I clicked the first link, but the issue being discussed is that the `mlab.text` source is not its own module (it has nothing to do with `scene.activated`). Because the GUI is fully set up before the user interacts with the visualization, the activation of the underlying scene attributes (such as the light manager and picker) is not an issue and even if it were the modification of a glyph object should still work correctly. Direct modification of the glyph's traits is what you are supposed to do. – aestrivex May 12 '14 at 18:12
  • 1
    I did not come up with a good understanding of the picker's behavior -- I tried to look at the code where tvtk's picker object calls the underlying VTK picker to try to figure out what is going wrong, but it was dense and I would have to spend some significant time debugging it. For now I have updated my answer with a workaround. – aestrivex May 12 '14 at 18:14