Published on O'Reilly Network (http://www.oreillynet.com/)
See this if you're having trouble printing code examples

Adding Data Visualization to Python for Producing Graphs

06/02/2000
 Related Articles

Introduction

With the drudgery of last month's article behind us, let's explore the DISLIN data visualization package. If you do not have DISLIN installed, you can obtain the software from http://www.linmpi.mpg.de/dislin. DISLIN provides the Python programmer with a robust package capable of producing both 2D and 3D graphs. DISLIN also supports basic drawing commands (e.g. line, box, circle), which also allows it to function as a generic drawing tool. (This will be left for next month.) The combination of DISLIN and NumPy provide a formidable scientific computing package.

After installing the package, get a hold of the DISLIN Python Manual (available on the web site). This short document illustrates the basic drawing commands of the package and also provides programming examples in Python. There is also a full manual available that provides complete details about the myriad of commands available. Before you dig into the full manual, however, read on to discover a simpler way.

Quickplots

What originally caught my eye about DISLIN was the availability of Quickplots. These are basic DISLIN routines that allow you to generate complex plots with a single command. They are very nice as interactive tools when using Python from a command prompt.

Before we get started, you need to set up the environment. To allow easy access to DISLIN and NumPy functions, the following two commands should be executed at the beginning of each session (or script file), after which functions from the two libraries will be available in the common namespace.

``````>>> from dislin import *
>>> from Numeric import *``````

The simplest Quickplot routine is `plot()` which draws a 2D graph containing data points connected by lines. To see this in action, open a Python command window and type along.

``````>>> x = arange(100.0)
>>> plot(x,sin(x/3)+cos(x/5))
>>> disfin()``````

The first command is a NumPy function creating an array with values of x=1.0,…,100.0. It is very important to note the .0 in 100.0 as that makes the numbers floating point. Not doing so would have generated an array of integers. Alternatively you could have used

`>>>x = arange(100,Float)`

which would have forced `x` to be floating point. The `plot()` command takes two arguments, each an array, and plots the second argument (as the dependent variable or vertical axis) against the first argument (as the independent variable or horizontal axis). In a more formal sense, the plot command plots f(x) against x. For this example I chose

,

a sum of two sinusoid functions.

The resultant plot is shown below. The `disfin()` function tells the plotting package that you are done with the current graph and to render it. It also freezes the console until the right mouse button is pressed. After pressing the mouse button, the plot is cleared and the control is returned to the console.

In addition to the simple 2D plots, there are several Quickplot routines that enable 3D graphics. Each of these routines use the same basic arguments. The first argument is a matrix of values followed by two single-dimension arrays. In a three-dimensional plot there are three axes. The x and y axes form a plane (flat surface) from which the z axis rises. The values in the matrix are the heights (above or below) the x-y plane. The x and y single-dimension arrays provide scaling along those axes. Back again to formal notation, the 3D routines plot z=f(x,y) against x and y. For the 3D plots I chose

,

which is a two-dimensional sinusoid function.

As an example of generating a 3D plot, try the following commands.

``````>>>z_mat = zeros((180,180),Float)
>>>x_ray = arange(180.0)
>>>y_ray = arange(180.0)

>>>dtr = 3.141592654/180.0

>>>for x in x_ray:
for y in y_ray:
z_mat[int(x)][int(y)] = sin(x*3*dtr)*sin(y*2*dtr)
>>>surface(z_mat,x_ray,y_ray)
>>>disfin()``````

The first command creates the result matrix, properly sized beforehand. We use the `zeros()` function to size-up the array and pre-allocate storage space for it. The second argument in `zeros()` declares the zeros in the matrix to be floating point zeros instead of integer ones (which would be created by default). If we left that out, the upcoming calculation would be truncated and stored in the `z_mat` matrix as integer values -- not what we want!

The `surface()` function is the Quickplot routine that generates the following graph.

While this may look exciting, the monochromatic nature is drab. By switching the `surface()` function to the `surshade()` function the following is produced.

Now that's a little better! With color the features of the plot really stand out. As a final example of QuickPlots, switch the `surshade()` function to `surf3()`, which will draw a colored contour plot of the same data. The color bar on the left shows the magnitudes as represented by the colors in the plot.

Quickplot Modification

You can add custom labels to the axis and change quite a few characteristics of a QuickPlot. This is done by setting variables internal to the plotting package via the `setvar()` routine. Consult the DISLIN Python manual for a complete list of available options. Recreating the first example with the addition of axis labels is shown below.

