IaGraph Manual

Introduction

This is a package of interactive graphing tools, built upon the Climate Data Analysis Tools (CDAT) suite produced by the Program for Climate Model Diagnosis and Intercomparison (PCMDI) at Lawrence Livermore National Laboratory (LLNL). The package will create line plots, scatter plots, and contour plots with a single line of Python code.

Sometimes the plot generated will also be suitable for publications, and procedures in this package will allow you to write those plots to a Postscript or GIF file, but usually you will want a more complex plot for publications, which this package cannot make. If you want a graphing package for Python that has more features, here are some you might want to look at: CDAT, ChartDirector, DISLIN, gmt, GracePlot, Matplotlib, and SciPy.

What distinguishes this package from other plotting packages for Python is the emphasis on graphing using a single line of Python code. Other packages do not require much more code (maybe 3-5 more lines), and in fact this package uses those other graphing packages to make its graphs. But for the purposes of interactive plotting, 3 lines is 2 lines too many. I try to emulate IDL (Interactive Data Language) syntax (though not IDL array indexing, since Python and IDL index their arrays completely differently).

The home page for the package contains the package license, installation and downloading instructions, a complete listing of package contents, help for the modules, and probably all the description and examples most users need to use the package. Most users can ignore this manual you're currently reading.

That being said, this manual describes the programming logic behind the package and also contains a more detailed description of the capabilities of this package.

The manual is subdivided into these categories:


Package Logic

General

Because the package is designed to be used for interactive plotting, I use a procedural logic instead of object-oriented or functional. Thus, all key commands are called as procedures instead of functions or methods. I also try to emulate the IDL direct graphics structure. IaGraph is built upon CDAT's Visualization Control System (VCS).

VCS works by decomposing the elements of a graph into objects and placing those objects onto a VCS canvas. Up to 8 VCS canvases can be defined at one time in a Python session. In IaGraph, each time a graph is created (e.g. with a plot or contour command), a new VCS canvas is created onto which the plot is placed. This new canvas is then set as the "active canvas" stored in the IaGraph "system variables" class (Sysvar), to enable us to manipulate the plot even after rendering. Any previous active canvas stored in the system variables class is cleared then overwritten when a new plot is created. Note that since when a new plot is created the existing active canvas is used, the new plot does not contribute to the 8 VCS canvas limit. Only when a new window is opened (using the window command) and a plot made in this new window is another VCS canvas initialized.

System Variables

Besides storing the active canvas, global control over many plot settings is accomplished through Sysvar (which is defined in __init__.py). The system variables are all class attributes of Sysvar; Sysvar has no instance variables (although class attributes are changed via a class instance). Thus, all system variables are available once IaGraph is imported, are available to all instances of the class, and will persist as long as the Python session is open. Admittedly, this is not very pretty and smacks of a Fortran common block. It was, however, the only way I could think of of allowing some level of global control over IaGraph plots.

The syntax of the Sysvar class is similar to IDL syntax. For instance, the main plotting system variables in IDL (!P variables) are prefixed by p_ in Sysvar. Likewise, axes system variables (!X and !Y in IDL) are prefixed by x_ and y_ in Sysvar. Because Sysvar attributes are all class attributes it's best to refer to an attribute with the __class__ tag. Thus, if sysvar (= IaGraph.Sysvar()) is a realization of Sysvar, the x-axis VCS font code is sysvar.__class__.x_font.

The default values for a number of the parameters in the plotting commands are all set as an attribute of Sysvar. Through system variables you can also control some aspects of a plot that are not controllable via a procedure keyword, or to directly supercede the internal defaults of a procedure. Procedures generally use the following logic in deciding which value to use for a parameter, if there is more than one choice:

  1. If the parameter can be set by a keyword, the keyword value is always used if its value isn't None.
  2. If the keyword value is None, the value of the corresponding system variable is used.
  3. If the value of the corresponding system variable is None, the procedure assigns a local default setting for that parameter.

Note that p_, x_, and y_ system variables are never (at least I think are never) changed by an IaGraph procedure. The only system variables that are changed by IaGraph procedure(s) are the active_canvas, active_canvas_base_gm, active_canvas_base_tpl, inactive_canvases, inactive_canvases_base_gm, and inactive_canvases_base_tpl attributes.

