~ubuntu-branches/ubuntu/utopic/python-chaco/utopic

« back to all changes in this revision

Viewing changes to docs/source/architecture_overview.rst

  • Committer: Package Import Robot
  • Author(s): Varun Hiremath, Varun Hiremath, Jakub Wilk
  • Date: 2014-03-15 22:52:33 UTC
  • mfrom: (1.2.4)
  • mto: This revision was merged to the branch mainline in revision 16.
  • Revision ID: package-import@ubuntu.com-20140315225233-ngcbglmcj5onpo93
Tags: 4.4.1-1
[ Varun Hiremath ]
* New upstream release
* d/control: Fix upstream Homepage URL (Closes: #649473)
* Bump Standards-Version to 3.9.5

[ Jakub Wilk ]
* Use canonical URIs for Vcs-* fields.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
*********************
2
 
Architecture Overview
3
 
*********************
4
 
 
5
 
.. note::
6
 
 
7
 
   This is an overview of not just Chaco, but also Kiva and Enable.
8
 
 
9
 
.. contents::
10
 
 
11
 
 
12
 
 
13
 
Core Ideas
14
 
==========
15
 
 
16
 
The Chaco toolkit is defined by a few core architectural ideas:
17
 
 
18
 
* **Plots are compositions of visual components**
19
 
 
20
 
  Everything you see in a plot is some sort of graphical widget,
21
 
  with position, shape, and appearance attributes, and with an
22
 
  opportunity to respond to events.
23
 
 
24
 
* **Separation between data and screen space**
25
 
 
26
 
  Although everything in a plot eventually ends up rendering into a common
27
 
  visual area, there are aspects of the plot which are intrinsically
28
 
  screen-space, and some which are fundamentally data-space.  Preserving
29
 
  the distinction between these two domains allows us to think about
30
 
  visualizations in a structured way.
31
 
 
32
 
* **Modular design and extensible classes**
33
 
 
34
 
  Chaco is meant to be used for writing tools and applications, and code
35
 
  reuse and good class design are important. We use the math behind the
36
 
  data and visualizations to give us architectural direction and conceptual
37
 
  modularity. The Traits framework allows us to use events to couple
38
 
  disjoint components at another level of modularity.
39
 
 
40
 
  Also, rather than building super-flexible core objects with myriad
41
 
  configuration attributes, Chaco's classes are written with subclassing in
42
 
  mind.  While they are certainly configurable, the classes themselves are
43
 
  written in a modular way so that subclasses can easily customize
44
 
  particular aspects of a visual component's appearance or a tool's
45
 
  behavior.
46
 
 
47
 
 
48
 
The Relationship Between Chaco, Enable, and Kiva
49
 
================================================
50
 
 
51
 
Chaco, Enable, and Kiva are three packages in the Enthought Tool Suite.
52
 
They have been there for a long time now, since almost the beginning of
53
 
Enthought as a company.  Enthought has delivered many applications using
54
 
these toolkits. The Kiva and Enable packages are bundled together in the
55
 
"Enable" project.
56
 
 
57
 
Kiva
58
 
----
59
 
 
60
 
Kiva is a 2-D vector drawing library for Python. It serves a purpose similar to
61
 
`Cairo <http://cairographics.org/>`_. It allows us to compose vector graphics
62
 
for display on the screen or for saving to a variety of vector and image file
63
 
formats. To use Kiva, a program instantiates a Kiva :class:`GraphicsContext`
64
 
object of an appropriate type, and then makes drawing calls on it like
65
 
:meth:`gc.draw_image`, :meth:`gc.line_to`, and :meth:`gc.show_text`. Kiva
66
 
integrates with windowing toolkits like wxWindows and Qt, and it has an OpenGL
67
 
backend as well. For wxPython and Qt, Kiva actually performs a high-quality,
68
 
fast software rasterization using the Anti-Grain Geometry (AGG) library. For
69
 
OpenGL, Kiva has a python extension that makes native OpenGL calls from C++.
70
 
 
71
 
Kiva provides a GraphicsContext for drawing onto the screen or saving out to
72
 
disk, but it provides no mechanism for user input and control. For this
73
 
"control" layer, it would be convenient to have to write only one set of event
74
 
callbacks or handlers for all the platforms we support, and all the toolkits on
75
 
each platform. The Enable package provides this layer. It insulates all the
76
 
rendering and event handling code in Chaco from the minutiae of each GUI
77
 
toolkit. Additionally, and to some extent more importantly, Enable defines the
78
 
concept of "components" and "containers" that form the foundation of Chaco's
79
 
architecture. In the Enable model, the top-most Window object is responsible for
80
 
dispatching events and drawing a single component. Usually, this component is a
81
 
container with other containers and components inside it. The container can
82
 
perform layout on its internal components, and it controls how events are
83
 
subsequently dispatched to its set of components.
84
 
 
85
 
Enable
86
 
------
87
 
 
88
 
Almost every graphical component in Chaco is an instance of an
89
 
Enable component or container.  We're currently trying to push more of the
90
 
layout system (implemented as the various different kinds of Chaco plot
91
 
containers) down into Enable, but as things currently stand, you have to
92
 
use Chaco containers if you want to get layout.  The general trend has been
93
 
that we implement some nifty new thing in Chaco, and then realize that it
94
 
is a more general tool or overlay that will be useful for other
95
 
non-plotting visual applications.  We then move it into Enable, and if
96
 
there are plotting-specific aspects of it, we will create an appropriate
97
 
subclass in Chaco to encapsulate that behavior.
98
 
 
99
 
The sorts of applications that can and should be done at the Enable level
100
 
include things like a visual programming canvas or a vector drawing tool.
101
 
There is nothing at the Enable level that understands the concept of
102
 
mapping between a data space to screen space and vice versa.  Although
103
 
there has been some debate about the incorporating rudimentary mapping into
104
 
Enable, for the time being, if you want some kind of canvas-like thing to
105
 
model more than just pixel space on the screen, implement it using
106
 
the mechanisms in Chaco.
107
 
 
108
 
.. [COMMENT]: A diagram would be helpful to illustrate the following paragraph.
109
 
 
110
 
The way that Enable hooks up to the underlying GUI toolkit system is via an
111
 
:class:`enable.Window` object. Each toolkit has its own implementation of this
112
 
object, and they all subclass from :class:`enable.AbstractWindow`. They usually
113
 
contain an instance of the GUI toolkit's specific window object, whether it's a
114
 
:class:`wx.Window` or :class:`Qt.QWidget` or :class:`pyglet.window.Window`. This
115
 
instance is created upon initialization of the enable.Window and stored as the
116
 
:attr:`control` attribute on the Enable window. From the perspective of the GUI
117
 
toolkit, an opaque widget gets created and stuck inside a parent control (or
118
 
dialog or frame or window). This instance serves as a proxy between the GUI
119
 
toolkit and the world of Enable. When the user clicks inside the widget area,
120
 
the :attr:`control` widget calls a method on the enable.Window object, which
121
 
then in turn can dispatch the event down the stack of Enable containers and
122
 
components. When the system tells the widget to draw itself (e.g., as the result
123
 
of a PAINT or EXPOSE event from the OS), the enable.Window is responsible for
124
 
creating an appropriate Kiva GraphicsContext (GC), then passing it down through
125
 
the object hierarchy so that everyone gets a chance to draw. After all the
126
 
components have drawn onto the GC, for the AGG-based bitmap backends, the
127
 
enable.Window object is responsible for blitting the rastered off-screen buffer
128
 
of the GC into the actual widget's space on the screen. (For Kiva's OpenGL
129
 
backend, there is no final blit, since calls to the GC render in immediate mode
130
 
in the window's active OpenGL context, but the idea is the same, and the
131
 
enable.Window object does perform initialization on the GL GraphicsContext.)
132
 
 
133
 
