Graphics Tools



  1. Making Simple Plots
  2. Higher-dimensional Data
  3. Unix Pipe
  4. Gpl
  5. plot_image.py

Dealing with Data

This section contains a brief introduction to some of the graphics tools available on the Drexel Physics computer lab.

Programs--scientific ones, at least--tend to generate lots of data. You have already seen examples of this in the C-language primer document, and you will see many more. Once, you had little choice as to what you could do with those data. You could only print it out and look at it in the form of columns of figures on the screen. Pretty dull...!

Often, the best way to represent a large dataset is in graphical form. At its simplest, this may just mean drawing simple line graphs. In more sophisticated contexts, you may end up making an elaborate 3-D movie, complete with audio track, to illustrate the Physics and explain your findings to others. Such sophisticated visualization is more an art than a science, and usually calls for specialized hardware and software (although you can actually get quite far without leaving our lab).


Making Simple Plots

Drawing a Graph

Let's begin by describing the steps we must take to plot a simple graph (e.g. to make a graph of the ``sine'' tabular data produced by one of the early examples in the C primer). For the sake of readability, and for the convenience of the plotting routines, let's imagine that the data are written out (to a file or just to stdout) in the form of columns: x y1(x) y2(x) .... As a reminder, and as a way of generating data for plotting purposes, here is a short program that does what we need:

#include <iostream>
#include <cmath>>

#define N_POINTS 1000
#define XMIN 	 0
#define XMAX 	 (4 * M_PI)	/* this is just 4 PI; M_PI defined in math.h */

main()
{
    int i;
    double x;

    for (i = 0; i < N_POINTS; i++) {
	x = XMIN + i * (XMAX - XMIN) / (N_POINTS - 1);
        cout << x << "  " << sin(x) << "  " << cos(x) << "  \n";
    }
}

This will produce 3 columns of data, with 1000 rows in each, listing the values of x, sin x and cos x, for values of x linearly spaced between 0 and 4 PI.

In the simplest possible case, to draw a graph of, say sin x versus x (column 2 versus column 1), we must do the following:

Naturally, X provides all the necessary primitive (low-level) machinery to do all this, and you can do all your own graphics relying purely on function calls to the X libraries if you so desire. However, this is usually quite cumbersome and unpleasant to program. Instead, we provide several simpler, if more limited, means of handling graphical data.

gnuplot

A very simple, yet very powerful, plotting package is the public domain gnuplot. This package is well maintained, well documented, widely used and capable of producing professional quality graphs. You can find details about it in home page and tutorial

As a way to practice, use the program above to generate data to be plotted in gnuplot. If the program is stored in c1.c, do

These commands will compile the code, run the code and pipe the data in a file c1.dat respectively.

Then invoke gnuplot and plot via

The with keyword specifies how to draw the data points: drawing a line between points, points, lines between the x-axis and the data points, lines and points, or small dots. Each keyword can be brutally abbreviated, e.g., w can be used for with. lw specifies the line width (default 1). lt specifies a line type and ls specifies a line style. The command test shows the default line types. ps specifies the point size.

Gnuplot allows much customization and flexibility. For instance you can specify line style 55 (arbitrary number) of a given color and width and plotting with line only or with lines AND points.

You can identify your graphs via

Help can be obtained with "?" as in "?plot". "quit" or "q" terminates gnuplot.


Higher-dimensional Data

Contours and Surfaces

Line plots such as those produced by gnuplot are fine when the dataset consists of a single independent variable. However, we very often want to plot datasets in which the value of some function depends on two (or more) independent variables. Visualizing problems with three or more independent variables is hard, but for two-dimensional problems -- looking at the data f(x, y), say -- we have a variety of approaches open to us.

Using Gnuplot

Gnuplot is capable of producing surface plots based on a specific function f(x,y) or on a data set read in from a file. The following simple program produces some sample image data on a 2-Dimensional numerical grid.


//                       sin*cos program
//                       
//              Illustrates a surface defined by f(x,y) 

#include <iostream>
#include <cmath>>

#define N_POINTS 250

main()
{
    int i, j;
    double x, y, z;

    for (j = 0; j < N_POINTS; j++)
	for (i = 0; i < N_POINTS; i++) {
	    x = 2*i*M_PI/(double)(N_POINTS-1);
	    y = 2*j*M_PI/(double)(N_POINTS-1);
            z = (1 + sin(x)*cos(y));
	    std::cout << x << " " << y << " " << z << " \n";
	}
}

Compile this program, and run it with a pipe into a file sin_cos_data. Start gnuplot and issue

This will produce a scatter plot of the data points. These points specify a surface. You could also use the "points" or "lines" options, but the figure will be crowded due to the high number of grid points.

