GUI Basics (Intro)


In [2]:
#%load ghello.py

In [3]:
# basic GUI Hello in Tkinter

from Tkinter import *

#make a root window
root = Tk()
root.title("Hello?")

# stick a label in it.
mylabel = Label(root, text="Is it me you're looking for?")

# pack it into the root window
mylabel.pack() # geometry manager

# run the main loop
root.mainloop()

Buttons!


In [5]:
#%load ghello1.py

In [76]:
# basic GUI Hello in Tkinter
from Tkinter import *

#make a root window
root = Tk() ; root.title("Hello?")

# stick a label in it and pack it in.
Label(root, text="Is it me you're looking for?").pack()

def good(): print "good."
def bad(): print "bad!"
    
# make some buttons
b1 = Button(root,text="Yes",command=good)
b2 = Button(root,text="No",command=bad)
b1.pack(side=LEFT,expand=1,fill=X) ; b2.pack(side=LEFT,fill=X,expand=1)


# run the main loop
root.mainloop()

Geometry Manager: Grid


In [8]:
#%load grid.py

In [4]:
# basic GUI Hello in Tkinter
from Tkinter import *

#make a root window
root = Tk() ; root.title("grid example")
root.minsize(120,50)
root.maxsize(700,500)


# stick a label in it and pack it in.
a = Label(root, text="A",borderwidth=4,bg="PeachPuff") # 'bg' = background color
b = Label(root, text="B",borderwidth=4,bg="LightBlue",relief=RIDGE)
c = Label(root, text="C",borderwidth=4,bg="PeachPuff",relief=GROOVE) # different styles
d = Label(root, text="D",borderwidth=4,bg="LightBlue")
e = Label(root, text="E",borderwidth=4,bg="PeachPuff",relief=GROOVE)
f = Label(root, text="F",borderwidth=4,bg="LightBlue")
g = Label(root, text="G",borderwidth=4,bg="Yellow")
h = Label(root, text="H",borderwidth=4,bg="PeachPuff",relief=SUNKEN)
i = Label(root, text="I",borderwidth=4,bg="LightBlue")
j = Label(root, text="J",borderwidth=4,bg="PeachPuff",padx=30,relief=GROOVE) # some padding
k = Label(root, text="K",borderwidth=4,bg="LightBlue",relief=GROOVE)

# Assign grid layouts
a.grid(row=0,column=0)
b.grid(row=0,column=1,sticky=(N,S,E,W))
c.grid(row=0,column=2,sticky=(N,S))
e.grid(row=1,column=0,sticky=(E,W))
f.grid(row=1,column=1,sticky=(E))
g.grid(row=1,column=2,sticky=(W))
h.grid(row=2,column=0,sticky=(N,S,W,E))
d.grid(row=0,column=3,sticky=(N,S,W,E),columnspan=2,rowspan=2)
i.grid(row=2,column=1,sticky=(N,S,W,E),columnspan=2)
j.grid(row=2,column=3,sticky=(N,S,W,E))
k.grid(row=2,column=4,sticky=(N,S,W,E),ipadx=30,ipady=30)

    
## get the gridsize and make each row and column expandable 
# weights = define how they get bigger or smaller
for r in range(root.grid_size()[0]):
    root.rowconfigure(r, weight=1)
for c in range(root.grid_size()[1]):
    root.columnconfigure(c, weight=1)

# run the main loop
root.mainloop()

Geometry Manager: Pack

  • Need to choose a single manager for each window (Pack or Grid or Place)
  • Checkbuttons

In [12]:
#%load pack.py

In [75]:
# basic GUI Hello in Tkinter
from Tkinter import *

#make a root window
root = Tk() ; root.title("pack example")

# stick a label in it and pack it in.
q = Button(root, text="Quit",borderwidth=4,bg="PeachPuff")
a = Checkbutton(root, text="A",borderwidth=4)
b = Checkbutton(root, text="B",borderwidth=4)
c = Checkbutton(root, text="C",borderwidth=4)
e = Label(root, text="What grade should I give you in this class?",borderwidth=4,bg="PeachPuff",relief=GROOVE)

e.pack(side=TOP,expand=1,fill=X) # Put this button at the top, fill entire width
q.pack(side=BOTTOM,expand=1,fill=BOTH)
a.pack(side=LEFT,expand=1)
b.pack(side=LEFT,expand=1)
c.pack(side=LEFT,expand=1)

