在 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
附件