Graph

Name

graph - 2D graph for plotting X-Y coordinate data.

Synopsis

graph pathName ?option value? …

Description

The graph command creates a graph for plotting two-dimensional data (X-Y coordinates). It has many configurable components: coordinate axes, elements, legend, grid lines, cross hairs, etc. They allow you to customize the look and feel of the graph.

Introduction

The graph command creates a new window for plotting two-dimensional data (X-Y coordinates). Data points are plotted in a rectangular area displayed in the center of the new window. This is the plotting area. The coordinate axes are drawn in the margins around the plotting area. By default, the legend is displayed in the right margin. The title is displayed in top margin.

The graph widget is composed of several components: coordinate axes, data elements, legend, grid, cross hairs, pens, postscript, and annotation markers.

Syntax

Example

The graph command creates a new graph.

# Create a new graph.  Plotting area is black.
graph .g -plotbackground black

A new Tcl command .g is also created. This command can be used to query and modify the graph. For example, to change the title of the graph to “My Plot”, you use the new command and the graph’s configure operation.

# Change the title.
.g configure -title "My Plot"

A graph has several components. To access a particular component you use the component’s name. For example, to add data elements, you use the new command and the element component.

# Create a new element named "line1"
.g element create line1 -xdata { 0.2 0.4 0.6 0.8 1.0 1.2 1.4 1.6 1.8 2.0 }\
        -ydata {26.18 50.46 72.85 93.31 111.86 128.47 143.14 155.85 166.60 175.38}

The element’s X-Y coordinates are specified using lists of numbers. Alternately, BLT vectors could be used to hold the X-Y coordinates.

# Create two vectors and add them to the graph.
vector xVec yVec
xVec set {0.2 0.4 0.6 0.8 1.0 1.2 1.4 1.6 1.8 2.0}
yVec set {26.18 50.46 72.85 93.31 111.86 128.47 143.14 155.85 166.60 175.38}
.g element create line1 -xdata xVec -ydata yVec

The advantage of using vectors is that when you modify one, the graph is automatically redrawn to reflect the new values.

# Change the y coordinate of the first point.
set yVector(0) 25.18

An element named e1 is now created in .b. It is automatically added to the display list of elements. You can use this list to control in what order elements are displayed. To query or reset the element display list, you use the element’s show operation.

# Get the current display list
set elemList [.b element show]
# Remove the first element so it won’t be displayed.
.b element show [lrange $elemList 0 end]

The element will be displayed by as many bars as there are data points (in this case there are ten). The bars will be drawn centered at the x-coordinate of the data point. All the bars will have the same attributes (colors, stipple, etc). The width of each bar is by default one unit. You can change this with using the -barwidth option.

# Change the X-Y coordinates of the first point.
set xVec(0) 0.18
set yVec(0) 25.18

An element named line1 is now created in .g. By default, the element’s label in the legend will be also line1. You can change the label, or specify no legend entry, again using the element’s configure operation.

# Don’t display "line1" in the legend.
.g element configure line1 -label {}

You can configure more than just the element’s label. An element has many attributes such as symbol type and size, dashed or solid lines, colors, line width, etc.

.g element configure line1 -symbol square -color red -dashes {2 4 2} -linewidth 2 -pixels 2c

Four coordinate axes are automatically created: x, x2, y, and y2. And by default, elements are mapped onto the axes x and y. This can be changed with the -mapx and -mapy options.

# Map "line1" on the alternate Y-axis "y2".
.g element configure line1 -mapy y2

Axes can be configured in many ways too. For example, you change the scale of the Y-axis from linear to log using the axis component.

# Y-axis is log scale.
.g axis configure y -logscale yes

One important way axes are used is to zoom in on a particular data region. Zooming is done by simply specifying new axis limits using the -min and -max configuration options.

.g axis configure x -min 1.0 -max 1.5
.g axis configure y -min 12.0 -max 55.15

To zoom interactively, you link the axis configure operations with some user interaction (such as pressing the mouse button), using the bind command. To convert between screen and graph coordinates, use the invtransform operation.

# Click the button to set a new minimum
bind .g <ButtonPress-1> {
    %W axis configure x -min [%W axis invtransform x %x]
    %W axis configure x -min [%W axis invtransform x %y]
}

By default, the limits of the axis are determined from data values. To reset back to the default limits, set the -min and -max options to the empty value.

# Reset the axes to autoscale again.
.g axis configure x -min {} -max {}
.g axis configure y -min {} -max {}

