I am trying to dynamically modify the tube radius of a 3D line plot in Mayavi2. For example
from traits.api import HasTraits, Float, Instance, on_trait_change
from traitsui.api import View, Item, Group
from mayavi.core.api import PipelineBase
from mayavi.core.ui.api import MayaviScene, SceneEditor, MlabSceneModel
import numpy
def curve():
n_mer, n_long = 6, 11
pi = numpy.pi
dphi = pi / 1000.0
phi = numpy.arange(0.0, 2 * pi + 0.5 * dphi, dphi)
mu = phi * n_mer
x = numpy.cos(mu) * (1 + numpy.cos(n_long * mu / n_mer) * 0.5)
y = numpy.sin(mu) * (1 + numpy.cos(n_long * mu / n_mer) * 0.5)
z = numpy.sin(n_long * mu / n_mer) * 0.5
t = numpy.sin(mu)
return x, y, z, t
class MyModel(HasTraits):
radius = Float(0.025)
scene = Instance(MlabSceneModel, ())
plot = Instance(PipelineBase)
@on_trait_change('radius,scene.activated')
def update_plot(self):
x, y, z, t = curve()
if self.plot is None:
self.plot = self.scene.mlab.plot3d(x, y, z, t,
tube_radius=self.radius, colormap='Spectral')
else:
print self.radius
self.plot.mlab_source.set(tube_radius=self.radius)
self.scene.mlab.draw()
view = View(Item('scene', editor=SceneEditor(scene_class=MayaviScene),
height=250, width=300, show_label=False),
Group(
'radius',
),
resizable=True,
)
my_model = MyModel()
my_model.configure_traits()
This gives:
However, when I change the radius nothing happens with the visual line plot.
Don't use trait.set
or trait.reset
to set mayavi or vtk attributes. Indeed the MLineSource
that you are using doesn't have such an attribute, but it probably wouldn't work even if it did.
It's usually useful to find the mayavi attribute manually that controls this feature to see what mayavi object it is assigned to. In this case, going through the mayavi pipeline GUI shows that it is on the tube filter.
mlab.plot3d
is a helper function that tries to do everything for you and doesn't maintain a
reference to the filters used. But in general it is good practice to keep references to each step in the mayavi pipeline if you construct the pipeline yourself. That way you can easily access the mayavi object which controls this.
If you don't construct the pipeline yourself you can always get to it in the pipeline by manually navigating the tree of parent and child objects. In this case you can access it like so:
@on_trait_change('radius,scene.activated')
def update_plot(self):
x, y, z, t = curve()
if self.plot is None:
self.plot = self.scene.mlab.plot3d(x, y, z, t,
tube_radius=self.radius, colormap='Spectral')
else:
self.plot.parent.parent.filter.radius = self.radius