The following tutorial leads the user through the creation of disipyl plots using the interactive Python interpreter. I also provide some longer examples in which I show the user how to derive specialized classes and functions to suit particular plotting needs.
You may find it useful to open another browser window with the auto-generated documentation. Doing so will help you gain familiarity with the function and classes which make up disipyl.
The tutorial assumes you've already installed disipyl
(and DISLIN) somewhere where the Python interpretter can find it (see the
section on installation for more details). I also assume the modules
Numeric
and RandomArray
(both part of the NumPy
package) are available
Throughout the tutorial we'll be creating and manipulating
disipyl objects both from the Python interactive
interpretter and in module files. Both interactive sessions and module code
will be setoff with grey boxes in a fixed font (assuming your browser
supports CSS). Interactive sessions will be distinguished from module code by
the presence of the interpretter prompt symbol
(>>>
).
For example, the following indicates an interactive session (the lines without the prompts show what values [if any] the interpetter returns).
>>> print "hello, python world!" hello, python world! >>>
This example shows a hypothetical function and class in a module:
## test.py def helloFunction(name): print "Hello %s, it's nice to meet you!" % name class AClass: def __init__(self): print "AClass created" def __del__(self): print "AClass destroyed"
Fire up the Python interpretter (see the documentation which came with you Python distribution if you don't know how to do that).
We'll check that everything is ready to go by running some demos. Type the following:
>>> from disipyl import demos >>> demos.showdemos()
A series of example plots will begin to appear. After each plot appears the program will wait until you hit the return key or click on the plot window with your right-mouse button before continuing.
To see a similar set of demos using the Tkinter GUI, type the following at the command-line from within the the disipyl directory (this assumes that the python interpretter is in your path):
$ python tkdisipyl.py
A small window with two buttons will appear, offering you a choice between the 2D and 3D demos. You can play around with both sets of demos. The 3D demos are particularly interesting because they provide a set of navigation buttons (e.g., rotate left, zoom in, etc.) so you can interactively explore the 3D plots.
Every valid drawing in disipyl consists of at least one instance of each of the following classes (or their descendants):
Canvas
PlotObject
AxisSystem
All three of these classes are primarily container classes - they maintain
a list of the subobjects which they are responsible for, and call each of
these subojects to draw themselves in turn. For example, a
PlotObject
instance must be assigned a valid
AxisSystem
(in the .axes
attribute). Similarly an
AxisSystem
should have two or more Axis
objects
(.xaxis
, .yaxis
, and sometimes a
.zaxis
).
All disipyl
objects are ultimately derived from the
Object
class, defined in the file pxdislin.py
. All
classes derived from Object
maintain a private attribute
(currently a list) called __options__
which is used to track and
maintain the different types of options which affect how the object is drawn.
This dictionary of options is accessed in a somewhat roundabout way - options
are set using the __call__ method of the class, options are retrieved using
the standard __getattr__
function. We can examine all the
options of an object by using the __call__ method without any argument. To
see how this works in action examine the following code:
>>> from disipyl import pxdislin >>> message = pxdislin.Text(text='hello, disipyl world!') >>> message() *BEGIN OBJECT: Text TeX = 0 color = fore font = default fonttype = hardware height = 36 justify = left position = (0, 0) rotation = 0 text = 'hello, disipyl world!' ucoords = 1 *END OBJECT: Text >>> message(color = 'red', height = 48) >>> message.color 'red' >>>
After importing the appropriate module, we created a Text
object to which we gave the name message
. We then invoked the
__call__
method (message()
) without any arguments,
which returned a printed message showing the various options for this object.
We invoked the __call__
method a second time with keyword
arguments. These keyword arguments corresponded to the options we wished to
set. Finally, we examined a single option (message.color
) using
the standard attribute calling mechanism.
Note, that options can be set using either the normal attribute calling
mechanism (.attribute
) or via the __call__
method,
but you should always prefer the __call__
method because only
then can disipyl ensure that the options you are setting are
relevant for the given object.
The first plot we will create will be a simple scatter plot. The module,
disipyl.plots
, provides a class, ScatterPlot
, which
provides reasonable default values for scatter plots. Once we've created our
plot, it's easy to refine it to get it just right.
Let's create the scatter plot:
>>> from disipyl import plots >>> s = plots.ScatterPlot(range(10),range(10)) >>> s.draw()
After importing the plots module we created a ScatterPlot object to which we assigned the variable name 's' (when working in the interactive interpretter it's most convenient to use short variable names; when creating module files you should use more descriptive names).
The plot we've just created isn't very exciting. It's a simple scatter plot where the x- and y-values are identical. We're going to spice up the plot, but first let's explore the plot object a little:
>>> s() *BEGIN OBJECT: ScatterPlot TeXmode = 1 defaultcanvastype = disipyl.pxdislin.Canvas symbols = <disipyl.pxdislin.SymbolGroup instance at 014197FC> *END OBJECT: ScatterPlot
Any disipyl object derived from the base class
Object
will display it's options when called without any
arguments. The ScatterPlot
has relatively few options of its
own. The option TeXmode
specifies whether TeX style formatting
of equations is available. The option defaultcanvastype
specifies the type of Canvas object the plot should generate if it needs to
draw itself (as opposed to being draw as a sub-object of a Canvas).
When a ScatterPlot
object is created the initial set of data
is represented by a SymbolGroup
object. A
SymbolGroup
is simply a collection of individual
Symbol
objects with similar options (color, shape, etc.). The
reason that the ScatterPlot
object has relatively few options is
that it is primarily a container object, as noted above. When we call the
draw method for the ScatterPlot
object it in turn invokes the
draw methods of each of it's sub-objects.
What are the valid settings for the various options? In version of
disipyl previous to 0.6 you just had to browse the source
code to find out. In version 0.6 and higher there is a new method for
querying objects about their options. This mechanism is accessed through the
info()
method, as shown below:
>>> s.info('TeXmode') Specifies whether the TeX mode should be used for text objects. Since this doesn't adversely affect anything else, it's probably simplest to leave this on. Valid: 0 (off) or 1 (on) ------- Default: 1 >>> s.info('defaultcanvastype') Specifies the default Canvas type (Canvas or its descendants) which is created when a plot finds itself without a canvas object to draw on. Valid: Any object derived from Canvas ------- Default: Canvas >>> s.info('symbols') Undocumented option. >>> s.info('foo') No such option for ScatterPlot
As you can see, the argument to the info()
method is a string
with the name of the option you want to know more about. If the option is
currently undocumented, then you are informed of this and you'll have to
browse into the source code to figure out what the option does (if it's not
obvious from the name). Eventually I hope to have all the options will be
documented.
If you're creating new disipyl classes youreself you can
specify a file which holds the option documentation by specifying the
INFOMODULE
attribute in a call to setoptions
. For
example, in the file pxdislin
the setdefaults
method of the Page
object is defined as so:
# snippet from pxdislin.py # from defintion of class Page def set_defaults(self): self.setoptions( fillcolor = None, border = 0, width = 3000, height = 2200, scale = 1, scalingmode = 'down', INFOMODULE = "optioninfo.page", )
The INFOMODULE
attribute points to a Python module
optioninfo.page
(the file page.py
in the
subdirectory optioninfo
). Simply change this value to an
appropriate value for your new class.
Now we're ready to add some pizzaz to this plot.
>>> s.symbols(color='red', size=35, shape='fill triangle') >>> s.axes.xaxis(name='X-Axis', nameheight=40) >>> s.axes.yaxis(name='Y-Axis', nameheight=40) >>> s.draw()
This code changes the color, size and shape of the symbols used to represent the scatter of the data, and adds some axis labels.
What if we want to then add some more data to the plot? For example, we might want to add some more symbols representing another set of observations. This is relatively easy to do:
>>> group2 = pxdislin.SymbolGroup(range(10),range(9,-1,-1),color='blue', shape='fill circle',size=35) >>> s.add(group2) >>> s.draw()
Finally, we'll center and square-up the graph so that the units are the same length in the x- and y-directions. We'll also add a title:
>>> s.axes(squared=1,centered=1,grids=1,ngridlines=(2,2)) >>> s.title = pxdislin.Title(text="A Simple Graph",offset=-200) >>> s.draw()
disipyl 0.6 introduces a new mechanism by which you can
interact with a 2D plot - the explore()
method. When you use
the explore()
method with an instance of any class derived from
PlotObject
you can click on the plot with mouse button one, and
the plot coordinates will be recorded. Click mouse button two to stop
recording. After the plot exits the x- and y-coordinates which you clicked
will be returned as a tuple containing two lists. Here's an example (in
which I clicked the plot three times)::
>>> s = plots.ScatterPlot(range(10), range(10)) >>> s.explore() ([1.2486993823422159, 3.4129315248323104, 5.5969735725168217], [2.2377216588389341, 4.4729876516275269, 7.018894839788552])
Currently the possibilties of plot interaction are very basic, but I will
include derived clases with more functionality in future releases (and you
can write such classes yourself - see the source code for
PlotObject.draw()
and PlotObject.explore()
in
pxdislin.py
and the function getMouseClicks
in
pydislin.py
)
We're now going to use disipyl to create a 3-D plot of the function: f(x,y) = Imag(Log(x+iy)). There's two ways to do this - the easy way and the hard way. We'll start with the easy way, to show you just how quickly one can create a plot in disipyl. Then for completeness we'll do it the hard way.
>>> import cmath >>> from disipyl import plots >>> def func(x,y): if x==0 and y==0: return 0 z = cmath.log(complex(x,y)) return z.imag >>> easy = plots.SurfacePlot(func,-2,2,0.5,-2,2,0.5) # set function to plot and axis limits >>> easy.axes(lengths3D=(2,2,1)) >>> easy.surface(topcolor=50,bottomcolor=200) >>> easy.title = pxdislin.Title(text="$f(x,y)=Im(\log(x+iy))$") >>> easy.draw()Most of the above is self-explanatory. The only additional operations performed after creating the plot were to change the relative scaling by which each of the axes is draw (by setting the
lengths3D
option), to set the colors used to draw the top and bottom of the surface
object, and to create a title.
>>> hard = plots.Plot3D() >>> surface = pxdislin3D.FunctionSurface(func, 0.3,0.3,3,3) >>> surface(topcolor=50,bottomcolor=200) >>> hard.add(surface) >>> hard.axes.limits(-2,2,-2,2,-3,3) >>> hard.axes(lengths3D=(2,2,1)) >>> hard.title = pxdislin.Title(text="$f(x,y)=Im(\log(x+iy))$") >>> hard.draw()
As you can see, the "hard way" isn't all that hard. The only real
difference is that we had to create our own FunctionSurface
object (in the easy example the SurfacePlot
object created it
for you), and we had to set our own axis limits..
If you are using the IDLE development environment you can use the
Diddle
classes in tkdisipyl.py
to interactively
explore your plot.
>>> from disipyl import tkdisipyl >>> d = tkdisipyl.Diddle(hard)
When you create a Diddle
object a Tk window should pop up
containing the plot and a number of navigation buttons. Try rotating,
tilting and zooming in on the plot.
The dispyl
package comes with a fairly good variety of
"pre-canned" plot types. However, sooner or later you'll want to make a
specialized plot for which none of the supplied classes is appropriate. In
such cases it's desirable to derive your own specialized plot class.
Most specialized plots can be derived from either the Plot2D
or Plot3D
classes. If you have very specialized needs you may
need to derive your class from the PlotObject
. The files
plots.py
and mlabplots.py
are filled with examples
of specialized plot classes.
If you want to learn more about how to create disipyl plots, check out the
demo plots in demos.py
. I'll also try and add more examples to
this tutorial as development continues, so please check the disipyl website
for updates.