# run the main loop
root.mainloop()

In [3]:
#%load pack_grid.py

In [25]:
# basic GUI Hello in Tkinter
from Tkinter import *

#make a root window
root = Tk() ; root.title("pack example (grid)")

# stick a label in it and pack it in.
q = Button(root, text="Quit",borderwidth=4,bg="PeachPuff")
a = Checkbutton(root, text="A",borderwidth=4)
b = Checkbutton(root, text="B",borderwidth=4)
c = Checkbutton(root, text="C",borderwidth=4)
e = Label(root, text="What grade should I give you in this class?",borderwidth=4,bg="PeachPuff",relief=GROOVE)

# e.pack(side=TOP,fill=X)
# q.pack(side=BOTTOM,expand=1,fill=X)
# a.pack(side=LEFT,expand=1)
# b.pack(side=LEFT,expand=1)
# c.pack(side=LEFT,expand=1)

e.grid(row=0, column=0, sticky=(N,E,W), columnspan=3)
q.grid(row=2, column=0, sticky=(S,E,W), columnspan=3)
a.grid(row=1, column=0)
b.grid(row=1, column=1)
c.grid(row=1, column=2)

#root.rowconfigure(0, weight=1)
#root.rowconfigure(1, weight=100)
#root.columnconfigure(1, weight=1)

# run the main loop
root.mainloop()

Mini Breakout!

Try to get the same gui layout as in the Pack example, but using Grid


In [16]:
# Breakout
from Tkinter import *

#make a root window
root = Tk() ; root.title("pack example")

# stick a label in it and pack it in.
q = Button(root, text="Quit",borderwidth=4,bg="PeachPuff")
a = Checkbutton(root, text="A",borderwidth=4)
b = Checkbutton(root, text="B",borderwidth=4)
c = Checkbutton(root, text="C",borderwidth=4)
e = Label(root, text="What grade should I give you in this class?",borderwidth=4,bg="PeachPuff",relief=GROOVE)

# Pack style
#e.pack(side=TOP,fill=X) # Put this button at the top, fill entire width
#q.pack(side=BOTTOM,expand=1,fill=X)
#a.pack(side=LEFT,expand=1)
#b.pack(side=LEFT,expand=1)
#c.pack(side=LEFT,expand=1)

# Grid Style
e.grid(row=0, column=0, sticky=(N,E,W), columnspan=3)
q.grid(row=2, column=0, sticky=(S,E,W), columnspan=3)
a.grid(row=1, column=0, sticky=(N))
b.grid(row=1, column=1, sticky=(N))
c.grid(row=1, column=2, sticky=(N))
    
## get the gridsize and make each row and column expandable 
# weights = define how they get bigger or smaller
for r in range(root.grid_size()[0]):
    root.rowconfigure(r, weight=1)
for c in range(root.grid_size()[1]):
    root.columnconfigure(c, weight=1)

# run the main loop
root.mainloop()

Events

  • real time updating

In [17]:
#%load events0.py

In [52]:
# basic events (1) GUI stuff
#   shows commands and Variables/textvaribles usage
# J. S. Bloom (2012) Python Seminar Class AY250

from Tkinter import *
import sys
root = Tk()
myvar = StringVar() # declare variable type
myvar.set("this is the first time I've set")

Entry(root, width=70, textvariable=myvar).pack() # input / entry widget (user enters text)
def changing(*args):
    print 'Arguments are:', args
    print 'Lenght is:', len(args), 'and type is:', type(args)
    print 'Type of 1:', type(args[0]), 'type of 2:', type(args[1]), 'type of 3:', type(args[2])
    print "new value for myvar:", myvar.get()
    sys.stdout.flush() # remove 1-lag behind in notebook

myvar.trace("w",changing) ; print 'Tkinter calls myvar:', myvar._name
myvar.set("bye.")

root.mainloop()


Tkinter calls myvar: PY_VAR14
Arguments are: ('PY_VAR14', '', 'w')
Lenght is: 3 and type is: <type 'tuple'>
Type of 1: <type 'str'> type of 2: <type 'str'> type of 3: <type 'str'>
new value for myvar: bye.
Arguments are: ('PY_VAR14', '', 'w')
Lenght is: 3 and type is: <type 'tuple'>
Type of 1: <type 'str'> type of 2: <type 'str'> type of 3: <type 'str'>
new value for myvar: bye
  • focus
  • key binding
  • enter exit window

In [23]:
#%load bind.py

