在 Traits GUI 中嵌入

日期2009-01-29(最后修改),2009-01-06(创建)

在 Traits 应用程序中嵌入 Matplotlib 图形

Traits 是 Enthought 工具套件 的一部分,它提供了一个很棒的框架,用于创建 GUI 应用程序,而无需使用通常连接 UI 和应用程序逻辑所需的许多样板代码。可以在 这里找到 Traits 的简要介绍。虽然 ETS 自带其自己的 Traits 感知绘图框架(Chaco),但如果您已经了解 matplotlib,那么嵌入它同样容易。Chaco 的优势(恕我直言)是其交互式“工具”,一个(正在开发中的)OpenGL 渲染后端和一个易于理解的代码库。但是,matplotlib 拥有更多更好的文档和更好的默认值;它可以正常工作。使 TraitsUI 和 matplotlib 能够很好地协同工作的关键是使用 mpl 面向对象的 API,而不是 pylab/pyplot。此示例需要以下软件包

  • numpy
  • wxPython
  • matplotlib
  • Traits > 3.0
  • TraitsGUI > 3.0
  • TraitsBackendWX > 3.0

在此示例中,我们将显示一个变量(x,一个 numpy ndarray)和一个参数(scale,一个带边界的浮点值)的函数(y,一个正弦波)。我们希望能够从 UI 中改变参数,并在绘图窗口中看到 y 的结果变化。以下是最终结果的样子: TraitsUI 的 "!CustomEditor" 可用于将任何 wxPython 窗口显示为对象的编辑器。您只需向 !CustomEditor 传递一个可调用对象,该对象在被调用时会返回您要显示的 wxPython 窗口。在本例中,我们的 !MakePlot() 函数返回一个包含 mpl !FigureCanvas 和导航工具栏的 wxPanel。此示例利用了 Traits 的一些功能。我们使用“动态初始化”来按需创建 Axes 和 Line2D 对象(使用 _xxx_default 方法)。我们使用 Traits 的“通知”在 x 或 y 数据发生变化时调用 update_line(...)。此外,y 数据被声明为一个依赖于“scale”参数和 x 数据的 Property 特性。然后,y 在需要时重新计算,无论何时“scale”或“x”发生变化。“cached_property”装饰器防止在依赖项*)#修改时重新计算 y。`

最后,在 redraw() 方法中有一些 wx-magic 来通过将实际绘制延迟 50 毫秒来限制重绘速率。这使用了 wx.!CallLater 类。这可以防止在拖动滑块时过度重绘,从而防止 UI 滞后。 这里 是完整的列表

在 [ ]
#!python
"""
A simple demonstration of embedding a matplotlib plot window in
a traits-application. The CustomEditor allow any wxPython window
to be used as an editor. The demo also illustrates Property traits,
which provide nice dependency-handling and dynamic initialisation, using
the _xxx_default(...) method.
"""
from enthought.traits.api import HasTraits, Instance, Range,\
                                Array, on_trait_change, Property,\
                                cached_property, Bool
from enthought.traits.ui.api import View, Item
from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg
from matplotlib.backends.backend_wx import NavigationToolbar2Wx
from matplotlib.figure import Figure
from matplotlib.axes import Axes
from matplotlib.lines import Line2D
from enthought.traits.ui.api import CustomEditor
import wx
import numpy
def MakePlot(parent, editor):
    """
    Builds the Canvas window for displaying the mpl-figure
    """
    fig = editor.object.figure
    panel = wx.Panel(parent, -1)
    canvas = FigureCanvasWxAgg(panel, -1, fig)
    toolbar = NavigationToolbar2Wx(canvas)
    toolbar.Realize()
    sizer = wx.BoxSizer(wx.VERTICAL)
    sizer.Add(canvas,1,wx.EXPAND|wx.ALL,1)
    sizer.Add(toolbar,0,wx.EXPAND|wx.ALL,1)
    panel.SetSizer(sizer)
    return panel
class PlotModel(HasTraits):
    """A Model for displaying a matplotlib figure"""
    #we need instances of a Figure, a Axes and a Line2D
    figure = Instance(Figure, ())
    axes = Instance(Axes)
    line = Instance(Line2D)
    _draw_pending = Bool(False) #a flag to throttle the redraw rate
    #a variable paremeter
    scale = Range(0.1,10.0)
    #an independent variable
    x = Array(value=numpy.linspace(-5,5,512))
    #a dependent variable
    y = Property(Array, depends_on=['scale','x'])
    traits_view = View(
                    Item('figure',
                         editor=CustomEditor(MakePlot),
                         resizable=True),
                    Item('scale'),
                    resizable=True
                    )
    def _axes_default(self):
        return self.figure.add_subplot(111)
    def _line_default(self):
        return self.axes.plot(self.x, self.y)[0]
    @cached_property
    def _get_y(self):
        return numpy.sin(self.scale * self.x)
    @on_trait_change("x, y")
    def update_line(self, obj, name, val):
        attr = {'x': "set_xdata", 'y': "set_ydata"}[name]
        getattr(self.line, attr)(val)
        self.redraw()
    def redraw(self):
        if self._draw_pending:
            return
        canvas = self.figure.canvas
        if canvas is None:
            return
        def _draw():
            canvas.draw()
            self._draw_pending = False
        wx.CallLater(50, _draw).Start()
        self._draw_pending = True
if __name__=="__main__":
    model = PlotModel(scale=2.0)
    model.configure_traits()

章节作者:未知[47],GaelVaroquaux

附件