disipyl Tutorial

Author: Paul M. Magwene
Email: paul.magwene@yale.edu

Overview

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

Conventions

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"

Getting Started

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.

Creating Plots

The Parts of a Plot

Every valid drawing in disipyl consists of at least one instance of each of the following classes (or their descendants):

  1. Canvas
  2. PlotObject
  3. 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 dictionary of options which are 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 objects. 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 only be set using the __call__ method. Regular attributes can be set using the standard attribute calling mechanism (.attribute).

Simple Plot Creation

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. Let's take a look at the sub-objects:

>>> dir(s)
['axes', 'canvas', 'dataobjects', 'dispostaxis', 'dispreaxis', 'labels', 'options', 'title', 'xlist', 'ylist']

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()

Creating a 3D Plot

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.

The easy 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.

The hard way

>>> 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.

Creating a New Plot Class

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 miscplots.py are filled with examples of specialized plot classes.

For More Information

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.