Gnuplot can also produce contour plots. This is somewhat complicated in this case since the data is given numerically from a file. The idea is to let gnuplot know that the data is given numerically on a grid of size 200x200 (third number is a weight to be ignored), enable the contour option and plot the surface AND the contour lines.

The set and unset commands allow to specify the values of variables in gnuplot or to free up these variables. You can request more contour levels by

Gnuplot can show the contour map only if desired. This is achieved by removing the "surface" and changing the observation point to one above the x-y plane.

There are numerous examples of how to create surface and contour plots of data and functions in the gnuplot homepage.

Isn't it better in color?

A very commonly used technique for displaying two-dimensional data is to make an image. This has the considerable advantage of enlisting the assistance of the many image-display and image-processing programs that exist in the public domain. In addition, images can be easily combined to make movies.

The idea of representing data by an image is very simple. The data are calculated on a rectangular grid in x and y, of dimension m by n, say. Each pixel in the final image represents a point in that grid, and the color assigned to the pixel represents the value of f(x,y) at that point. The mapping between the value of f and the color assigned is entirely up to the programmer. Typically it is chosen to enhance or emphasize certain features of interest in the data.

Often the color resolution of our screens allows us to display up to 256 colors simultaneously. This number is chosen because integers in the range 0 to 255 can be represented using a single byte of data--an unsigned char in C. Of course, there are many ways to choose these colors. The mapping between the integers 0 to 255 and the final color that appears on the display is called a color map. The standard color map we might use looks like this:

There is no particular reason for this choice--it is simply convenient. Small numbers correspond to blue, large numbers to red, and intermediate numbers to intermediate colors in the ``spectrum''.

To X, an image is a collection of bytes, one per pixel, along with a color map telling the display how to ``paint'' the screen. There are many different image formats in use -- gif, jpeg, miff, xpn, to name but a few. Fortunately, we don't have to know how to construct them all. The program convert allows us to turn one into another.

Gnuplot allows to create color images. For instance, the following will create a color image of the data set we look at previously.

You can create your own color palette as well. For instance

will create a palette built on 4 colors with a very different feel than previously.

Matrix notation

Gnuplot can read the 2D data on an equally spaced grid via a matrix notation. Namely, the following Gnuplot statements could plot an image of the data

The file matrix_dat should contain the data in row/coluumn notation, as would be written by the code







//                       sin*cos program
//
//              Illustrates a surface defined by f(x,y)
//
//                       Matrix format output
//
#include <iostream>
#include <cmath>>

#define N_POINTS 250

main()
{
    int i, j;
    double x, y, z;

    for (j = 0; j < N_POINTS; j++)
        for (i = 0; i < N_POINTS; i++) {
            x = 2*i*M_PI/(double)(N_POINTS-1);
            y = 2*j*M_PI/(double)(N_POINTS-1);
            z = (1 + sin(x)*cos(y));
            std::cout << " " << z ;
        }
        std::cout << "\n";
}


Note that the x- and y-coordinate are labeled by a matrix notation, the actual values being lost. But it is so simple...

There are numerous examples of how to create color images of data and functions on the gnuplot homepage. There are also many examples of color palettes.


Unix Pipe

One of the great advantage of the Unix Operating System is the concept of the Unix pipe by which different processes can communicate with each other. We have already seen how to redirect the stdout stream of a process to a file, or a file into the stdin stream of a process, via the operators > or <. Processes can also communicate directly with each other by redirecting the stdout stream of a process to the stdin stream of a second process via the pipe operator |. Unix also allow processes to fork other processes and to communicate with them. Gnuplot is written to fully take advantage of these Unix pipes.

Gnuplot Scripting

The first and simplest use of the Unix pipe to communicate with gnuplot is via scripting the gnuplot commands. The commands to be executed by gnuplot are simply typed (via emacs) in a file which is piped into gnuplot.

For instance, the file gnuplot_script could contain

#
#   example of a gnuplot script file
#
set title "a simple plot"
plot "data_file" using 1:2 with dots
quit

This file is then piped in gnuplot via the syntax

gnuplot -persist < gnuplot_script

The keyword -persist guaranties that the plot will stay in the window until you type q. Not using this keyword will cause gnuplot to close the plot immediately once drawn.

This scripting capability allows the user to develop complicated plots piecewise and record the way in which they were produced. This provides a way to submit your work in assignments.

Interactive data entry

Gnuplot allows to enter small data sets interactively. Namely, the - operator in place of a file name as in

plot "-" u 1:2 w lines

opens up an interactive query for data which remains active until e is entered.

Code activation and pipe from gnuplot

Gnuplot supports code activation and piping within the "plot" command. Namely,

plot "< ./executable_code" using 1:2 with lines

will launch the executable executable_code in the local directory and accept the data it outputs in stdout for plotting.

This syntax is very powerful in that it embodies fully the Unix pipe concept and avoids the creation of data files. When combined with gnuplot scripting this becomes a very powerful technique to facilitate your work.

