This is an archival dump of old wiki content --- see scipy.org for current material.
Please see http://scipy-cookbook.readthedocs.org/

Embedding a Matplotlib Figure in a Traits App

Traits, part of theEnthought Tools Suit, provides a great framework for creating GUI Apps without a lot of the normal boilerplate required to connect the UI the rest of the application logic. A brief introduction to Traits can be found here. Although ETS comes with it's own traits-aware plotting framework (Chaco), if you already know matplotlib it is just as easy to embed this instead. The advantages of Chaco (IMHO) are its interactive "tools", an (in development) OpenGL rendering backend and an easy-to-understand codebase. However, matplotlib has more and better documentation and better defaults; it just works. The key to getting TraitsUI and matplotlib to play nice is to use the mpl object-oriented API, rather than pylab / pyplot. This recipe requires the following packages:

For this example, we will display a function (y, a sine wave) of one variable (x, a numpy ndarray) and one parameter (scale, a float value with bounds). We want to be able to vary the parameter from the UI and see the resulting changes to y in a plot window. Here's what the final result looks like: mpl_in_traits_view.png The TraitsUI "CustomEditor" can be used to display any wxPython window as the editor for the object. You simply pass the CustomEditor a callable which, when called, returns the wxPython window you want to display. In this case, our MakePlot() function returns a wxPanel containing the mpl FigureCanvas and Navigation toolbar. This example exploits a few of Traits' features. We use "dynamic initialisation" to create the Axes and Line2D objects on demand (using the _xxx_default methods). We use Traits "notification", to call update_line(...) whenever the x- or y-data is changed. Further, the y-data is declared as a Property trait which depends on both the 'scale' parameter and the x-data. 'y' is then recalculated on demand, whenever either 'scale' or 'x' change. The 'cached_property' decorator prevents recalculation of y if it's dependancies are not modified.

Finally, there's a bit of wx-magic in the redraw() method to limit the redraw rate by delaying the actual drawing by 50ms. This uses the wx.CallLater class. This prevents excessive redrawing as the slider is dragged, keeping the UI from lagging.Here's the full listing:

   1 """
   2 A simple demonstration of embedding a matplotlib plot window in
   3 a traits-application. The CustomEditor allow any wxPython window
   4 to be used as an editor. The demo also illustrates Property traits,
   5 which provide nice dependency-handling and dynamic initialisation, using
   6 the _xxx_default(...) method.
   7 """
   8 from enthought.traits.api import HasTraits, Instance, Range,\
   9                                 Array, on_trait_change, Property,\
  10                                 cached_property, Bool
  11 from enthought.traits.ui.api import View, Item
  12 from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg
  13 from matplotlib.backends.backend_wx import NavigationToolbar2Wx
  14 from matplotlib.figure import Figure
  15 from matplotlib.axes import Axes
  16 from matplotlib.lines import Line2D
  17 from enthought.traits.ui.api import CustomEditor
  18 import wx
  19 import numpy
  20 def MakePlot(parent, editor):
  21     """
  22     Builds the Canvas window for displaying the mpl-figure
  23     """
  24     fig = editor.object.figure
  25     panel = wx.Panel(parent, -1)
  26     canvas = FigureCanvasWxAgg(panel, -1, fig)
  27     toolbar = NavigationToolbar2Wx(canvas)
  28     toolbar.Realize()
  29     sizer = wx.BoxSizer(wx.VERTICAL)
  30     sizer.Add(canvas,1,wx.EXPAND|wx.ALL,1)
  31     sizer.Add(toolbar,0,wx.EXPAND|wx.ALL,1)
  32     panel.SetSizer(sizer)
  33     return panel
  34 class PlotModel(HasTraits):
  35     """A Model for displaying a matplotlib figure"""
  36     #we need instances of a Figure, a Axes and a Line2D
  37     figure = Instance(Figure, ())
  38     axes = Instance(Axes)
  39     line = Instance(Line2D)
  40     _draw_pending = Bool(False) #a flag to throttle the redraw rate
  41     #a variable paremeter
  42     scale = Range(0.1,10.0)
  43     #an independent variable
  44     x = Array(value=numpy.linspace(-5,5,512))
  45     #a dependent variable
  46     y = Property(Array, depends_on=['scale','x'])
  47     traits_view = View(
  48                     Item('figure',
  49                          editor=CustomEditor(MakePlot),
  50                          resizable=True),
  51                     Item('scale'),
  52                     resizable=True
  53                     )
  54     def _axes_default(self):
  55         return self.figure.add_subplot(111)
  56     def _line_default(self):
  57         return self.axes.plot(self.x, self.y)[0]
  58     @cached_property
  59     def _get_y(self):
  60         return numpy.sin(self.scale * self.x)
  61     @on_trait_change("x, y")
  62     def update_line(self, obj, name, val):
  63         attr = {'x': "set_xdata", 'y': "set_ydata"}[name]
  64         getattr(self.line, attr)(val)
  65         self.redraw()
  66     def redraw(self):
  67         if self._draw_pending:
  68             return
  69         canvas = self.figure.canvas
  70         if canvas is None:
  71             return
  72         def _draw():
  73             canvas.draw()
  74             self._draw_pending = False
  75         wx.CallLater(50, _draw).Start()
  76         self._draw_pending = True
  77 if __name__=="__main__":
  78     model = PlotModel(scale=2.0)
  79     model.configure_traits()

SciPy: Cookbook/EmbeddingInTraitsGUI (last edited 2015-10-24 17:48:26 by anonymous)