A number of plot attributes can be controlled via system variables, including: font and font height of overall title, axes titles, and axes tick labels. Sysvar also allows you to directly control which ticks are labeled: set [xy]_tickvalues. This is particularly useful if you want to have non-numeric labels, such as latitude/longitude values. For more information on changing graphics properties via system variables see here. Remember, once you change the setting of a system variable, that setting is retained for the rest of the Python session, until it is changed again!

A full list of all Sysvar attributes (and their default values) is found here. The precise rules of how a procedure chooses its parameter settings can be viewed via the help command for the procedure.

Procedures

Plots are created and manipulated via procedures and either create or operate on the active canvas, as stored in the active_canvas attribute in the Sysvar class. There are 2 exceptions: the loadct procedure and helper functions.

The procedures that create an active canvas (and overwrite any previously existing active canvas) are: contour, plot, and plotct. The procedures that operate on an active canvas (and do not change anything in the active canvas) are: active2gif and active2ps.

The loadct takes a VCS canvas and specified color map index (passed in as the two positional arguments) and sets the active color map for that canvas to the specified map. For consistency with the rest of the package, loadct should have operated on the active canvas, but for some reason Python won't let me. This workaround worked, so for this one key procedure I had the canvas passed in as an argument.

Helper functions can be procedural or functional. Usually they do tasks that are non-central to the package and thus are not available with a from IaGraph import * command. One example of this is wavelen2rgb which returns an RGB triple given a wavelength of visible light. To use helper functions, you'll have to import them via their full package/module pathname. Thus, for wavelen2rgb import it via: import IaGraph.wavelen2rgb.wavelen2rgb as wavelen2rgb.

[Back up top to the Introduction.]


X-Y Line and Scatter Plots

The plot command creates both line and scatter plots, since scatter plots are just line plots without the lines. The default of plot is to make a line plot with solid connecting lines and a square as the plot symbol. You can change the line type through the linestyle keyword and plot symbol through the psym keyword. To remove connecting lines, set psym to a value greater than zero. Negative psym plots connecting lines and a psym of 0 gives a line plot without any plot symbols. Here are lists of the available plot symbols and line styles:

Note that for the "dash" linestyle, the VCS routine I use to dump plots to Postscript and GIF does not seem to reproduce the dash spacings as they appear on screen; the dashes are much closer together in the Postscript and GIF versions. Thus, I'd recommend you use "long-dash" if you want a readable dash.

Plot symbol size is controlled by the symht keyword. The default value of 7 gives squares that have an approximate on-screen size of 2 mm.

Keywords shared in common between plot and other plotting procedures (e.g. contour) are described here.

The plot procedure is somewhat special in that while CDAT is the dependency you wish to have in order to get full performance from the routine, plot will still provide some functionality if you only have Grace and gracePlot installed, or even if you only have the Tk widgets in the ScientificPython package installed. See the help for plot for details.

[Back up top to the Introduction.]


Contour Plots

The contour command can produce three types of contour plots: plots with contour lines only, plots with smooth, filled contours, and plots with both filled contours and lines overlain. When contour lines are plotted, negative contours are long-dashed and positive contours are solid. Contour defaults to plotting both filled contours with lines overlain, along with a color bar key below the plot. Obviously if only contour lines are plotted, there's no color bar key plotted. If you are doing filled contours and wish to suppress the color bar, set keyword colorbar to 0.

The procedure defaults to automatically calculate contours for you. The system variable p_maxnlev sets the maximum number of level intervals that will be allowed in this automatically calculation. If you want specific keywords, specify them through the c_levels keyword.

You can choose which color table to use in the filled contours via the ctindex keyword. The command loadct() will list all available values. The default is 13 (rainbow, violet to red, 390-680 nm).

Continents are turned off by default. To plot outlines of modern continents, set the continents keyword to a non-zero value.

[Back up top to the Introduction.]


Color Tables