In [54]:
# basic events binding GUI stuff
#   shows binding on a Canvas
# J. S. Bloom (2012) Python Seminar Class AY250

from Tkinter import *

def callback(event):
    print {"4": "Button", "7": "Enter", "2": "Key"}[event.type] + " event->",
    print (event.x,event.y,event.char,event.keysym,"button:",event.num)

root = Tk()
w=Canvas (root) ; w.pack() ; w.focus_set() # focus pulls attention to a specific window
callback_name  = w.bind("<Button-1>",callback)
callback_name2  = w.bind("<Enter>",callback)
callback_name4  = w.bind("<Key>",callback)

root.mainloop()


Enter event-> (366, 179, '??', '??', 'button:', '??')
Enter event-> (340, 168, '??', '??', 'button:', '??')
Button event-> (340, 168, '??', '??', 'button:', 1)
Enter event-> (364, 164, '??', '??', 'button:', '??')
Enter event-> (376, 129, '??', '??', 'button:', '??')
Enter event-> (288, 136, '??', '??', 'button:', '??')
Button event-> (288, 136, '??', '??', 'button:', 1)
Enter event-> (288, 136, '??', '??', 'button:', '??')
Button event-> (288, 136, '??', '??', 'button:', 1)
Key event-> (288, 136, '\r', 'Return', 'button:', '??')
Key event-> (288, 136, 'd', 'd', 'button:', '??')
Key event-> (288, 136, 'w', 'w', 'button:', '??')
Key event-> (288, 136, ' ', 'space', 'button:', '??')
Enter event-> (368, 136, '??', '??', 'button:', '??')
  • button state updating
  • task idling (idle)

In [25]:
#%load events.py

In [77]:
# basic events GUI stuff
#   shows commands and Variables/textvaribles usage
# quote of the day
# J. S. Bloom (2012) Python Seminar Class AY250

from Tkinter import *
import urllib2
import string 

#make a root window
root = Tk() ; root.title("event example")

# make a string variable
qt = StringVar()

# here are two callback function we'll reference later
def report_quote(*args):
    # qt will hold quote of the day
    print "Quote changed to:"
    print qt.get()
    
def show_quote(*args):
    # disable the quote button to avoid multiple clicks
    a.configure(state=DISABLED)
    a.update_idletasks()   # update right away, don't wait 
    
    # grab a new quote from the web
    qt.set(" ".join([string.replace(x,"&quot;","'",100) for x in urllib2.urlopen("http://www.iheartquotes.com/api/v1/random").readlines()[:-2]]))
    
    # set the button state back to normal (enabled) and update all the Event Loop Tasks
    a.configure(state=NORMAL) # make the button clickable again, once you're done grabbing the quote
    root.update()
    
# here we set up some widgets...note how we set 
# the textvariable parameter of the Label e to the StringVar qt
# whenever qt changes, so will the textvariable of this Label
e  = Label(root,height=15,width=65,justify=LEFT,\
          textvariable=qt,relief=SUNKEN)

# destroy() is a method of all widgets in Tk
q  = Button(root, text="Quit",command=root.destroy) # destroy the window
a  = Button(root, text="Get Quote",command=show_quote)

# set the initial variable and set a watch on qt's change
# 'w' is for generating an event on writing
# 'r' is for generating an event on reading of that variable
qt.set("Click 'Get Quote'") ; print 'qt is a StringVar named', qt._name
qt.trace("w",report_quote)

# pack in all the buttons
e.pack(side=TOP,fill=X,expand=1)
q.pack(side=LEFT,expand=10)
a.pack(side=LEFT,expand=1)

# run the main loop
root.mainloop()


qt is a StringVar named PY_VAR19

Main Breakout!

  • Make a "real-time" calculator, that automatically updates the output with the result of the entered expression as it is being typed, as soon as it is a valid expression

In [66]:
from Tkinter import *
import math # can use e and pi etc.

#make a root window
root = Tk()
root.title("Real Time Calculator")

# Create widgets
calc_output = Label(root, text="output here") # output to display the result
calc_input = StringVar() # input from user
calc_input.set('Type math here')

# Place widgets
calc_output.pack(side=TOP,expand=1,fill=X) # geometry manager
Entry(root, textvariable=calc_input).pack(side=TOP, expand=1, fill=X) # input below output