Gnuplot activation and pipe from user codes

A user C code can also activate gnuplot and pipe a gnuplot script into it. For instance, the following code

//
//           to illustrate the use of C pipes
//           to communicate with gnuplot
//
//                      Michel Vallieres

#include <stdio.h>
#include <math.h>

int main()
{
  FILE *fp;

  fp = popen( "gnuplot -persist", "w" );

  fprintf( fp, "set title \'Whatever\'\n" );
  fprintf( fp, "plot \'data_file\' using 1:2 with lines\n" );
  fflush( fp );

  sleep(5);
  fprintf( fp, "quit\n" );

  pclose( fp );
}

launches gnuplot with a persist option, pipes commands to plot the data in column 1 and 2 in the file data_file and quits. Try the code with the following simple data.
1 2
2 1
1.1 1.2
1.5 0.5
2.7 0.7

The following C and C++ codes (identical in function) illustrate the very similar syntax to set-up these graphics in the two languages.

sample code

popen()

The launch of gnuplot in the previous section was done via a call to popen(). Any C or C++ codes can launch other executables (or itself) and communicate with them. This is generally done via the fork() and pipe() calls. This is clearly beyond what we need for this course. However, the popen() call simplifies this whole procedure.

popen( executable, type )

launches an executable and opens a pipe to communicate with it. For convenience, the communication fully follows the syntax used in reading/writing from/to a file. The pipe channel can either read from the launched process (type ``r'') or write to the launched process (type ``w''), but not both. The pipe will either read from stdout of the launched process or write to its stdin depending on the type specified in the popen() call.

The following three codes illustrate the use of popen(): code_main.c, code_a.c, and code_b.c Compile each code. It is important that the executables be called code_main, code_a and code_b. Then run code_main. It will launch the other two codes and communicate with them.

Study these simple codes well. They illustrate the notion of parallel computing in which multiple processes work together toward a task.


Gpl

Gpl is a tcsh script to be used as a front-end to gnuplot. It allows to plot simple x-y plots in a Unix pipe with very simple syntax. The options are ( listed by gpl --help )

 
    gpl:       minimal subset of gnuplot commands, with data from stdin
    
    Options:   -c i j k...     columns to plot (x y1 y2...)       [1 2]
               -f              linear fit to first plot            [no]
               -F x1 x2        x limits to fit            [plot limits]
               -g    specify X-window geometry     [xdefault]
               -G              toggle PNG graphics output         [off]
               -h header       specify an overall header         [none]
               -k              suppress key giving column info     [no]
               -l x1 x2 y1 y2  specify plot limits          [automatic]
               -L size         specify plot limits (+/- L)  [automatic]
               -p              toggle points/lines             [points]
               -P              toggle PostScript output           [off]
               -s script       save the script in the named file   [no]
               -x              specify x-label                   [none]
               -y              specify y-label                   [none]
               -Y a b ...      specify plot labels    ["column j", ...]
The script works by first copying the piped data into a temporary file in /tmp. It then creates a gnuplot script that implements the required options in /tmp. It finally launches gnuplot to execute the script and erases the tmporary files. You can list the script by typing
more /usr/bin/gpl

Dr. McMillan wrote and maintains Gpl. A description of it can be found in PHYS105.

plot_image.py

At times it may be advantageous to produce map images based on a 2D function f(x,y) with minimum interpolation. Unfortunately, this is difficult to do in Gnuplot. The python program plot_image.py does exactly this.

The program plot_image.py accepts the values of f(x,y) on an x - y lattice though a pipe in stdin. Download the code. Make the code executable. This program is a python code based on functions found in matplotlib.

The calling syntax of plot_image.py is

./executable | ./plot_image.py -s Nx Ny -c nc [-h] [-g] -t title
The size of the image in pixels is specified as a command line argument (-s Nx Ny, dimension of the x - y grid). The program also accepts the optional -h or -g which specify alternate color palettes. The -t title specifies a plot title. The -c nc argument toggles on the contour display with nc lines.

The following simple codes can be used to practice the use of plot_image.py. gen data.c and gen_data_rectangle.c produce sin() cos() based data on square (200x200) and rectangular (300x200) lattices. Gen_data_sharp.c produces a two-color image (2 value data) with a sharp boundary.

Details:

#
#   plot_image.py
#
#   Step 1: make this file executable
#
#           chmod +x plot_image.py
#
#   Step 2: pipe data in python script
#
#           ./gen_data | ./plot_image -s nx ny -c nc -t 'image title'
#
#   with optional arguments
#          -s nx ,ny    image size [16x16]
#          -c nc        number of contour levels [none]
#          -t ' '       image title ['some like it hot']
#
#   additional:  -g  gray map  [jet map]
#                -h  hot map
#
#   ref: matplotlib web site