source: trunk/src/Utils/pgplot_related.c @ 221

Last change on this file since 221 was 221, checked in by Matthew Whiting, 17 years ago

More documentation being added to source code, with a new file (src/Utils/Hanning.cc) added as well.

File size: 10.8 KB
Line 
1#include <stdio.h>
2#include <stdlib.h>
3#include <cpgplot.h>
4#include <math.h>
5#include <string.h>
6#include <ctype.h>
7
8#define WDGPIX 100  /* used by cpgwedglog
9                       --> number of increments in the wedge. */
10
11//
12// This file contains the following programs, all in C code:
13//
14//  int cpgtest() --> a front-end to cpgqinf, to test whether a pgplot
15//                    device is currently open.
16//  int cpgIsPS() --> a front-end to cpgqinf, to test whether a postscript
17//                    device is currently open.
18//  void cpgwedglog(const char* side, float disp, float width,
19//                  float fg, float bg, const char *label)
20//                --> a C-code version of pgwedg, plotting the wedge
21//                    scale in logarithmic units.
22//  void cpgcumul(int npts, float *data, float datamin, float datamax,
23//                       int pgflag)
24//                --> a new pgplot routine that draws a cumulative
25//                    distribution. Uses _swap and _sort.
26//  void cpghistlog(npts, data, datamin, datamax, nbin, pgflag)
27//                --> as for cpghist, with the y-axis on a logarithmic scale.
28//
29//
30
31
32/********************************************************************/
33/*   CPGTEST
34/********************************************************************/
35
36int cpgtest()
37{
38  /**
39   *     A front-end to cpgqinf, to test whether a pgplot device is
40   *     currently open. Returns 1 if there is, else 0.
41   */
42  char answer[10];                 /* The PGQINF return string */
43  int answer_len = sizeof(answer); /* allocated size of answer[] */
44  cpgqinf("STATE", answer, &answer_len);
45  return strcmp(answer, "OPEN") == 0;
46}
47
48/********************************************************************/
49/*   CPGTYPE
50/********************************************************************/
51
52int cpgIsPS()
53{
54  /**
55   *     A front-end to cpgqinf, that tests whether the device is using a
56   *     postscript (by which we mean "hardcopy") device
57   */
58  char answer[50];
59  int answer_len = sizeof(answer);
60  cpgqinf("TYPE", answer, &answer_len);
61  return ((answer[answer_len-2]=='P')&&((answer[answer_len-1]=='S')));
62}
63
64/********************************************************************/
65/*   CPGWEDGLOG
66/********************************************************************/
67
68void cpgwedglog(const char* side, float disp, float width, float fg, float bg,
69                const char *label)
70{
71  /**
72   *     A C-code version of PGWEDG that writes the scale of the wedge in
73   *      logarithmic coordinates. All parameters are exactly as for cpgwedg.
74   */
75 
76  float wxa,wxb,wya,wyb, xa,xb,ya,yb; /* Temporary window coord storage.*/
77  float vxa,vxb,vya,vyb;              /* Viewport coords of wedge. */
78  float oldch, newch;                 /* Original and annotation character
79                                         heights. */
80  float ndcsiz;                       /* Size of unit character height
81                                         (NDC units). */
82  int horiz;                          /* Logical: True (=1) if wedge plotted
83                                         horizontally. */
84  int image;                          /* Logical: Use PGIMAG (T=1) or
85                                         PGGRAY (F=0). */
86
87  int nside,i;                        /* nside = symbolic version of side. */
88  const int bot=1,top=2,lft=3,rgt=4;
89  float wedwid, wdginc, vwidth, vdisp, xch, ych, labwid, fg1, bg1;
90  float txtfrc=0.6;                   /* Set the fraction of WIDTH used
91                                             for anotation. */
92  float txtsep=2.2;                   /* Char separation between numbers
93                                             and LABEL. */
94  float wdgarr[WDGPIX];               /* Array to draw wedge in. */
95  float tr[6] = {0.0,1.0,0.0,0.0,0.0,1.0};
96
97/*   if(pgnoto("pgwedg")) return; */
98
99  /* Get a numeric version of SIDE. */
100  if(tolower(side[0])=='b'){
101    nside = bot;
102    horiz = 1;
103  }
104  else if(tolower(side[0]=='t')){
105    nside = top;
106    horiz = 1;
107  }
108  else if(tolower(side[0]=='l')){
109    nside = lft;
110    horiz = 0;
111  }
112  else if(tolower(side[0]=='r')){
113    nside = rgt;
114    horiz = 0;
115  }
116  /*   else gwarn("Invalid \"SIDE\" argument in PGWEDG.");  */
117  else fprintf(stdout,"%PGPLOT, Invalid \"SIDE\" argument in CPGWEDGLOG.");
118
119  /* Determine which routine to use. */
120  if(strlen(side)<2) image = 0;
121  else if(tolower(side[1])=='i') image = 1;
122  else if(tolower(side[1])=='g') image = 0;
123  else fprintf(stdout,"%PGPLOT, Invalid \"SIDE\" argument in CPGWEDGLOG.");
124
125  cpgbbuf();
126
127  /* Store the current world and viewport coords and the character height. */
128  cpgqwin(&wxa, &wxb, &wya, &wyb);
129  cpgqvp(0, &xa, &xb, &ya, &yb);
130  cpgqch(&oldch);
131
132  /* Determine the unit character height in NDC coords. */
133  cpgsch(1.0);
134  cpgqcs(0, &xch, &ych);
135  if(horiz == 1)  ndcsiz = ych;
136  else ndcsiz = xch;
137
138  /* Convert 'WIDTH' and 'DISP' into viewport units. */
139  vwidth = width * ndcsiz * oldch;
140  vdisp  = disp * ndcsiz * oldch;
141
142  /* Determine the number of character heights required under the wedge. */
143  labwid = txtsep;
144  if(strcmp(label," ")!=0) labwid = labwid + 1.0;
145 
146  /* Determine and set the character height required to fit the wedge
147     anotation text within the area allowed for it. */
148  newch = txtfrc*vwidth / (labwid*ndcsiz);
149  cpgsch(newch);
150
151  /* Determine the width of the wedge part of the plot minus the anotation.
152     (NDC units). */
153  wedwid = vwidth * (1.0-txtfrc);
154
155  /* Use these to determine viewport coordinates for the wedge + annotation.*/
156  vxa = xa;
157  vxb = xb;
158  vya = ya;
159  vyb = yb;
160  if(nside==bot){
161    vyb = ya - vdisp;
162    vya = vyb - wedwid;
163  }
164  else if(nside==top) {
165    vya = yb + vdisp;
166    vyb = vya + wedwid;
167  }
168  else if(nside==lft) {
169    vxb = xa - vdisp;
170    vxa = vxb - wedwid;
171  }
172  else if(nside==rgt) {
173    vxa = xb + vdisp;
174    vxb = vxa + wedwid;
175  }
176
177  /* Set the viewport for the wedge. */
178  cpgsvp(vxa, vxb, vya, vyb);
179
180  /* Swap FG/BG if necessary to get axis direction right. */
181/*   fg1 = max(fg,bg); */
182/*   bg1 = min(fg,bg); */
183  if(fg>bg) {
184    fg1 = fg;
185    bg1 = bg;
186  }
187  else {
188    fg1 = bg;
189    bg1 = fg;
190  }
191
192
193  /* Create a dummy wedge array to be plotted. */
194  wdginc = (fg1-bg1)/(WDGPIX-1);
195  for(i=0;i<WDGPIX;i++)  wdgarr[i] = bg1 + (i-1) * wdginc;
196
197  /* Draw the wedge then change the world coordinates for labelling. */
198  if (horiz==1) {
199    cpgswin(1.0, (float)WDGPIX, 0.9, 1.1);
200    if (image==1) cpgimag(wdgarr, WDGPIX,1, 1,WDGPIX, 1,1, fg,bg, tr);
201    else          cpggray(wdgarr, WDGPIX,1, 1,WDGPIX, 1,1, fg,bg, tr);
202    cpgswin(bg1,fg1,0.0,1.0);
203  }
204  else{
205    cpgswin(0.9, 1.1, 1.0, (float)WDGPIX);
206    if (image==1) cpgimag(wdgarr, 1,WDGPIX, 1,1, 1,WDGPIX, fg,bg, tr);
207    else          cpggray(wdgarr, 1,WDGPIX, 1,1, 1,WDGPIX, fg,bg, tr);
208    cpgswin(0.0, 1.0, bg1, fg1);
209  }
210
211  /* Draw a labelled frame around the wedge -- using a logarithmic scale! */
212  if(nside==bot)  cpgbox("BCNSTL",0.0,0,"BC",0.0,0);
213  else if(nside==top) cpgbox("BCMSTL",0.0,0,"BC",0.0,0);
214  else if(nside==lft) cpgbox("BC",0.0,0,"BCNSTL",0.0,0);
215  else if(nside==rgt) cpgbox("BC",0.0,0,"BCMSTL",0.0,0);
216
217  /* Write the units label. */
218  if((strcmp(label," ")!=0)) cpgmtxt(side,txtsep,1.0,1.0,label);
219
220  /* Reset the original viewport and world coordinates. */
221  cpgsvp(xa,xb,ya,yb);
222  cpgswin(wxa,wxb,wya,wyb);
223  cpgsch(oldch);
224  cpgebuf();
225
226}
227
228
229/********************************************************************/
230/*   CPGCUMUL
231/********************************************************************/
232
233void _swap(float *a, float *b)
234{
235  float t;
236  t=*a; *a=*b; *b=t;
237}
238
239void _sort(float *array, int begin, int end)
240{
241  float pivot = array[begin];
242  int i = begin + 1, j = end, k = end;
243  float t;
244
245  while (i < j) {
246    if (array[i] < pivot) i++;
247    else if (array[i] > pivot) {
248      j--; k--;
249      t = array[i];
250      array[i] = array[j];
251      array[j] = array[k];
252      array[k] = t; }
253    else {
254      j--;
255      _swap(&array[i], &array[j]);
256    }  }
257  i--;
258  _swap(&array[begin], &array[i]);       
259  if (i - begin > 1)
260    _sort(array, begin, i);
261  if (end - k   > 1)
262    _sort(array, k, end);                     
263}
264
265
266void cpgcumul(int npts, float *data, float datamin, float datamax, int pgflag)
267{
268  /**
269   *  A new pgplot routine that draws a cumulative distribution.
270   *   The use of pgflag is similar to cpghist & cpghist_log:
271   *   <ul><li> 0 --> draw a new graph using cpgenv, going from 0 to 1 on the y-axis.
272   *       <li> 2 --> draw the plot on the current graph, without re-drawing any axes.
273   *   </ul>
274   */
275
276  int i;
277  float *sorted;
278  float MINCOUNT=0.;
279
280  sorted = (float *)calloc(npts,sizeof(float));
281  for(i=0;i<npts;i++) sorted[i] = data[i];
282  _sort(sorted,0,npts);
283
284  cpgbbuf();
285
286  /* DEFINE ENVIRONMENT IF NECESSARY */
287  if(pgflag == 0) cpgenv(datamin,datamax,MINCOUNT,1.0001,0,0);
288  if(pgflag == 2) cpgswin(datamin,datamax,MINCOUNT,1.);
289
290  /* DRAW LINE */
291  cpgmove(datamin,MINCOUNT);
292  for(i=0;i<npts;i++) cpgdraw(sorted[i],(float)(i+1)/(float)(npts));
293  cpgdraw(datamax,1.);
294
295  cpgebuf();
296 
297  free(sorted);
298
299}
300
301/********************************************************************/
302/*   CPGHISTLOG
303/********************************************************************/
304
305void cpghistlog(int npts, float *data, float datamin, float datamax, int nbin,
306                int pgflag)
307{
308  /**
309   *  Works exactly as for cpghist, except the y-axis is a logarithmic scale.
310   *
311   */
312
313
314  int i,bin;
315  float *num;
316  float maxNum,binSize,x1,x2,y1,y2,older,newer,fraction;
317  float MINCOUNT=-0.2;
318
319  num = (float *)calloc(nbin,sizeof(float));
320
321  cpgbbuf();
322
323  /* HOW MANY VALUES IN EACH BIN? */
324  for(i=0; i<npts; i++){
325    fraction = (data[i] - datamin) / (datamax - datamin);
326    bin = (int)( floor(fraction*nbin) );
327    if((bin>=0)&&(bin<nbin)) num[bin]+=1.;
328  }
329  for(i=0; i<nbin;i++){
330    if(num[i]>0) num[i] = log10(num[i]);
331    else num[i] = MINCOUNT;
332  }
333  maxNum = num[0];
334  for(i=1; i<nbin; i++) if(num[i]>maxNum) maxNum = num[i];
335  binSize = (datamax - datamin) / (float)nbin;
336
337  /* BOUNDARIES OF PLOT */
338  x1 = datamin;
339  x2 = datamax;
340  y1 = MINCOUNT;
341  y2 = ceil(maxNum);
342
343  /* DEFINE ENVIRONMENT IF NECESSARY */
344  if(pgflag%2 == 0) cpgenv(x1,x2,y1,y2,0,20);
345
346  /* DRAW HISTOGRAM */
347  if(pgflag/2 == 0){
348    older = 0.;
349    x2 = datamin;
350    cpgmove(datamin,MINCOUNT);
351    for(i=0;i<nbin;i++){
352      newer = num[i];
353      x1 = x2;
354      x2 = datamin + i*binSize;
355      if(newer!=MINCOUNT){
356        if(newer<=older){
357          cpgmove(x1,newer);
358          cpgdraw(x2,newer);
359        }
360        else{
361          cpgmove(x1,older);
362          cpgdraw(x1,newer);
363          cpgdraw(x2,newer);
364        }
365      }
366      cpgdraw(x2,MINCOUNT);
367      older=newer;
368    }
369  }
370  else if(pgflag/2 == 1){
371    older = MINCOUNT;
372    x2 = datamin;
373    for(i=0;i<nbin;i++){
374      newer = num[i];
375      x1 = x2;
376      x2 = datamin + i*binSize;
377      if(newer!=MINCOUNT) cpgrect(x1,x2,0.,newer);     
378    }
379  }
380  else if(pgflag/2 == 2){
381    older = 0.;
382    cpgmove(datamin,MINCOUNT);
383    x2 = datamin;
384    for(i=0;i<nbin;i++){
385      newer = num[i];
386      x1 = x2;
387      x2 = datamin + i*binSize;
388      if((newer==MINCOUNT)&&(older==MINCOUNT)) cpgmove(x2,MINCOUNT);
389      else {
390        cpgdraw(x1,newer);
391        if(newer==MINCOUNT) cpgmove(x2,newer);
392        else cpgdraw(x2,newer);
393      }
394      older = newer;
395    }
396  }
397
398  cpgebuf();
399   
400}
401
Note: See TracBrowser for help on using the repository browser.