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