1
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
2
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
4
<html xmlns="http://www.w3.org/1999/xhtml">
7
<title>Data Exploration with Chaco</title>
9
<meta name="generator" content="S5" />
10
<meta name="version" content="S5 1.1" />
11
<meta name="presdate" content="20050728" />
12
<meta name="author" content="Eric A. Meyer" />
13
<meta name="company" content="Complex Spiral Consulting" />
14
<!-- configuration parameters -->
15
<meta name="defaultView" content="slideshow" />
16
<meta name="controlVis" content="hidden" />
17
<!-- style sheet links -->
18
<link rel="stylesheet" href="ui/default/slides.css" type="text/css" media="projection" id="slideProj" />
19
<link rel="stylesheet" href="ui/default/outline.css" type="text/css" media="screen" id="outlineStyle" />
20
<link rel="stylesheet" href="ui/default/print.css" type="text/css" media="print" id="slidePrint" />
21
<link rel="stylesheet" href="ui/default/opera.css" type="text/css" media="projection" id="operaFix" />
23
<script src="ui/default/slides.js" type="text/javascript"></script>
25
<!-- Syntax Highlighting -->
26
<link type="text/css" rel="stylesheet" href="SyntaxHighlighter.css"></link>
31
<div id="controls"><!-- DO NOT EDIT --></div>
32
<div id="currentSlide"><!-- DO NOT EDIT --></div>
33
<div id="header"></div>
35
<h1>Scipy Tutorial Session, 16 August 2006</h1>
36
<h2>(Use the arrow keys or the controls in the lower-right-hand corner to navigate this slideshow.)</h2>
42
<div class="presentation">
45
<h1><i>Data Exploration with Chaco</i></h1>
47
<p><img src="images/chaco_splash.png"></p>
53
<h1>Structure of today's tutorial</h1>
55
<li>Overview of Chaco</li>
56
<li>Basic plots and interactors</li>
57
<li>Creating simple interactors</li>
58
<li>Core concepts: data model, layout, interaction model</li>
59
<li>More complex plots</li>
60
<!-- <li>Creating more complex interactors</li> -->
61
<li>Walkthrough of some examples</li>
68
Chaco is a <em>plot application toolkit</em> for Python. You use it to build
69
stand-alone plotting applications, or embed it inside any application that needs
70
to visualize numerical data.
72
<p>Sample plotting applications:
74
<li>batch plotting of data (csv -> png)</li>
75
<li>display for realtime data acquisition</li>
76
<li>visual plot construction kit</li>
77
<li>visual editor for tweaking input parameters to simulations</li>
78
<li>mapping and GIS applications</li>
84
<h1>Chaco Features</h1>
86
<li>Different rendering layers, backbuffering</li>
87
<li>Container model for layout and event dispatch</li>
88
<li>Modular and extensible architecture</li>
89
<li>Data model/filtering pipeline</li>
90
<li>Vector drawing engine</li>
96
<!-------------------------------------------------------------------------------
98
Part 1. Basic plots and interactors
100
------------------------------------------------------------------------------->
105
<h1>A first look</h1>
106
<textarea name="highlightcode" class="py:nocontrols">
110
from scipy import arange, pi, sin
112
step = 4*pi / numpoints
113
x = arange(-2*pi, 2*pi+step/2, step)
116
# Create the plot and set its size
117
from enthought import chaco
118
myplot = chaco.create_line_plot((x,y), bgcolor="white", add_grid=True, add_axis=True)
120
myplot.bounds = [400,400]
122
# Create a graphics context for offline rendering
123
plot_gc = chaco.PlotGraphicsContext(myplot.outer_bounds)
124
plot_gc.render_component(myplot)
125
plot_gc.save("tutorial1.png")
130
<h1>tutorial1.py</h1>
131
<img src="images/tutorial1.png">
136
<h1>Creating a window</h1>
137
<textarea name="highlightcode" class="py:nocontrols">
140
from enthought import chaco
142
# Import the plot from Tutorial 1
143
from tutorial1 import myplot
145
from enthought.enable2.wx_backend.api import Window
146
class PlotFrame(wx.Frame):
147
def __init__(self, *args, **kw):
148
kw["size"] = (600,600)
149
wx.Frame.__init__( *(self,) + args, **kw )
151
# Use Enable.Window to bridge between the vector-drawing world of Chaco and WX
152
self.plot_window = Window(parent=self, component=myplot)
154
sizer = wx.BoxSizer(wx.HORIZONTAL)
155
sizer.Add(self.plot_window.control, 1, wx.EXPAND)
157
self.SetAutoLayout(True)
165
<h1>Opening the window</h1>
166
<p><h2>Normal python (standalone app)</h2>
167
<textarea name="highlightcode" class="py:nocontrols">
168
from tutorial2 import PlotFrame
170
app = wx.PySimpleApp()
171
frame = PlotFrame(None)
175
<h2>From within IPython</h2>
176
<textarea name="highlightcode" class="py:nocontrols">
177
# This requires invoking IPython as "ipython -pylab" or "ipython -wthread"
179
from tutorial2 import PlotFrame
180
frame = PlotFrame(None)
186
<h1>Fun from within IPython</h1>
187
We can tweak plot attributes on the fly:
188
<textarea name="highlightcode" class="py:nocontrols">
189
plot.vgrid.visible = False
190
plot.x_axis.visible = False
191
plot.request_redraw()
196
<h1>Fun from within IPython</h1>
197
We can even write functions to do the tweaking for us!
198
<textarea name="highlightcode" class="py:nocontrols">
199
# tutorial2_ipython.py
202
plot.y_axis.title = text
203
plot.request_redraw()
205
def xrange(low, high):
206
plot.x_mapper.range.low = low
207
plot.x_mapper.range.high = high
208
plot.request_redraw()
210
def yrange(low, high):
211
plot.y_mapper.range.low = low
212
plot.y_mapper.range.high = high
213
plot.request_redraw()
219
<h1>The Joy of Traits</h1>
221
Since all Chaco primitives use traits, we can easily bring up property sheets.
227
<h1>Adding a basic interactor</h1>
228
<p>All Chaco components can have tools on them, and any events they receive get forwarded on to
231
<textarea name="highlightcode" class="py:nocontrols">
234
from tutorial2 import myplot, PlotFrame, main
236
from enthought.chaco.tools import PanTool
238
myplot.tools.append(PanTool(myplot))
246
<p>Because the zoom tool draws a visible "zoom box", we need to add it to the list
247
of overlays instead of the list of tools. (It will still get events.)
248
<textarea name="highlightcode" class="py:nocontrols">
251
from tutorial2 import myplot, PlotFrame, main
253
from enthought.chaco.tools import SimpleZoom
255
# Create an instance of the tool and add it as an overlay..
256
myplot.overlays.append(SimpleZoom(myplot, tool_mode="box", always_on=True))
263
<h1>Coordinating different tools</h1>
264
PanTool and SimpleZoom both key off the left mouse click/drag. Fortunately,
265
PanTool is not a "stateful" interaction, and there is a way to tell SimpleZoom
266
to play nicely with others:
267
<textarea name="highlightcode" class="py:nocontrols">
270
from tutorial2 import myplot, PlotFrame, main
271
from enthought.chaco.tools import PanTool, SimpleZoom
273
myplot.tools.append(PanTool(myplot))
275
zoom = SimpleZoom(myplot, tool_mode="box", always_on=False)
277
myplot.overlays.append(zoom)
283
<h1>Writing our first interactor</h1>
284
Diagnostic tool to dump out the events we are getting:
285
<textarea name="highlightcode" class="py:nocontrols">
288
# AbstractController is the base class for non-rendering tools
289
from enthought.chaco.api import AbstractController
291
class EventPrinter(AbstractController):
293
def dispatch(self, event, suffix):
294
# event' is a MouseEvent or KeyEvent object from the enable2
295
# package, and suffix is a text string
296
print suffix, "event received at (%d,%d)" % (event.x, event.y)
299
from tutorial2 import myplot, PlotFrame, main
301
myplot.tools.append(EventPrinter(myplot))
307
<h1>Looking at data</h1>
308
We don't really want to know the mouse position; we want to know about
309
coordinates in data space:
311
<textarea name="highlightcode" class="py:nocontrols">
314
from enthought.chaco.api import AbstractController
316
class DataPrinter(AbstractController):
317
def dispatch(self, event, suffix):
318
# We are assuming that self.component is an X-Y plot
319
x = self.component.x_mapper.map_data(event.x)
320
y = self.component.y_mapper.map_data(event.y)
321
print suffix, "event received at (%d,%d)" % (x, y)
324
from tutorial2 import myplot, PlotFrame, main
326
myplot.tools.append(DataPrinter(myplot))
331
<!-------------------------------------------------------------------------------
333
Part 2. Digging deeper - the data model and understanding factories
335
------------------------------------------------------------------------------->
339
<h1>Digging deeper</h1>
340
<textarea name="highlightcode" class="py:nocontrols">
343
myplot = chaco.create_line_plot((x,y))
346
What does the create_line_plot() actually do?
348
<li>creates datasources</li>
349
<li>creates range objects and mappers</li>
350
<li>creates the plot object</li>
358
<textarea name="highlightcode" class="py:nocontrols">
359
# plot_factory.py:create_line_plot()
361
index_data, value_data = transpose(data)
362
index = ArrayDataSource(index_data)
363
value = ArrayDataSource(value_data, sort_order="none")
366
ArrayDataSource is just a subclass of AbstractDataSource which works with
367
Numeric/numpy arrays.
368
<textarea name="highlightcode" class="py:nocontrols">
369
class AbstractDataSource(HasTraits):
370
value_dimension = DimensionTrait
371
index_dimension = DimensionTrait
375
get_data_mask() -> array, mask
378
get_bounds() -> array
383
<h1>Ranges, Mappers, and the Plot</h1>
384
<textarea name="highlightcode" class="py:nocontrols">
385
index_range = DataRange()
386
index_range.add(index)
387
index_mapper = LinearMapper(range=index_range)
389
value_range = DataRange()
390
value_range.add(value)
391
value_mapper = value_mapper_class(range=value_range)
393
plot = LinePlot(index=index, value=value,
394
index_mapper = index_mapper,
395
value_mapper = value_mapper,
396
orientation = orientation,
400
border_visible = True)
407
<h1>Decorating with Axes and Grids</h1>
408
<textarea name="highlightcode" class="py:nocontrols">
409
def add_default_axes(plot, orientation="normal", vtitle="",htitle=""):
410
if orientation == "normal":
411
v_mapper = plot.value_mapper
412
h_mapper = plot.index_mapper
414
v_mapper = plot.index_mapper
415
h_mapper = plot.value_mapper
417
left = PlotAxis(orientation='left',
422
bottom = PlotAxis(orientation='bottom',
427
plot.underlays.append(left)
428
plot.underlays.append(bottom)
430
Adding grids is basically the same code.
436
We can use a container to put two plots on the screen.
437
<textarea name="highlightcode" class="py:nocontrols" rows="24">
438
def _create_plot(self):
439
x = arange(-5.0, 15.0, 20.0/100)
442
left_plot = create_line_plot((x,y), bgcolor="white",add_grid=True, add_axis=True)
443
left_plot.tools.append(PanTool(left_plot))
444
self.left_plot = left_plot
447
right_plot = create_line_plot((x,y), bgcolor="white", add_grid=True, add_axis=True)
448
right_plot.tools.append(PanTool(right_plot))
449
right_plot.y_axis.orientation = "right"
450
self.right_plot = right_plot
452
container = HPlotContainer(spacing=20, padding=50, bgcolor="lightgray")
453
container.add(left_plot)
454
container.add(right_plot)
462
<h1>Connecting the two plots</h1>
463
We're going to link the X dimension of the two plots. Really, all we have to do to
464
achieve this is to set the horizontal range on the two plots to be the same.
465
<textarea name="highlightcode" class="py:nocontrols">
468
class PlotFrame2(PlotFrame):
470
def _create_plot(self):
472
container = super(PlotFrame2, self)._create_plot()
474
self.right_plot.index_mapper.range = self.left_plot.index_mapper.range
482
<h1>Connecting the two plots (cont.)</h1>
483
We can connect the Y dimension, too. And let's throw in a zoom tool.
484
<textarea name="highlightcode" class="py:nocontrols">
487
self.right_plot.value_mapper.range = self.left_plot.value_mapper.range
489
self.left_plot.overlays.append(
490
SimpleZoom(self.left_plot, tool_mode="box", always_on=False))
492
self.right_plot.overlays.append(
493
SimpleZoom(self.right_plot, tool_mode="box", always_on=False))
500
<h1>Linked views, but not connected data</h1>
501
Adding a line inspector will show the problem.
502
<textarea name="highlightcode" class="py:nocontrols">
505
from tutorial9b import PlotFrame2
507
class PlotFrame3(PlotFrame2):
508
def _create_plot(self):
509
container = super(PlotFrame2, self)._create_plot()
511
self.left_plot.overlays.append(
512
LineInspector(component=self.left_plot,
516
self.right_plot.overlays.append(
517
LineInspector(component=self.right_plot,
526
<h1>Connecting the data</h1>
528
<textarea name="highlightcode" class="py:nocontrols">
531
class PlotFrame3(PlotFrame2):
532
def _create_plot(self):
533
container = super(PlotFrame2, self)._create_plot()
535
self.left_plot.overlays.append(
536
LineInspector(component=self.left_plot,
540
self.right_plot.overlays.append(
541
LineInspector(component=self.right_plot,
545
self.right_plot.index = self.left_plot.index
554
<h1>Why Index-Value instead of X-Y?</h1>
555
Because you are then immune to a plot's physical layout.
556
<textarea name="highlightcode" class="py:nocontrols">
559
class PlotFrame4(PlotFrame3):
560
def _create_plot(self):
561
container = super(PlotFrame4, self)._create_plot()
563
plot = self.right_plot
564
plot.orientation = "v"
565
plot.hgrid.mapper = plot.index_mapper
566
plot.vgrid.mapper = plot.value_mapper
567
plot.y_axis.mapper = plot.index_mapper
568
plot.x_axis.mapper = plot.value_mapper
570
self.left_plot.overlays.append(
571
LineInspector(component=self.left_plot,
573
is_listener=True, color="blue",
576
self.right_plot.overlays.append(
577
LineInspector(component=self.right_plot,
579
is_listener=True, color="blue",
586
<!-------------------------------------------------------------------------------
588
Part 3. Real-world examples
590
------------------------------------------------------------------------------->
597
<h1>Visual Components</h1>
601
<li>Tools and tool overlays</li>
602
<li>Legends, annotations, etc.</li>
607
<h1>Visual Components (cont.)</h1>
609
<li>have bounds, position, padding, border, bgcolor</li>
610
<li>can be placed inside containers</li>
611
<li>can be horizontally and vertically resized (or not)</li>
612
<li>implement draw (and request draw on their underlays and overlays)</li>
613
<li>implement dispatch (and dispatch to underlays and overlays)</li>
619
<h1>More about Containers</h1>
623
<li>Draw order & backbuffering</li>
629
<h1>Walkthrough of interesting examples</h1>
634
<h1>How to get it</h1>
635
<p><font size=+5><a href="http://code.enthought.com/chaco">http://code.enthought.com/chaco</a></font></p>
636
<p>Mailing lists: chaco-users@enthought.com, enthought-dev@enthought.com</p>
637
<p>Get Enthon! http://code.enthought.com/enthon</p>
643
<script language="javascript" src="Scripts/shCore.js"></script>
644
<script language="javascript" src="Scripts/shBrushPython.js"></script>
645
<script language="javascript" src="Scripts/shBrushXml.js"></script>
646
<script language="javascript">
647
dp.SyntaxHighlighter.HighlightAll('highlightcode');