The procedure loadct will set a color map for the VCS canvas that is passed into loadct. All plotting procedures that use a color map (e.g. contour) set the active color map using loadct; the color map is specified to the plotting routine via the ctindex keyword.

A list of the color maps defined in loadct is found here.

If you wish to add your own color map, I'd suggest you just hack the code for loadct. Just add an additional elif statement after the elif block that selects the default color map (i.e. after the "elif cmap_index == 99:" statement). In your new elif block, assign a color map index to be the loadct reference to your color map, and set all values of loadct_cmap.index[i] to RGB triples, for indices i from 16 to 239, inclusive.

[Back up top to the Introduction.]


Writing Plots To File

The active canvas (stored in system variable active_canvas) can be written to a Postscript file using active2ps and a GIF file using active2gif.

The active2ps routine writes the plot to landscape. The active2gif routine also writes to landscape. However, the GIF file is not rotated 90 degrees like the Postscript file is, so you can view the file without having to rotate the image. Both routines will replace any prexisting graphics file of the same name.

[Back up top to the Introduction.]


Miscellaneous Procedures

plotct: Produces a plot of a loadct color table, with values of color indices shown. You can use this to visualize what the color map you're using will look like. This procedure creates a new plot and overwrites and existing active canvas.

[Back up top to the Introduction.]


Graphics Keywords and System Variables

Keywords

The plot and contour procedures share some keywords. Here we describe how to use those keywords:

annot: The placement of axes titles and the overall title is pretty standard, and so I won't discuss them. However, I've added an additional annotation feature to the plot generation routines (e.g. plot, contour) that I think I should probably explain a little. Often I like to add additional information about what a plot contains, how it was made, etc.; this information I plot out at the top of the page in small type. The annot keyword enables you to include such text.

If the keyword is defined, the default values of position adjust to give you more space at the top of the page to add the annotation. The size of the plot isn't changed, but the location on the page is.

position: The position of the plot on the page can be moved by the position keyword or its system variable equivalent. This keyword is a 4-element list [bbllx, bblly, bburx, bbury] of the bounding box (x,y) coordinates in normalized values. The data origin is the lower-left corner, and the upper-right corner of the data box is the upper-right corner of position.

[xy]range: The xrange and yrange keywords allow you to control what part of the x- and y-axes are plotted. Each keyword accepts a 2-element list of minimum and maximum values specifying the interval. Note that these keywords set the range of the [xy]-axis used to calculate "neat" tickmarks, from which the actual axis range is set; depending on what the [xy]range values are, the actual plot range may look different. If you want the range to be precisely certain values, set them through the [xy]_tickvalues system variable. The [xy]_range system variables do the same thing as the [xy]range keywords. If you wish to directly control axis tick labels, set the [xy]_tickvalues system variable.

title: String scalar specifying the overall title.

[xy]title: String scalar specifying the [xy]-axis title.

System Variables

A number of graphics attributes, besides those with an equivalent graphics keyword (noted above), can be controlled via system variables. The programming logic of systems variables is described here. The Sysvar class docstring documentation provides enough details (along with a list of the default values) for most of the variables. Here we describe how to change graphics settings for system variables that could use some more description. In all the examples given, we assume that:

sysvar = IaGraph.Sysvar()
is an instance of the Sysvar class. Remember, since all system variables are Sysvar class attributes it is good practice to refer to those attributes with the __class__ attribute, e.g. sysvar.__class__.p_font.

Font Type and Height: p_font changes the font of the overall title, while [xy]_font sets the font of the axes text. The font code is an integer that follows the VCS code for font.

The height is set for overall graphics and the axes text through the p_fontht and [xy]_fontht system variables, respectively. This is an integer and is in arbitrary units. You can approximately convert these values to normalized units by multiplying by p_fontht2norm. A setting of 40 font height units gives capital letters that are approximately 1/4 inch on screen (assuming landscape orientation output).

Ticks: The p_ticklen variables gives general tick lengths, in normalized units. Axes tick lengths are specified by [xy]_ticklen.

The plotting routines, by default, calculate the number of tick marks based upon a "nice" division of the axes ranges. The maximum number of ticks that will be allowed in this default calculation is controlled by [xy]_tickmaxnum.