``````>>> x=arange(100.0)
>>> setvar('X','Independent Variable')
>>> setvar('Y','Dependent Variable')
>>> plot(x,sin(x/3)+cos(x/5))
>>> disfin()``````

Going Beyond the Basics

Creating custom plots or significantly modifying some of the previous examples will force you to engross yourself in the DISLIN function set. If this is your desire, you need to check out the pxDislin module written by Paul Magwene available here. PxDislin is an Object-Oriented wrapper for DISLIN that provides a straightforward and simple programming model.

PxDislin

To get started with pxDislin, start a new console session and import the library.

`>>> from pxdislin import *`

This takes care of importing the DISLIN library itself. Of course if you want NumPy (don't we all?), remember to import it as well.

PxDislin has a class hierarchy that builds on the basic dPlot object. The most basic graphic consists of a dPlot object incorporating a dAxis object. The dPlot object can be thought as the canvas on which the drawing is made. The dAxis object helps to define the size. Let's try an example

``````>>> plot = dPlot()
>>> axis = dAxis(-10,10,-10,10)
>>> plot.show()``````

The first line creates the basic plot object. The second line created an axis object. The third associated the two and the fourth caused the plot to be drawn. If you are following along, you should have a rectangular window on your screen with an empty axis.

PxDislin objects support many options via attributes. The attributes are broken up into 'options' and 'info' types. Options refer to features of a plot that you might want to change after the object is created, perhaps to alter its appearance. Options are set by calling the objects `config()`. In pxDislin, calling `object.config()` is equivalent to calling `object().` In the above example click the right mouse button to clear the plot and type

``````>>>plot(ttext="Title")
>>>plot.show()``````

A new plot window should appear looking as before but with a title string. To see a list of options for a particular object, simply type the object name followed by an empty set of parenthesis.

``````>>> plot()

*dPlot:
app_look = console
color = fore
continue_key = Return
display_type = screen
external_ID = None
external_type = window
filename = dis.out
font = default
font_size = 36
height = 500
origin = (25, 25)
page_height = 3000
page_width = 3000
ps_origin = (25, 25)
pscript = None
pscript = None
psfont = courier
psfont = courier
scale = 1.0
screen_mode = normal
size = None
suppress_disout = 1
tsize = 64
ttext = test
width = 500
*END OBJECT: dPlot``````

Notice the nice additional feature of the command telling you what the current setting is for each option.

The info attributes directly affect the generation of the object (typically they contain the data to be plotted) and are set by using the . (dot) notation. The info attributes are typically passed into the object at creation time as parameters to the function.

Plot Routines

As with the basic DISLIN library, pxDislin contains high-level plot generating functions. Similar to the first example, creating a 2D plot in pxDislin is as simple as

``````>>> x=arange(100.0)
>>> y = sin(x/3)+cos(x/5)
>>> plot = dScatter(x,y)
>>> plot.show().``````

After which you should have

To retrieve the plot data, type `plot.xl` (`xl` is the info attribute holding the dependent variable). To see the list of info variables, type `object._info.` Following is an example showing the info parameters of the just generated scatter plot.

``````>>> plot._info
['axis', 'legend', 'title', 'xl', 'yl']``````

You can create 3D plots with pxDislin as well. The following recreates a previous example. Note that the `d3DSurface` object takes a function to be evaluated over a range as the first argument. The second and third arguments specify the start, stop and range of the x and y variables respectively.

``````>>> def f(x,y):
...     dtr = 3.1415 / 180.0
...     return(sin(x*3*dtr)*sin(y*2*dtr))
...

>>> plot = d3DSurface(f,(0,180.0,1),(0,180.0,1))
>>> plot.surface(clr_top=20)
>>> plot.surface(clr_bottom=230)
>>> plot.show()``````

End Game

With only a brief introduction to the DISLIN package, it is hard to see its full potential. In the coming articles there will more examples of its use and capabilities. I encourage you to read up on both DISLIN and pxDislin to discover for yourself the additional capabilities. Besides, who can resist making 3D color plots of interesting functions? A catalog of some basic plots and associated functions can be found here. Have fun!

With the introductions behind us, next month we will take a graphical look into the world of linear algebra. By using the tools of geometry we can gain some insight into the meaning of vectors and matrices.

Eric Hagemann specializes in fast algorithms for crunching numbers on all varieties of computers from embedded to mainframe.