Some of the advantages to using Enable are that it makes mouse and key events
134
 
from disparate windowing systems all share the same kind of signature, and be
135
 
accessible via the same name. So, if you write bare wxPython and handle a
136
 
:obj:`key_pressed` event in wx, this might generate a value of
137
 
:obj:`wx.WXK_BACK`. Using Enable, you would just get a "key" back and its value
138
 
would be the string "Backspace", and this would hold true on Qt4 and Pyglet.
139
 
Almost all of the event handling and rendering code in Chaco is identical under
140
 
all of the backends; there are very few backend-specific changes that need to be
141
 
handled at the Chaco level.
142
 
 
143
 
The :class:`enable.Window` object has a reference to a single top-level graphical
144
 
component (which includes containers, since they are subclasses of
145
 
component).  Whenever it gets user input events, it recursively dispatches
146
 
all the way down the potentially-nested stack of components.  Whenever a
147
 
components wants to signal that it needs to be redrawn, it calls
148
 
self.request_redraw(), which ultimately reaches the enable.Window, which
149
 
can then make sure it schedules a PAINT event with the OS.  The nice thing
150
 
about having the enable.Window object between the GUI toolkits and our
151
 
apps, and sitting at the very top of event dispatch, is that we can easily
152
 
interject new kinds of events; this is precisely what we did to enable all
153
 