You can also directly set the x- and y-axis tick labels through [xy]_tickvalues. This system variable is a dictionary where the dictionary key is the tick marks' numerical value and the dictionary value is a string labeling each tick mark.

Remember, once you change the setting of a system variable, that setting is retained for the rest of the Python session, until it is changed again! Thus, if you change the font height system variable, all subsequent IaGraph plots made during that Python session will use that height.

[Back up top to the Introduction.]


Coding Tricks

The code is pretty well-commented, so you should be able to read it to figure out what it does. However, there are a few design decisions I made that I thought I should point out.

The first one I wanted to point out because it could result in you running out of memory if you make a zillion plots. Because every time you make a plot you need to create a whole bunch of VCS objects, the question comes what you should name these objects. A static name isn't any good, because if you have a multiplicity of plots, there's no guarantee that each plot's object of the same name will be identical (in fact, the reverse is usually true). And since I wanted the capability of being able to go back to any plot in memory at will and revising it (which requires all component objects to remain defined for the duration of the plot's life), I needed to create a naming system that gave every VCS object a unique name. (Additionally, I couldn't figure out a way to remove a name from the VCS object list, if the object itself isn't defined, so even if I saved the names of all VCS objects I wanted removed, I couldn't remove them because the local objects that instantiated the list entry are undefined after the procedure exits.)

Thus, the VCS objects created by IaGraph all have a suffix based upon the system time, in fraction of a second. The suffix is long enough to guarantee no reuse of names for at least 100 days; as long as the Python session is closed before then, every name will be guaranteed to be unique.

Unfortunately, as long as you don't close your Python session, all VCS objects created during that session will remain defined. If you make many plots, this could result in many VCS objects being created, which may result in you running out of memory. I don't know when this limit is reached; no problems resulted when I made 100 consecutive simple x-y plots in one window during one session on my modest Linux box (which has 255 Mb memory and 498 Mb swap).

The second design decision regards the names of the graphics method and template objects (again here I mean the name that shows up in a show method, not the name of an object instance). In the all the routines of the package, I assume the following is true:

The third decision was to store the names of the base graphics method and template used on a canvas as a system variable. By "base" I mean the graphics method and template used when the plot was first created (e.g. by a plot or contour command). I stored these values as system variables in order to retrieve the definitions of plot range, and other settings, for overplots.

Finally, the plot command uses the xvsy graphics method for both the cases when you have connecting lines and when you do not. I do this by assuming the background color is white and setting the line color to white when you have the case of no connecting lines. However, since oplot might be plotting over a filled contour plot, in oplot I do not assume that the background color is white and go through the extra work of using the scatter graphics method to take care of the case when there are no connecting lines.

[Back up top to the Introduction.]


Troubleshooting

Here's a list of some glitches that periodically arise. I list these separately from my bugs list since they're not worth fixing and reasonably easy to work-around.

Date Problem Fix
16 Jun 2004 There is a substantial difference in rendering time if you close a window manually and then plot another plot vs. keeping that window open and plotting another plot into that existing window. I don't know why this happens. For now I'd manually close the window if you want it to be faster.
09 Jan 2004 When I make a zillion plots, I run out of memory. Close the Python session and restart. See the coding tricks discussion above.
22 Dec 2003 Sometimes, the plot doesn't render exactly like you expect. For instance, a filled contour plot with contour lines will only print contour lines. This seems to be an inconsistent problem and I don't know why it happens. The fix: quit out of that Python session and re-run the script. Doing that once or twice has always fixed the problem for me.

[Back up top to the Introduction.]


Future Work

Here's a partial list of improvements that need to be made in this package:

[Back up top to the Introduction.]


Copyright Notice for Manual

Copyright © 2003-2004 Johnny Lin. Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.2 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license can be found here.

The Transparent copy of this document is located at http://www.johnny-lin.com/py_pkgs/IaGraph/Doc/manual.html.

[Back up top to the Introduction.]


Return to IaGraph Home Page.
Return to Johnny Lin's Python Library.

Updated: June 16, 2004 by Johnny Lin <email address>.