# Define call-back function
def calculate(*args):
    safe_eval = lambda expr: eval(expr, dict(__builtins__=None), vars(math)) # make sure expression is safe
    expression = calc_input.get()
    try:
        calc_output.configure(text=str(safe_eval(expression)))
    except ZeroDivisionError:
        calc_output.configure(text="Cannot divide by zero!")
    except:
        pass # some zero division errors?

# Monitor user's input
calc_input.trace("w",calculate) # monitor if user writes ("w"), and if so, call the calculate call-back function

# run the main loop
root.mainloop()

Traits


In [48]:
#%load traits1.py

In [60]:
try:
	from enthought.traits.api import HasTraits, Str, \
            Int, Directory, RGBColor, Float, Array, Enum
	from enthought.traits.ui.api import View, Item, Group
except:
	from traits.api import HasTraits, Str, \
            Int, Directory, RGBColor, Float, Array, Enum
	from traitsui.api import View, Item, Group	

class Bear(HasTraits):
    name = Str
    color = RGBColor("gold")
    weight = Float # must declare variable type, so can do validation
    location = Array()
    favorite_food = Enum("Honey","Turkey","PaloAltian",default="Honey")
    datadir = Directory("./")
    
yogi = Bear(name="Yogi",weight=34.0,location=(131.2,+31.1))
yogi.configure_traits()


Out[60]:
True
  • buttons in traits

In [51]:
#%load button.py

In [62]:
try:
	from enthought.traits import *
	from enthought.pyface.api import GUI
	from enthought.traits.api import HasTraits, Int, Button
	from enthought.traits.ui.api import View, Item, ButtonEditor
except:
	from traits import *
	#from pyface.api import GUI
	from traits.api import HasTraits, Int, Button
	from traitsui.api import View, Item, ButtonEditor	

class Counter(HasTraits):
    value =  Int()
    add_one = Button()
    def _add_one_fired(self): # notation: _variablename_fired -- function to call when button is "fired" (triggered)
        self.value +=1
    view = View('value', Item('add_one', show_label=False ))

#Counter().edit_traits()
#GUI().start_event_loop()
Counter().configure_traits()


Out[62]:
True
  • real time calculator with traits

In [54]:
#%load icalc.py

In [64]:
# useful Traits-based GUI instant calc
# J. S. Bloom (2012) Python Seminar Class AY250

try:
	from enthought.traits.api import HasTraits, Str, Float ; import math
except:
	from traits.api import HasTraits, Str, Float ; import math
	
seval = lambda expr: eval(expr, dict(__builtins__=None), vars(math))

class Calc(HasTraits):
    expression = Str
    rez        = Str("Type an expression")
    def _expression_changed(self, old, new):
            try:
                self.rez = str(seval(new))
            except:
                pass

c = Calc() ; c.configure_traits()


Out[64]:
True
  • now control the layout
  • views

In [59]:
#%load icalc1.py

In [65]:
# useful Traits-based GUI instant calc
# J. S. Bloom (2012) Python Seminar Class AY250

try:
  from enthought.traits.api import HasTraits, Str, Float ; import math
  from enthought.traits.ui.api import View, Group, Item
except:
  from traits.api import HasTraits, Str, Float ; import math
  from traitsui.api import View, Group, Item 
  
seval = lambda expr: eval(expr, dict(__builtins__=None), vars(math))

class Calc(HasTraits):
    expression = Str
    rez        = Str("Type an expression below")
    def _expression_changed(self, old, new):
            try:
                self.rez = str(seval(new))
            except:
                self.rez = ""
                
view1 = View(Item('rez',width=-250,resizable=True,padding=2,
                  label="Result",enabled_when="False",full_size=True),
             Item('expression', width=-250,resizable=True),
                  title='Instant Calc',resizable=True,
                  buttons=['OK'],scrollable=False)
                
c = Calc() ; c.configure_traits(view=view1)


Out[65]:
True

More Traits


In [61]:
#%load traits2.py

In [62]:
try:
    from enthought.traits.api import HasTraits, Str, \
            Int, Float, Enum,DelegatesTo,This,Instance
    from enthought.traits.ui.api import View, Item, Group
except:
    from traits.api import HasTraits, Str, \
            Int, Float, Enum,DelegatesTo,This,Instance
    from traitsui.api import View, Item, Group 
      
import sys

class Bear(HasTraits):
    first_name = Str
    weight = Float
    favorite_food = Enum("Honey","Turkey","PaloAltian",default="Honey")