of our tools to work with Multitouch.
154
 
 
155
 
The basic things to remember about Enable are that: 
156
 
 
157
 
* Any place that your GUI toolkit allows you stick a generic widget, you
158
 
  can stick an Enable component (and this extends to Chaco components, as
159
 
  well).  Dave Morrill had a neat demonstration of this by embedding
160
 
  small Chaco plots as cells in a wx Table control.  
161
 
 
162
 
* If you have some new GUI toolkit, and you want to provide an Enable
163
 
  backend for it, all you have to do is implement a new Window class for
164
 
  that backend.  You also need to make sure that Kiva can actually
165
 
  create a GraphicsContext for that toolkit.  Once the kiva_gl branch is
166
 
  committed to the trunk, Kiva will be able to render into any GL
167
 
  context. So if your newfangled unsupported GUI toolkit has a
168
 
  GLWindow type of thing, then you will be able to use Kiva, Enable, and
169
 
  Chaco inside it.  This is a pretty major improvement to
170
 
  interoperability, if only because users now don't have to download and
171
 
  install wxPython just to play with Chaco.
172
 
 
173
 
 
174
 
Chaco
175
 
===========================================================================
176
 
 
177
 
.. note::
178
 
 
179
 
    This section provides an overview of the relationships between these
180
 
    classes, and illustrates some sample usages.  For a more detailed list of
181
 
    the class hierarchy, please see :ref:`modules_and_classes`.
182
 
    
183
 
At the highest level, Chaco consists of:
184
 
 
185
 
* Visual components that render to screen or an output device
186
 
  (e.g., :class:`LinePlot`, :class:`ScatterPlot`, :class:`PlotGrid`, 
187
 
  :class:`PlotAxis`, :class:`Legend`)
188
 
 
189
 
* Data handling classes that wrap input data, interface with
190
 
  application-specific data sources, and transform coordinates
191
 
  between data and screen space (e.g., :class:`ArrayDataSource`,
192
 
  :class:`GridDataSource`, :class:`LinearMapper`)
193
 
 
194
 
* Tools that handle keyboard or mouse events and modify other
195
 
  components (e.g., :class:`PanTool`, :class:`ZoomTool`, 
196
 
  :class:`ScatterInspector`)
197
 
 
198
 
Every Chaco plot is composed of these elements.  One can think of them
199
 
as comprising a "display pipeline", although the components form more
200
 
of a graph.
201
 
 
202
 
For example, a simple scatter plot will have:
203
 
 
204
 
* Two :class:`ArrayDataSource` objects, one for the array of X data and one for
205
 
  the Y data
206
 
 
207
 
* Two :class:`DataRange1D` ranges, one for the X axis and one for the Y axis.
208
 
  If we want the ranges to automatically compute the bounds of the dataset,
209
 
  then they need a reference to the an :class:`ArrayDataSource`.
210
 
 
211
 
* Two independent :class:`LinearMapper` mappers, one for X axis and one for the
212
 
  Y axis.  The mappers convert from screen space to data space and vice verse,
213
 
  so they need a reference to the :class:`DataRange1D` objects so they know the
214
 
  data space extents. 
215
 
 
216
 
* A :class:`ScatterPlot` renderer, that has a reference to two mappers, as
217
 
  well as an index and a value :class:`ArrayDataSource`.
218
 
 
219
 
This creates *only* the renderer that draws scatter markers in some region of
220
 
screen space.  This does not create an X-axis, a Y-axis, or horizontal and
221
 
vertical grids.  These other visuals are embodied as separate, distinct
222
 
components: axes are drawn by the :class:`PlotAxis` component, and grids are
223
 
drawn by the :class:`PlotGrid` component.  Both of these overlays require a
224
 
mapper in order to know where on the screen they should draw.
225
 
 
226
 
.. So, the pipeline looks like:
227
 
 
228
 
 
229