1 // Tony Richardson
2 //
3 // This program is intended to be used as a template for creating simple
4 // two-dimensional plotting programs which use the PLplot plotting
5 // library.  The program was written with an emphasis on trying to clearly
6 // illustrate how to use the PLplot library functions.
7 //
8 // This program reads data for M lines with N points each from an input
9 // data file and plots them on the same graph using different symbols.  It
10 // draws axes with labels and places a title at the top of the figure.  A
11 // legend is drawn to the right of the figure.  The input data file must
12 // have the following format:
13 //
14 //    M        N
15 //    x[1]     y[1][1]     y[1][2]     .     .     .     y[1][M]
16 //    x[2]     y[2][1]     y[2][2]     .     .     .     y[2][M]
17 //    x[3]     y[3][1]     y[3][2]     .     .     .     y[3][M]
18 //     .          .           .        .     .     .        .
19 //     .          .           .        .     .     .        .
20 //     .          .           .        .     .     .        .
21 //    x[N]     y[N][1]     y[N][2]     .     .     .     y[N][M]
22 //
23 // (The first line contains the integer values M and N.  The succeeding
24 // N lines contain the x-coordinate and the corresponding y-coordinates
25 // of each of the M lines.)
26 //
27 
28 #include "plcdemos.h"
29 
30 static int
31 error( char *str );
32 
33 //
34 // You can select a different set of symbols to use when plotting the
35 // lines by changing the value of OFFSET.
36 //
37 
38 #define OFFSET    2
39 
40 int
main(int argc,char * argv[])41 main( int argc, char *argv[] )
42 {
43 // ==============  Begin variable definition section. =============
44 
45 //
46 // i, j, and k are counting variables used in loops and such. M is the
47 // number of lines to be plotted and N is the number of sample points
48 // for each line.
49 //
50 
51     int i, j, k, M, N, leglen;
52 
53 //
54 // x is a pointer to an array containing the N x-coordinate values.  y
55 // points to an array of M pointers each of which points to an array
56 // containing the N y-coordinate values for that line.
57 //
58 
59     PLFLT *x, **y;
60 
61 // Define storage for the min and max values of the data.
62 
63     PLFLT xmin, xmax, ymin, ymax, xdiff, ydiff;
64 
65 // Define storage for the filename and define the input file pointer.
66 
67     char filename[80], string[80], tmpstr[80];
68     FILE *datafile;
69 
70 // Here are the character strings that appear in the plot legend.
71 
72     static char *legend[] =
73     {
74         "Aardvarks",
75         "Gnus",
76         "Llamas",
77         NULL
78     };                          // Make sure last element is NULL
79 
80 // ==============  Read in data from input file. =============
81 
82 // Parse and process command line arguments
83 
84     (void) plparseopts( &argc, argv, PL_PARSE_FULL );
85 
86 // First prompt the user for the input data file name
87 
88     printf( "Enter input data file name. " );
89     scanf( "%s", filename );
90 
91 // and open the file.
92 
93     datafile = fopen( filename, "r" );
94     if ( datafile == NULL )     // error opening input file
95         error( "Error opening input file." );
96 
97 // Read in values of M and N
98 
99     k = fscanf( datafile, "%d %d", &M, &N );
100     if ( k != 2 )               // something's wrong
101         error( "Error while reading data file." );
102 
103 // Allocate memory for all the arrays.
104 
105     x = (PLFLT *) malloc( N * sizeof ( PLFLT ) );
106     if ( x == NULL )
107         error( "Out of memory!" );
108     y = (PLFLT **) malloc( M * sizeof ( PLFLT * ) );
109     if ( y == NULL )
110         error( "Out of memory!" );
111     for ( i = 0; i < M; i++ )
112     {
113         y[i] = (PLFLT *) malloc( N * sizeof ( PLFLT ) );
114         if ( y[i] == NULL )
115             error( "Out of memory!" );
116     }
117 
118 // Now read in all the data.
119 
120     for ( i = 0; i < N; i++ )     // N points
121     {
122         k = fscanf( datafile, "%f", &x[i] );
123         if ( k != 1 )
124             error( "Error while reading data file." );
125         for ( j = 0; j < M; j++ )         // M lines
126         {
127             k = fscanf( datafile, "%f", &y[j][i] );
128             if ( k != 1 )
129                 error( "Error while reading data file." );
130         }
131     }
132 
133 // ==============  Graph the data. =============
134 
135 // Set graph to portrait orientation. (Default is landscape.)
136 // (Portrait is usually desired for inclusion in TeX documents.)
137 
138     plsori( 1 );
139 
140 // Initialize plplot
141 
142     plinit();
143 
144 //
145 // We must call pladv() to advance to the first (and only) subpage.
146 // You might want to use plenv() instead of the pladv(), plvpor(),
147 // plwind() sequence.
148 //
149 
150     pladv( 0 );
151 
152 //
153 // Set up the viewport.  This is the window into which the data is
154 // plotted.  The size of the window can be set with a call to
155 // plvpor(), which sets the size in terms of normalized subpage
156 // coordinates.  I want to plot the lines on the upper half of the
157 // page and I want to leave room to the right of the figure for
158 // labelling the lines. We must also leave room for the title and
159 // labels with plvpor().  Normally a call to plvsta() can be used
160 // instead.
161 //
162 
163     plvpor( 0.15, 0.70, 0.5, 0.9 );
164 
165 //
166 // We now need to define the size of the window in user coordinates.
167 // To do this, we first need to determine the range of the data
168 // values.
169 //
170 
171     xmin = xmax = x[0];
172     ymin = ymax = y[0][0];
173     for ( i = 0; i < N; i++ )
174     {
175         if ( x[i] < xmin )
176             xmin = x[i];
177         if ( x[i] > xmax )
178             xmax = x[i];
179         for ( j = 0; j < M; j++ )
180         {
181             if ( y[j][i] < ymin )
182                 ymin = y[j][i];
183             if ( y[j][i] > ymax )
184                 ymax = y[j][i];
185         }
186     }
187 
188 //
189 // Now set the size of the window. Leave a small border around the
190 // data.
191 //
192 
193     xdiff = ( xmax - xmin ) / 20.;
194     ydiff = ( ymax - ymin ) / 20.;
195     plwind( xmin - xdiff, xmax + xdiff, ymin - ydiff, ymax + ydiff );
196 
197 //
198 // Call plbox() to draw the axes (see the PLPLOT manual for
199 // information about the option strings.)
200 //
201 
202     plbox( "bcnst", 0.0, 0, "bcnstv", 0.0, 0 );
203 
204 //
205 // Label the axes and title the graph.  The string "#gm" plots the
206 // Greek letter mu, all the Greek letters are available, see the
207 // PLplot manual.
208 //
209 
210     pllab( "Time (weeks)", "Height (#gmparsecs)", "Specimen Growth Rate" );
211 
212 //
213 // Plot the data.  plpoin() draws a symbol at each point.  plline()
214 // connects all the points.
215 //
216 
217     for ( i = 0; i < M; i++ )
218     {
219         plpoin( N, x, y[i], i + OFFSET );
220         plline( N, x, y[i] );
221     }
222 
223 //
224 // Draw legend to the right of the chart.  Things get a little messy
225 // here.  You may want to remove this section if you don't want a
226 // legend drawn.  First find length of longest string.
227 //
228 
229     leglen = 0;
230     for ( i = 0; i < M; i++ )
231     {
232         if ( legend[i] == NULL )
233             break;
234         j = strlen( legend[i] );
235         if ( j > leglen )
236             leglen = j;
237     }
238 
239 //
240 // Now build the string.  The string consists of an element from the
241 // legend string array, padded with spaces, followed by one of the
242 // symbols used in plpoin above.
243 //
244 
245     for ( i = 0; i < M; i++ )
246     {
247         if ( legend[i] == NULL )
248             break;
249         strcpy( string, legend[i] );
250         j = strlen( string );
251         if ( j < leglen )         // pad string with spaces
252         {
253             for ( k = j; k < leglen; k++ )
254                 string[k] = ' ';
255             string[k] = '\0';
256         }
257 
258         // pad an extra space
259 
260         strcat( string, " " );
261         j = strlen( string );
262 
263         // insert the ASCII value of the symbol plotted with plpoin()
264 
265         string[j]     = i + OFFSET;
266         string[j + 1] = '\0';
267 
268         // plot the string
269 
270         plmtex( "rv", 1., 1. - (double) ( i + 1 ) / ( M + 1 ), 0., string );
271     }
272 
273 //  Tell plplot we are done with this page.
274 
275     pladv( 0 );                   // advance page
276 
277 // Don't forget to call plend() to finish off!
278 
279     plend();
280     exit( 0 );
281 }
282 
283 static int
error(char * str)284 error( char *str )
285 {
286     fprintf( stderr, "%s\n", str );
287     exit( 1 );
288 }
289