By default, the legend is drawn in the right margin. You can change this or any legend configuration options using the legend component.

# Configure the legend font, color, and relief
.g legend configure -position left -relief raised -font fixed -fg blue

To prevent the legend from being displayed, turn on the -hide option.

# Don’t display the legend.
.g legend configure -hide yes

The graph widget has simple drawing procedures called markers. They can be used to highlight or annotate data in the graph. The types of markers available are bitmaps, images, polygons, lines, or windows. Markers can be used, for example, to mark or brush points. In this example, is a text marker that labels the data first point. Markers are created using the marker component.

# Create a label for the first data point of "line1".
.g marker create text -name first_marker -coords {0.2 26.18} -text start -anchor se -xoffset -10 -yoffset -10

This creates a text marker named first_marker. It will display the text “start” near the coordinates of the first data point. The -anchor, -xoffset, and -yoffset options are used to display the marker above and to the left of the data point, so that the data point isn’t covered by the marker. By default, markers are drawn last, on top of data. You can change this with the -under option.

# Draw the label before elements are drawn.
.g marker configure first_marker -under yes

You can add cross hairs or grid lines using the crosshairs and grid components.

# Display both cross hairs and grid lines.
.g crosshairs configure -hide no -color red
.g grid configure -hide no -dashes { 2 2 }
# Set up a binding to reposition the crosshairs.
bind .g <Motion> {
    .g crosshairs configure -position @%x,%y
}

The crosshairs are repositioned as the mouse pointer is moved in the graph. The pointer X-Y coordinates define the center of the crosshairs.

Finally, to get hardcopy of the graph, use the postscript component.

# Print the graph into file "file.ps"
.g postscript output file.ps -maxpect yes -decorations no

This generates a file file.ps containing the encapsulated PostScript of the graph. The option -maxpect says to scale the plot to the size of the page. Turning off the -decorations option denotes that no borders or color backgrounds should be drawn (i.e. the background of the margins, legend, and plotting area will be white).

Graph operations

Graph components

A graph is composed of several components: coordinate axes, data elements, legend, grid, cross hairs, postscript, and annotation markers. Instead of one big set of configuration options and operations, the graph is partitioned, where each component has its own configuration options and operations that specifically control that aspect or part of the graph.

Axis components

Four coordinate axes are automatically created: two X-coordinate axes (x and x2) and two Y-coordinate axes (y, and y2). By default, the axis x is located in the bottom margin, y in the left margin, x2 in the top margin, and y2 in the right margin.

An axis consists of the axis line, title, major and minor ticks, and tick labels. Major ticks are drawn at uniform intervals along the axis. Each tick is labeled with its coordinate value. Minor ticks are drawn at uniform intervals within major ticks.

The range of the axis controls what region of data is plotted. Data points outside the minimum and maximum limits of the axis are not plotted. By default, the minimum and maximum limits are determined from the data, but you can reset either limit.

You can have several axes. To create an axis, invoke the axis component and its create operation.

# Create a new axis called "tempAxis"
.g axis create tempAxis

You map data elements to an axis using the element’s -mapy and -mapx configuration options. They specify the coordinate axes an element is mapped onto.

# Now map the tempAxis data to this axis.
.g element create "e1" -xdata $x -ydata $y -mapy tempAxis

Any number of axes can be displayed simultaneously. They are drawn in the margins surrounding the plotting area. The default axes x and y are drawn in the bottom and left margins. The axes x2 and y2 are drawn in top and right margins. By default, only x and y are shown. Note that the axes can have different scales.

To display a different axis or more than one axis, you invoke one of the following components: xaxis, yaxis, x2axis, and y2axis. Each component has a use operation that designates the axis (or axes) to be drawn in that corresponding margin: xaxis in the bottom, yaxis in the left, x2axis in the top, and y2axis in the right.

# Display the axis tempAxis in the left margin.
.g yaxis use tempAxis

The use operation takes a list of axis names as its last argument. This is the list of axes to be drawn in this margin.

You can configure axes in many ways. The axis scale can be linear or logarithmic. The values along the axis can either monotonically increase or decrease. If you need custom tick labels, you can specify a Tcl procedure to format the label any way you wish. You can control how ticks are drawn, by changing the major tick interval or the number of minor ticks. You can define non-uniform tick intervals, such as for time-series plots.

The default axes are x, y, x2, and y2. But you can display more than four axes simultaneously. You can also swap in a different axis with use operation of the special axis components: xaxis, x2axis, yaxis, and y2axis.

.g create axis temp
.g create axis time
...
.g xaxis use temp
.g yaxis use time