class Parent(Bear):
    last_name = Str
    def _last_name_changed(self, old, new):
            print "Parent's last name changed to %s (was = '%s')." % (new,old)
            sys.stdout.flush()
            
class Cub(Bear):
    last_name  = DelegatesTo('father') # delegate out
    father = Instance(Parent)
    mother = Instance(Parent)
    
yogi  = Parent(first_name="Yogi",weight=34.0,last_name="Morgan")
sally = Parent(first_name="Sally",weight=30.0,last_name="Klein")
oski = Cub(first_name="Oski",weight=39.0,father=yogi,mother=sally)

oski.configure_traits()


Parent's last name changed to Morgan (was = '').
Parent's last name changed to Klein (was = '').
Parent's last name changed to G (was = 'Klein').
Parent's last name changed to Go (was = 'G').
Parent's last name changed to Gol (was = 'Go').
Parent's last name changed to Gold (was = 'Gol').
Parent's last name changed to Goldb (was = 'Gold').
Parent's last name changed to Goldbe (was = 'Goldb').
Parent's last name changed to Goldber (was = 'Goldbe').
Parent's last name changed to Goldberg (was = 'Goldber').
Parent's last name changed to t (was = 'Morgan').
Parent's last name changed to ta (was = 't').
Parent's last name changed to tao (was = 'ta').
Parent's last name changed to ta (was = 'tao').
Parent's last name changed to tac (was = 'ta').
Parent's last name changed to taco (was = 'tac').
Parent's last name changed to tac (was = 'taco').
Parent's last name changed to tao (was = 'tac').
Parent's last name changed to ta (was = 'tao').
Parent's last name changed to t (was = 'ta').
Parent's last name changed to Morgan (was = 't').
Out[62]:
True

matplotlib widgets

slider demo


In [63]:
#%load slider_demo.py

In [69]:
from pylab import *
from matplotlib.widgets import Slider, Button, RadioButtons

ax = subplot(111)
subplots_adjust(left=0.25, bottom=0.25)
t = arange(0.0, 1.0, 0.001)
a0 = 5
f0 = 3
s = a0*sin(2*pi*f0*t)
l, = plot(t,s, lw=2, color='red')
axis([0, 1, -10, 10])

axcolor = 'lightgoldenrodyellow'
axfreq = axes([0.25, 0.1, 0.65, 0.03], axisbg=axcolor)
axamp  = axes([0.25, 0.15, 0.65, 0.03], axisbg=axcolor)

sfreq = Slider(axfreq, 'Freq', 0.1, 30.0, valinit=f0)
samp = Slider(axamp, 'Amp', 0.1, 10.0, valinit=a0)

def update(val):
    amp = samp.val
    freq = sfreq.val
    l.set_ydata(amp*sin(2*pi*freq*t))
    draw()
sfreq.on_changed(update)
samp.on_changed(update)

resetax = axes([0.8, 0.025, 0.1, 0.04])
button = Button(resetax, 'Reset', color=axcolor, hovercolor='0.975')
def reset(event):
    sfreq.reset()
    samp.reset()
button.on_clicked(reset)

rax = axes([0.025, 0.5, 0.15, 0.15], axisbg=axcolor)
radio = RadioButtons(rax, ('red', 'blue', 'green'), active=0)
def colorfunc(label):
    l.set_color(label)
    draw()
radio.on_clicked(colorfunc)

show()

In [1]:
#%load mpl_figure_editor.py

In [66]:
import wx

import matplotlib
# We want matplotlib to use a wxPython backend
matplotlib.use('WXAgg')
from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas
from matplotlib.figure import Figure
from matplotlib.backends.backend_wx import NavigationToolbar2Wx

try:
    from enthought.traits.api import Any, Instance
    from enthought.traits.ui.wx.editor import Editor
    from enthought.traits.ui.wx.basic_editor_factory import BasicEditorFactory
except:
    from traits.api import Any, Instance
    from traitsui.wx.editor import Editor
    from traitsui.wx.basic_editor_factory import BasicEditorFactory

