Python Tutorial Ets Tutorial
Python Tutorial Ets Tutorial
ETS
1 / 73
Intended Audience Use Python to build interactive desktop applications Goal: Successful participants will be able to Start using Enthought Tool Suite (ETS) to build non-trivial applications
ETS
2 / 73
Introduction
Outline
1
Introduction ODE 101 Traits TraitsUI Chaco Mayavi Putting it all together Note on Envisage Summary
Prabhu and Pankaj (Enthought) ETS 3 / 73
2 3 4 5 6 7 8
Introduction
ETS
4 / 73
Introduction
Approach
A graphical explorer for ODEs from the ground up Support arbitrary 2 and 3 dimensional systems Using ETS
ETS
5 / 73
Introduction
Why?
ETS
6 / 73
Introduction
ODE 101
Outline
1
Introduction ODE 101 Traits TraitsUI Chaco Mayavi Putting it all together Note on Envisage Summary
Prabhu and Pankaj (Enthought) ETS 7 / 73
2 3 4 5 6 7 8
Introduction
ODE 101
ODE 101
Used to model many systems
Physics, astronomy Geology (weather modeling) Chemistry (reactions) Biology Ecology/population modeling Economics (stock trends, interest rates etc.)
ETS
8 / 73
Introduction
ODE 101
Simple equation
(1)
ETS
9 / 73
Introduction
ODE 101
Introduction
ODE 101
ETS
11 / 73
Introduction
ODE 101
Result
ETS
12 / 73
Species the evolution of the system Think: Velocity of a particle in 3D Lets trace its path
Solution
import numpy as np from scipy.integrate import odeint def lorenz(r, t s=10.,r=28., b=8./3.): x, y, z = r u = s*(y-x) v = r*x -y - x*z w = x*y - b*z return np.array([u, v, w]) start = (10., 50., 50.) t = np.linspace(0., 50., 2000) r = odeint(lorenz, start, t) x, y, z = r[:,0], r[:,1], r[:,2] mlab.plot3d(x, y, z, t, from mayavi import mlab tube_radius=None)
Introduction
ODE 101
Now what?
ETS
16 / 73
Introduction
ODE 101
Miscellaneous libraries
ETS
17 / 73
Traits
Outline
1
Introduction ODE 101 Traits TraitsUI Chaco Mayavi Putting it all together Note on Envisage Summary
Prabhu and Pankaj (Enthought) ETS 18 / 73
2 3 4 5 6 7 8
Traits
Introduction to Traits
ETS
19 / 73
Traits
Trait features
Initialization: default value Validation: strongly typed Delegation: value delegation Notication: events Visualization: MVC, automatic GUI!
ETS
20 / 73
Traits Example
from traits.api import (Delegate, HasTraits, Instance, Int, Str) class Parent(HasTraits): # INITIALIZATION: last_name initialized to last_name = Str() class Child(HasTraits): age = Int # VALIDATION: father must be Parent instance father = Instance(Parent) # DELEGATION: last_name delegated to fathers last_name = Delegate(father) # NOTIFICATION: Method called when age changes def _age_changed(self, old, new): print Age changed from %s to %s % (old, new)
Traits Example
from traits.api import (Delegate, HasTraits, Instance, Int, Str) class Parent(HasTraits): # INITIALIZATION: last_name initialized to last_name = Str() class Child(HasTraits): age = Int # VALIDATION: father must be Parent instance father = Instance(Parent) # DELEGATION: last_name delegated to fathers last_name = Delegate(father) # NOTIFICATION: Method called when age changes def _age_changed(self, old, new): print Age changed from %s to %s % (old, new)
Traits Example
In In In In []: []: []: []: joe = Parent() joe.last_name = Johnson moe = Child() moe.father = joe
In []: moe.last_name # Delegation Out[]: "Johnson" In []: moe.age = 10 # Notification Age changed from 0 to 10 In []: moe.configure_traits() # Visualization
10 m
@on_trait_change(extended.trait[].name)
Dynamic:
obj.on_trait_change(handler, [extended.trait[].name])
Notication Example
class Parent(HasTraits): last_name = Str() class Child(HasTraits): age = Int father = Instance(Parent) def _age_changed(self, old, new): print Age changed from %s to %s % (old, new) @on_trait_change(father.last_name) def _dad_name_updated(self): print self.father.last_name def handler(obj, name, old, new): print obj, name, old, new c = Child(father=Parent(last_name=Ram)) c.on_trait_change(handler, [father, age])
Notication Example
class Parent(HasTraits): last_name = Str() class Child(HasTraits): age = Int father = Instance(Parent) def _age_changed(self, old, new): print Age changed from %s to %s % (old, new) @on_trait_change(father.last_name) def _dad_name_updated(self): print self.father.last_name def handler(obj, name, old, new): print obj, name, old, new c = Child(father=Parent(last_name=Ram)) c.on_trait_change(handler, [father, age])
Traits
Think!
ETS
26 / 73
Traits
Think!
ETS
26 / 73
Traits
Object model
A class to represent the equation and parameters A class for the ODE solution Make sure it works TDD
ETS
27 / 73
Lorenz Equation
import numpy as np from traits.api import HasTraits, Float class s r b LorenzEquation(HasTraits): = Float(10) = Float(28) = Float(8./3)
def eval(self, X, t): x, y, z = X[0], X[1], X[2] u = self.s*(y-x) v = self.r*x - y - x*z w = x*y - self.b*z return np.array([u, v, w])
Or . . .
from traits.api import HasTraits, Range, # ... class LorenzEquation(HasTraits): # ... s = Range(0.0, 20.0, 10.0, desc=the parameter s) r = Range(0.0, 50.0, 28.0) b = Range(0.0, 10.0, 8./3) # ...
Testing
class TestLorenzEquation(unittest.TestCase): def setUp(self): self.ode = LorenzEquation() self.solver = ODESolver(ode=self.ode) self.solver.initial_state = [10.,50.,50.] self.solver.t = numpy.linspace(0, 10, 1001) def test_eval(self): dX = self.ode.eval(self.solver.initial_state, 0.0) self.assertAlmostEqual(dX[0], 400) self.assertAlmostEqual(dX[1], -270) self.assertAlmostEqual(dX[2], 1100/3.) def test_solve(self): soln = self.solver.solution[1,:] self.assertAlmostEqual(soln[0], 13.65484958) self.assertAlmostEqual(soln[1], 46.64090341) self.assertAlmostEqual(soln[2], 54.35797299)
Exercise
Solve an ODE Use the given skeleton code of the ODE equation (solve_ode.py) and the solver. Put them together to get a solution. Print the nal solution.
TraitsUI
Outline
1
Introduction ODE 101 Traits TraitsUI Chaco Mayavi Putting it all together Note on Envisage Summary
Prabhu and Pankaj (Enthought) ETS 35 / 73
2 3 4 5 6 7 8
TraitsUI
TraitsUI
Implement MVC design pattern Create default views for models Keep multiple views synced with model Create UI with minimal toolkit knowledge
ETS
36 / 73
configure_traits()
Sync with model Sync between different views
configure_traits()
Sync with model Sync between different views
Simplest view
MVC?
from traitsui.api import View, Item class LorenzEquation(ODE): # ... view = View(Item(s), Item(r), Item(b)) eq = LorenzEquation() eq.configure_traits(view=view)
title: Title of the view kind: modal, live, livemodal resizable width, height buttons: OK, Cancel and other buttons id: persists view
. . . and a lot more
Groups
Exercise
Customize the view for Lorenz equation Use the existing solve_ode.py le and setup the views for one or more of the classes (as many as you are able).
Chaco
Outline
1
Introduction ODE 101 Traits TraitsUI Chaco Mayavi Putting it all together Note on Envisage Summary
Prabhu and Pankaj (Enthought) ETS 45 / 73
2 3 4 5 6 7 8
Chaco
Chaco
2D plotting library Embeddable in any wx/Qt application Fast and interactive visualizations Integrates well with Traits and TraitsUI Easily extensible to create new types of plots and interactions
ETS
46 / 73
Chaco
ETS
47 / 73
Chaco
Core Ideas
Plots are compositions of visual components Separation between data and screen space Modular design and extensible classes
ETS
48 / 73
Chaco
ETS
49 / 73
class ODEPlot(HasTraits): ... traits_view = View( Item(plot, editor=ComponentEditor(), show_label=False), resizable=True, title="ODE Solution") def _plot_default(self): self.pd.set_data(index, self.solver.t) # Set the first array as value array for plot. self.pd.set_data(value, self.solver.solution[:,0]) plot = Plot(self.pd) plot.plot((index, value)) return plot
We can make the plot react to changes to the solution (changing initial condition etc.)
class ODEPlot(HasTraits): ... @on_trait_change(solver.solution) def _on_soln_changed(self): self.pd.set_data(index, self.solver.t) self.pd.set_data(value, self.solver.solution[:, 0])
Mayavi
Outline
1
Introduction ODE 101 Traits TraitsUI Chaco Mayavi Putting it all together Note on Envisage Summary
Prabhu and Pankaj (Enthought) ETS 57 / 73
2 3 4 5 6 7 8
Mayavi
Mayavi
ETS
58 / 73
A simple plot
1D data
from numpy import * t = linspace(0, 2*pi, 50) u = cos(t)*pi x, y, z = sin(u), cos(u), sin(t)
>>> mlab.plot3d(x, y, z, t)
>>> mlab.clf()
IPython is your friend!
>>> mlab.points3d?
Extra argument: Scalars Keyword arguments UI
>>> mlab.clf()
IPython is your friend!
>>> mlab.points3d?
Extra argument: Scalars Keyword arguments UI
Embedding a 3D plot
from mayavi.core.ui.api import MayaviScene, \ MlabSceneModel, SceneEditor class Plot3D(HasTraits): scene = Instance(MlabSceneModel, args=()) view = View(Item(name=scene, editor=SceneEditor( scene_class=MayaviScene), show_label=False, resizable=True, height=500, width=500), resizable=True) @on_trait_change(scene.activated) def generate_data(self): # Create some data X, Y = mgrid[-2:2:100j, -2:2:100j] R = 10*sqrt(X**2 + Y**2) Z = sin(R)/R self.scene.mlab.surf(X,Y,Z,colormap=gist_earth)
Embedding a 3D plot
from mayavi.core.ui.api import MayaviScene, \ MlabSceneModel, SceneEditor class Plot3D(HasTraits): scene = Instance(MlabSceneModel, args=()) view = View(Item(name=scene, editor=SceneEditor( scene_class=MayaviScene), show_label=False, resizable=True, height=500, width=500), resizable=True) @on_trait_change(scene.activated) def generate_data(self): # Create some data X, Y = mgrid[-2:2:100j, -2:2:100j] R = 10*sqrt(X**2 + Y**2) Z = sin(R)/R self.scene.mlab.surf(X,Y,Z,colormap=gist_earth)
Exercise
Add a slider to the UI Add a Range slider to the above example to change the R = 10*sqrt(X**2 + Y**2) to R = self.factor*sqrt(X**2 + Y**2) such that the factor can be adjusted.
Solution
from traits.api import Range # <-class Plot3D(HasTraits): scene = Instance(MlabSceneModel, args=()) factor = Range(0.0, 20.0, 10.0) # <-view = View(Item(name=scene, # ... ), Item(name=factor), # <-resizable=True) @on_trait_change(scene.activated, factor) # <-def generate_data(self): # ...
Outline
1
Introduction ODE 101 Traits TraitsUI Chaco Mayavi Putting it all together Note on Envisage Summary
Prabhu and Pankaj (Enthought) ETS 64 / 73
2 3 4 5 6 7 8
The application
ETS
65 / 73
Exercise
ODE application Given the existing code, in solve_ode.py and embed_3d_ex.py create a UI for the Lorenz equation along with the solver and a 3D or 2D plot.
So what?
Focus on the object model Solve the actual problem Model separation Easy to wire-up UI is mostly declarative
ETS
67 / 73
What next?
Note on Envisage
Outline
1
Introduction ODE 101 Traits TraitsUI Chaco Mayavi Putting it all together Note on Envisage Summary
Prabhu and Pankaj (Enthought) ETS 69 / 73
2 3 4 5 6 7 8
Note on Envisage
Envisage
Extensible framework
ETS
70 / 73
Note on Envisage
Application frameworks . . .
Central idea Developer focuses on making a clean library Framework API species how different pieces of the app interact Plugin writer exposes the library or objects involved into the framework Application writer uses plugins to create new application easily
ETS
71 / 73
Note on Envisage
Application frameworks . . .
Matplotlib library TVTK wxPython Shell MPL Plugin
TVTK Plugin
Framework
Code editor
LIBRARIES
Prabhu and Pankaj (Enthought)
PLUGINS
ETS
APPLICATIONS
72 / 73
Note on Envisage
Big picture
Application and plugins Envisage application: given a list of plugins Plugins setup their contributions Application starts: all plugins are started Plugins add their capabilties to the app Application stops: all plugins are stopped
ETS
73 / 73
Note on Envisage
Big picture
Interaction/communication between plugins Plugins dene extension points Extensions extension points Services
Well known/shared objects Can be registered and looked-up with the application
ETS
74 / 73
Note on Envisage
Envisage application
Envisage application Extension Registry Extensions Plugin Services Service Registry Plugin
ETS
75 / 73
Summary
Outline
1
Introduction ODE 101 Traits TraitsUI Chaco Mayavi Putting it all together Note on Envisage Summary
Prabhu and Pankaj (Enthought) ETS 76 / 73
2 3 4 5 6 7 8
Summary
Summary
ETS
77 / 73