Only the axes specified for use are displayed on the screen.

The xaxis, x2axis, yaxis, and y2axis components operate on an axis location rather than a specific axis like the more general axis component does. They implicitly control the axis that is currently using to that location. By default, xaxis uses the x axis, yaxis uses y, x2axis uses x2, and y2axis uses y2. When more than one axis is displayed in a margin, it represents the first axis displayed.

The following operations are available for axes. They mirror exactly the operations of the axis component. The axis argument must be xaxis, x2axis, yaxis, or y2axis. This feature is deprecated since more than one axis can now be used a margin. You should only use the xaxis, x2axis, yaxis, and y2axis components with the use operation. For all other operations, use the general axis component instead.

Designates the axis axisName is to be displayed at this location. AxisName can not be already in use at another location. This command returns the name of the axis currently using this location.

Crosshairs component

Cross hairs consist of two intersecting lines (one vertical and one horizontal) drawn completely across the plotting area. They are used to position the mouse in relation to the coordinate axes. Cross hairs differ from line markers in that they are implemented using XOR drawing primitives. This means that they can be quickly drawn and erased without redrawing the entire graph.

The following operations are available for cross hairs:

Element components

A data element represents a set of data. It contains x and y vectors containing the coordinates of the data points. Elements can be displayed with a symbol at each data point and lines connecting the points. Elements also control the appearance of the data, such as the symbol type, line width, color etc.

When new data elements are created, they are automatically added to a list of displayed elements. The display list controls what elements are drawn and in what order.

The following operations are available for elements.

Specifies the data points of element elemName to be drawn using active foreground and background colors. ElemName is the name of the element and index is a number representing the index of the data point. If no indices are present then all data points become active.

Associates command with tagName such that whenever the event sequence given by sequence occurs for an element with this tag, command will be invoked. The syntax is similar to the bind command except that it operates on graph elements, rather than widgets. See the bind manual entry for complete details on sequence and the substitutions performed on command before invoking it.

If all arguments are specified then a new binding is created, replacing any existing binding for the same sequence and tagName. If the first character of command is + then command augments an existing binding rather than replacing it. If no command argument is provided then the command currently associated with tagName and sequence (it’s an error occurs if there’s no such binding) is returned. If both command and sequence are missing then a list of all the event sequences for which bindings have been defined for tagName.

Grid component

Grid lines extend from the major and minor ticks of each axis horizontally or vertically across the plotting area. The following operations are available for grid lines.

Legend component

The legend displays a list of the data elements. Each entry consists of the element’s symbol and label. The legend can appear in any margin (the default location is in the right margin). It can also be positioned anywhere within the plotting area.

The following operations are valid for the legend.

Pen components

Pens define attributes (both symbol and line style) for elements. Pens mirror the configuration options of data elements that pertain to how symbols and lines are drawn. Data elements use pens to determine how they are drawn. A data element may use several pens at once. In this case, the pen used for a particular data point is determined from each element’s weight vector (see the element’s -weight and -style options).

One pen, called activeLine, is automatically created. It’s used as the default active pen for elements. So you can change the active attributes for all elements by simply reconfiguring this pen.

.g pen configure "activeLine" -color green

You can create and use several pens. To create a pen, invoke the pen component and its create operation.

.g pen create myPen

You map pens to a data element using either the element’s -pen or -activepen options.

.g element create line1 -xdata $x -ydata $tempData -pen myPen

An element can use several pens at once. This is done by specifying the name of the pen in the element’s style list (see the -styles option).

.g element configure line1 -styles {myPen 2.0 3.0}

This says that any data point with a weight between 2.0 and 3.0 is to be drawn using the pen myPen. All other points are drawn with the element’s default attributes.

The following operations are available for pen components.

Postscript component

The graph can generate encapsulated PostScript output. There are several configuration options you can specify to control how the plot will be generated. You can change the page dimensions and borders. The plot itself can be scaled, centered, or rotated to landscape. The PostScript output can be written directly to a file or returned through the interpreter.

The following postscript operations are available. pathName postscript cget option

Returns the current value of the postscript option given by option. Option may be any option described below for the postscript configure operation.

Marker components

Markers are simple drawing procedures used to annotate or highlight areas of the graph. Markers have various types: text strings, bitmaps, images, connected lines, windows, or polygons. They can be associated with a particular element, so that when the element is hidden or un-hidden, so is the marker. By default, markers are the last items drawn, so that data elements will appear in behind them. You can change this by configuring the -under option.

