Features


A Versatile Plotting Routine

Lowell Smith


Lowell Smith is a retired aerospace engineer (Hercules Aerospace Company). He first programmed in Fortran in 1962 on the IBM-1620, then later on the IBM-1130 and various IBM-360/370 models. After getting an IBM PC in 1982, he began using Pascal and C. He has never worked as a programmer, but has programmed many engineering applications over the years. He can be reached via 73377. 501@compuserve.com.

Introduction

While developing programs that generate data which needs to be presented in graphical form I have often wanted a general purpose function for creating both screen display and hard copy from within the program. The basic requirements include:

The function SPLOT was developed to meet those requirements. It requires a VGA monitor. (CGA and EGA monitors are rapidly becoming obsolete, and I don't consider their graphics acceptable.)

All plotting is done in straight line segments. The calling program must provide enough points to give the desired resolution for curves. Horizontal and vertical text output is provided.

Operation

The first task is to determine the appropriate scale for the plot. The maximum and minimum X and Y values of all the data to be plotted establish approximate extrema for both axes. The linscale function then adjusts these to provide the appropriate values for a "nice" plot with the specified number of divisions on each axis. The data are scaled to the 640 by 480 screen coordinates for plotting. The algorithm was adapted from C. R. Lewart, Comm. ACM, Algorithm 463, 1972. It is thus not necessary to specify upper and lower limits as input, although that could be done if the additional control is desired.

The PostScript header is written to the file. This includes the macros cntrj and rtj which are used for center and right justification of text strings. initgraph initializes the graphics and then checks to see if a VGA monitor is available.

The function changetextstyle uses the graphics library function settextstyle to set the printing direction and character size. The font LITT.CHR is used for screen display. An error message is issued if it and EGAVGA.BGI are not available in the current directory. They could be linked in the .EXE file for permanent applications. The PostScript output uses the printer-resident Helvetica font.

Text output is defined by outtxt with arguments to set the starting coordinates and horizontal and vertical justification. Since outtxt is called from linaxis as well as main, I use the global variable DIRECTION, which is set by changetextstyle, to control printing direction.

The function outlin draws a line between two pairs of X,Y coordinates. The line is drawn on the screen by the graphics library function line. The appropriate commands are also written to the PostScript file if it is defined.

The function box uses outlin to draw a box with the coordinates of the upper left and lower right corners indicated by the parameters.

The task of drawing and labeling the axes is handled by the function linaxis. The function formx is used to format the numeric labels. Called with kon=0 it prints the numbers to a string in G format, checks to see whether E or F format is appropriate, and determines the required precision. Called with kon=1 it returns a string formatted with the specified precision and type (E or F). For the Y axis the maximum width of the numeric labels is used to set the global variable YAXOFF which determines the placement of the Y axis text label.

Table 1 shows the arguments for SPLOT.

For curve i of the nplots curves, the first npnts_pnts[i] points are plotted with symbols only. The remaining points are plotted with connecting lines but no symbols. The number of either symbols or connecting lines, but not both, may be 0.

The function symbol draws any of four predefined symbols. If there are more than four curves, the sequence of symbols is repeated.

The message box is drawn by the function msgbox. For the screen output we delete the material behind the box with the graphics library function fillpoly, draw the enclosing box, and output the strings with outtxt. For the PostScript output we define the macro pstrz. It is first used to get the maximum string length and the vertical space required. It is used again for writing the strings after deleting the background and drawing the enclosing box.

Files

The files for HP LaserJet output are screen images in binary .PCL format for printing at 150 dots per inch resolution. This gives plots about 4 by 3.25 inches which is (barely) acceptable for routine use. They are printed using the DOS copy command, as in:

copy spl0t1.hp prn /b
They must be copied as binary to assure getting all the file printed.

The PostScript files are defined in full-page size in landscape mode, suitable for reports. The resolution is determined by the printer used.

The plot shown in Figure 1 is one of three generated by the sample main program. The original PostScript file was for full-size output in landscape mode. The scaling command ".4 .4 scale" was added at the beginning of the file to size it for use here.

Examples

The SPLOT function can be compiled with Borland's Turbo C++ or Borland C++ using the small, compact, or large model. The sample program was compiled in the small model. I have included a test using the coreleft function to determine whether enough core is available for the chosen model. In addition the macro CORE can be set to 1 for conditional compilation of statements to display the core available after graphics initialization. None of the functions has large space requirements for automatic variables.

In the sample main program I have chosen the (perhaps unorthodox) method of using automatic variables to allocate space for the plot data. The arrays

char    msgspace[5] [81];
double  xpltspace [5] [300];
double    ypltspace[5] [300];
allocate room for five strings in the message box and for five curves with 300 total points each. The statements msg[i]=msgspace[i], etc. assign space to the appropriate pointers.

For the first plot we open both HP LaserJet and PostScript output files. The HP file must be opened as binary. The PostScript file is opened as text. In text mode the newline gives a carriage return followed by a line feed. Some PostScript printers may not like that. If you open the file as binary you get only a newline, consistent with UNIX usage. This will work with all PostScript printers, but some MS-DOS editors won't handle those files. In MS-DOS 5 edit accepts files without carriage returns, but saves them with carriage returns. The epsilon editor accepts files with or without carriage returns and permits saving them without returns by means of the set-line-translate command.

For the first demonstration plot (Figure 1) we simply use a for loop to create a circle and an ellipse defined by 201 points each. Setting numpoints=0 and totpoints=201 for both curves we get connected lines only. The appropriate strings for the title and the X and Y axis labels are inserted using strcpy. Defining nmsg[0]=0 indicates that there will be no message box.

For the second plot (Figure 2) we open a PostScript file but assign NULL to the LaserJet file pointer, indicating that it will not be used. We use for loops to define two parabolas. The first has 101 points equally spaced between X=-5 and X=+5. The second has 17 points between X=-4 and X=+4, followed by an additional 137 points in the same region. For the first curve we set numpoints=0 and totpoints=101 to provide connected lines only. For the second we set numpoints=17 and totpoints=154 to get both symbols and connected lines. In this case the symbols will be on the lines, but they would not be if the two sets of points were for different functions. If we set totpoints[1]=17 we would get symbols only for the second curve.

The third plot (Figure 3) illustrates the available symbols and the way the code handles large numbers. We define five lines with symbols. In addition to setting the title and X and Y axis labels, we copy two strings to the message box pointers msg[0] and msg[1]. We set nmsg[0]=2, indicating that two strings are included, and nmsg[1]=370 and nmsg[2]=130 to determine the location of the message box in screen coordinates.

Listing 1: SAMPPLOT.C

Listing 2: SPLOT.C