使用Mayavi以交互方式进行3d绘图的简单方法?

时间:2017-11-01 20:30:13

标签: python matplotlib 3d mayavi

阅读Mayavi的文档" http://docs.enthought.com/mayavi/mayavi/building_applications.html"让我真的很困惑。

我的问题是,如果我只是想要一个允许用户互动的3d图,例如,拖动滑块并更改图的内容,我就 来使用Traits , 对?通过文档,标准程序类似于:

class visual(HasTraits):
    scene = ...
    view = View(...)
    @on_trait_change(...)
    def do_something()
        ...

我不知道什么是特质。我甚至不理解在构造函数之外定义的类中的属性(它是' trait'?)。

回到最初的问题,如果我只想要一个可以改变的3d情节,为什么我不直接这样做?一个工作的例子如下:

import numpy as np
from mayavi import mlab
from matplotlib import pyplot as plt
from matplotlib.widgets import Slider


def slider_changed(val):
    s.mlab_source.scalars = np.asarray(x * (val + 1), 'd')

# mayavi 3d plot
x, y = np.mgrid[0:3:1,0:3:1]
s = mlab.surf(x, y, np.asarray(x*0.1, 'd'))

# a matplotlib slider
plt.figure()
ax = plt.subplot(1, 1, 1)
slider = Slider(ax, valmin=0., valmax=1., label='test')
slider.on_changed(slider_changed)

plt.show()
mlab.show()

如果我不关心嵌入应用程序中的3d图,这对我来说似乎是一种更简单的方法吗? 3d绘图的许多属性可通过mlab_source的属性进行操作。我在这里使用matplotlib滑块作为示例,但它似乎可以是pyqt UI或其他任何东西。

然而,文档说

  

管道和管道对象的所有不同属性都表示为Traits,即可以在对话框中显示的特殊属性,以及在修改它们时触发回调。特别是这意味着当修改可视化对象时,场景可以自动更新。

这是否意味着如果我想要自动更新的内容,我必须按照上述方式使用Traits?

1 个答案:

答案 0 :(得分:2)

理解特征可能是一个良好的开端this article。我们在这里讨论的那些特征是developped by Enthough。值得注意的是,还有其他一些称为特征的对象/概念,它与使用mayavi相关的东西完全无关。

  

我不必使用Traits,对吧?

在调用s.mlab_source.scalars = np.asarray(x * (val + 1), 'd')使用Traits。 Mayavi仅因为您更改基础数据而更新情节的事实是使用Traits的结果。

Mayavi只使用这些特征,而不是通常的对象。所以一旦你使用mayavi,你就不可避免地会使用特征。

  

这是否意味着如果我想要自动更新的东西,我必须按照上面描述的方式使用Traits?

不,你自己给了反例。您不必子类HasTraits来更新绘图。您可以使用您能想到的任何其他解决方案。但是,一旦你想将mayavi场景嵌入到GUI中,按照文档说明的方式进行操作可能是个好主意。

另外,子类化HasTraits实际上是一种非常简洁的方式来轻松获得交互式图形。所以问题的例子看起来像

import numpy as np
from mayavi import mlab

from traits.api import HasTraits, Range, Instance,on_trait_change
from traitsui.api import View, Item, Group
from mayavi.core.ui.api import MayaviScene, SceneEditor, MlabSceneModel

x, y = np.mgrid[0:3:1,0:3:1]

class MyModel(HasTraits):
    slider    = Range(-5., 5., 0.5, )    
    scene = Instance(MlabSceneModel, ())

    def __init__(self):
        HasTraits.__init__(self)
        self.s = mlab.surf(x, y, np.asarray(x*1.5, 'd'), figure=self.scene.mayavi_scene)

    @on_trait_change('slider')
    def slider_changed(self):
        self.s.mlab_source.scalars = np.asarray(x * (self.slider + 1), 'd')

    view = View(Item('scene', editor=SceneEditor(scene_class=MayaviScene)),
                Group("slider"))

my_model = MyModel()
my_model.configure_traits()

enter image description here

这里要注意的好处是你实际上没有定义一个显式的回调(即没有on_slider_change或类似的)。