Markers, in contrast to elements, don’t affect the scaling of the coordinate axes. They can also have elastic coordinates (specified by -Inf and Inf respectively) that translate into the minimum or maximum limit of the axis. For example, you can place a marker so it always remains in the lower left corner of the plotting area, by using the coordinates -Inf,-Inf.

The following operations are available for markers.

Bitmap markers

A bitmap marker displays a bitmap. The size of the bitmap is controlled by the number of coordinates specified. If two coordinates, they specify the position of the top-left corner of the bitmap. The bitmap retains its normal width and height. If four coordinates, the first and second pairs of coordinates represent the corners of the bitmap. The bitmap will be stretched or reduced as necessary to fit into the bounding rectangle.

Bitmap markers are created with the marker’s create operation in the form:

Image markers

A image marker displays an image. Image markers are created with the marker’s create operation in the form:

Line markers

A line marker displays one or more connected line segments. Line markers are created with marker’s create operation in the form:

Polygon markers

A polygon marker displays a closed region described as two or more connected line segments. It is assumed the first and last points are connected. Polygon markers are created using the marker create operation in the form:

Text markers

A text marker displays a string of characters on one or more lines of text. Embedded newlines cause line breaks. They may be used to annotate regions of the graph. Text markers are created with the create operation in the form:

Window markers

A window marker displays a widget at a given position. Window markers are created with the marker’s create operation in the form:

Graph component bindings

Specific graph components, such as elements, markers and legend entries, can have a command trigger when event occurs in them, much like canvas items in Tk’s canvas widget. Not all event sequences are valid. The only binding events that may be specified are those related to the mouse and keyboard (such as Enter, Leave, ButtonPress, Motion, and KeyPress).

Only one element or marker can be picked during an event. This means, that if the mouse is directly over both an element and a marker, only the uppermost component is selected. This isn’t true for legend entries. Both a legend entry and an element (or marker) binding commands will be invoked if both items are picked.

It is possible for multiple bindings to match a particular event. This could occur, for example, if one binding is associated with the element name and another is associated with one of the element’s tags (see the -bindtags option). When this occurs, all of the matching bindings are invoked. A binding associated with the element name is invoked first, followed by one binding for each of the element’s bindtags. If there are multiple matching bindings for a single tag, then only the most specific binding is invoked. A continue command in a binding script terminates that script, and a break command terminates that script and skips any remaining scripts for the event, just as for the bind command.

The -bindtags option for these components controls addition tag names which can be matched. Implicitly elements and markers always have tags matching their names. Setting the value of the -bindtags option doesn’t change this.

C language API

You can manipulate data elements from the C language. There may be situations where it is too expensive to translate the data values from ASCII strings. Or you might want to read data in a special file format.

Data can manipulated from the C language using BLT vectors. You specify the X-Y data coordinates of an element as vectors and manipulate the vector from C. The graph will be redrawn automatically after the vectors are updated.

From Tcl, create the vectors and configure the element to use them.

vector X Y
.g element configure line1 -xdata X -ydata Y

To set data points from C, you pass the values as arrays of doubles using the Blt_ResetVector call. The vector is reset with the new data and at the next idle point (when Tk re-enters its event loop), the graph will be redrawn automatically.

#include <tcl.h>
#include <blt.h>

register int i;
Blt_Vector *xVec, *yVec;
double x[50], y[50];

/* Get the BLT vectors "X" and "Y" (created above from Tcl) */
if ((Blt_GetVector(interp, "X", &xVec) != TCL_OK) ||
    (Blt_GetVector(interp, "Y", &yVec) != TCL_OK)) {
    return TCL_ERROR;
}

for (i = 0; i < 50; i++) {
    x[i] = i * 0.02;
    y[i] = sin(x[i]);
}


/* Put the data into BLT vectors */
if ((Blt_ResetVector(xVec, x, 50, 50, TCL_VOLATILE) != TCL_OK) ||
    (Blt_ResetVector(yVec, y, 50, 50, TCL_VOLATILE) != TCL_OK)) {
   return TCL_ERROR;
}

See the vector manual page for more details.

Speed tips

There may be cases where the graph needs to be drawn and updated as quickly as possible. If drawing speed becomes a big problem, here are a few tips to speed up displays.

Limitations

Auto-scale routines do not use requested min/max limits as boundaries when the axis is logarithmically scaled.

The PostScript output generated for polygons with more than 1500 points may exceed the limits of some printers (See PostScript Language Reference Manual, page 568). The work-around is to break the polygon into separate pieces.