class _MPLFigureEditor(Editor):

    scrollable  = True

    def init(self, parent):
        self.control = self._create_canvas(parent)
        self.set_tooltip()
        
    def update_editor(self):
        pass

    def _create_canvas(self, parent):
        """ Create the MPL canvas. """
        # The panel lets us add additional controls.
        panel = wx.Panel(parent, -1, style=wx.CLIP_CHILDREN)
        sizer = wx.BoxSizer(wx.VERTICAL)
        panel.SetSizer(sizer)
        # matplotlib commands to create a canvas
        mpl_control = FigureCanvas(panel, -1, self.value)
        sizer.Add(mpl_control, 1, wx.LEFT | wx.TOP | wx.GROW)
        toolbar = NavigationToolbar2Wx(mpl_control)
        sizer.Add(toolbar, 0, wx.EXPAND)
        self.value.canvas.SetMinSize((10,10))
        return panel

class MPLFigureEditor(BasicEditorFactory):

    klass = _MPLFigureEditor


if __name__ == "__main__":
    # Create a window to demo the editor
    from enthought.traits.api import HasTraits
    from enthought.traits.ui.api import View, Item
    from numpy import sin, cos, linspace, pi

    class Test(HasTraits):

        figure = Instance(Figure, ())

        view = View(Item('figure', editor=MPLFigureEditor(),
                                show_label=False),
                        width=400,
                        height=300,
                        resizable=True)

        def __init__(self):
            super(Test, self).__init__()
            axes = self.figure.add_subplot(111)
            t = linspace(0, 2*pi, 200)
            axes.plot(sin(t)*(1+0.5*cos(11*t)), cos(t)*(1+0.5*cos(11*t)))

    Test().configure_traits()


---------------------------------------------------------------------------
ImportError                               Traceback (most recent call last)
<ipython-input-66-418e07e83d7a> in <module>()
----> 1 import wx
      2 
      3 import matplotlib
      4 # We want matplotlib to use a wxPython backend
      5 matplotlib.use('WXAgg')

ImportError: No module named wx

In [2]:
#%load mpl.py

In [67]:
try:
  from enthought.traits.api import HasTraits, Str, Float, Instance; import math
  from enthought.traits.ui.api import View, Item, ButtonEditor
except:
  from traits.api import HasTraits, Str, Float, Instance; import math
  from traitsui.api import View, Item, ButtonEditor

from matplotlib.figure import Figure

from mpl_figure_editor import MPLFigureEditor
import numpy as np

class Test(HasTraits):

  figure = Instance(Figure, ())

  view = View(Item('figure', editor=MPLFigureEditor(),
                                show_label=False),
                        width=400,
                        height=300,
                        resizable=True)
  def __init__(self):
     super(Test, self).__init__()
     axes = self.figure.add_subplot(111)
     t = np.linspace(0, 2*np.pi, 200)
     axes.plot(np.sin(t)*(1+0.5*np.cos(11*t)), np.cos(t)*(1+0.5*np.cos(11*t)))

t = Test()
t.configure_traits()


---------------------------------------------------------------------------
ImportError                               Traceback (most recent call last)
<ipython-input-67-c43276811fe7> in <module>()
      8 from matplotlib.figure import Figure
      9 
---> 10 from mpl_figure_editor import MPLFigureEditor
     11 import numpy as np
     12 

ImportError: No module named mpl_figure_editor

In [5]:
#%load tmpl.py

In [68]:
from mpl_figure_editor import MPLFigureEditor

# do pip install wx
import wx
 
import matplotlib
# We want matplotlib to use a wxPython backend
matplotlib.use('WxAgg')
from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas
from matplotlib.figure import Figure
from matplotlib.backends.backend_wx import NavigationToolbar2Wx

try:
    from enthought.traits.api import Any, Instance

    from enthought.traits.api import HasTraits
    from enthought.traits.ui.api import View, Item
except:
    from traits.api import Any, Instance
    from traits.api import HasTraits
    from traitsui.api import View, Item

from numpy import sin, cos, linspace, pi

class Test(HasTraits):

        figure = Instance(Figure, ())

	view = View(Item('figure', editor=MPLFigureEditor(),
                                show_label=False),
                        width=400,
                        height=300,
                        resizable=True)

        def __init__(self):
            super(Test, self).__init__()
            axes = self.figure.add_subplot(111)
            t = linspace(0, 2*pi, 200)
            axes.plot(sin(t)*(1+0.5*cos(11*t)), cos(t)*(1+0.5*cos(11*t)))

Test().configure_traits()


---------------------------------------------------------------------------
ImportError                               Traceback (most recent call last)
<ipython-input-68-152526bfae24> in <module>()
----> 1 from mpl_figure_editor import MPLFigureEditor
      2 
      3 # do pip install wx
      4 import wx
      5 

ImportError: No module named mpl_figure_editor