source: tags/release-1.2.2/src/Utils/pgplot_related.c

Last change on this file was 634, checked in by MatthewWhiting, 15 years ago

Initialising some variables so that they don't get used uninitialised (not that they would, but it avoids pedantic compilation warnings!).

File size: 14.7 KB
Line 
1/*
2// -----------------------------------------------------------------------
3// pgplot_related.c: New functions for use with PGPLOT.
4// -----------------------------------------------------------------------
5// Copyright (C) 2006, Matthew Whiting, ATNF
6//
7// This program is free software; you can redistribute it and/or modify it
8// under the terms of the GNU General Public License as published by the
9// Free Software Foundation; either version 2 of the License, or (at your
10// option) any later version.
11//
12// Duchamp is distributed in the hope that it will be useful, but WITHOUT
13// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15// for more details.
16//
17// You should have received a copy of the GNU General Public License
18// along with Duchamp; if not, write to the Free Software Foundation,
19// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
20//
21// Correspondence concerning Duchamp may be directed to:
22//    Internet email: Matthew.Whiting [at] atnf.csiro.au
23//    Postal address: Dr. Matthew Whiting
24//                    Australia Telescope National Facility, CSIRO
25//                    PO Box 76
26//                    Epping NSW 1710
27//                    AUSTRALIA
28// -----------------------------------------------------------------------
29*/
30#include <stdio.h>
31#include <stdlib.h>
32#include <cpgplot.h>
33#include <math.h>
34#include <string.h>
35#include <ctype.h>
36
37#define WDGPIX 100  /* used by cpgwedglog
38                       --> number of increments in the wedge. */
39
40/*
41 This file contains the following programs, all in C code:
42
43  int cpgtest() --> a front-end to cpgqinf, to test whether a pgplot
44                    device is currently open.
45  void cpgwedglog(const char* side, float disp, float width,
46                  float fg, float bg, const char *label)
47                --> a C-code version of pgwedg, plotting the wedge
48                    scale in logarithmic units.
49  void cpgcumul(int npts, float *data, float datamin, float datamax,
50                       int pgflag)
51                --> a new pgplot routine that draws a cumulative
52                    distribution. Uses _swap and _sort.
53  void cpghistlog(npts, data, datamin, datamax, nbin, pgflag)
54                --> as for cpghist, with the y-axis on a logarithmic scale.
55
56*/
57
58
59/********************************************************************/
60/*   CPGTEST                                                        */
61/********************************************************************/
62
63int cpgtest()
64{
65  /**
66   *     A front-end to cpgqinf, to test whether a pgplot device is
67   *     currently open. Returns 1 if there is, else 0.
68   */
69  char answer[10];                 /* The PGQINF return string */
70  int answer_len = sizeof(answer); /* allocated size of answer[] */
71  cpgqinf("STATE", answer, &answer_len);
72  return strcmp(answer, "OPEN") == 0;
73}
74
75/********************************************************************/
76/*   CPGWEDGLOG                                                     */
77/********************************************************************/
78
79void cpgwedglog(const char* side, float disp, float width, float fg, float bg,
80                const char *label)
81{
82  /**
83   *     A C-code version of PGWEDG that writes the scale of the wedge in
84   *      logarithmic coordinates. All parameters are exactly as for cpgwedg.
85   */
86 
87  float wxa,wxb,wya,wyb, xa,xb,ya,yb; /* Temporary window coord storage.*/
88  float vxa,vxb,vya,vyb;              /* Viewport coords of wedge. */
89  float oldch, newch;                 /* Original and annotation character
90                                         heights. */
91  float ndcsiz;                       /* Size of unit character height
92                                         (NDC units). */
93  int horiz;                          /* Logical: True (=1) if wedge plotted
94                                         horizontally. */
95  int image;                          /* Logical: Use PGIMAG (T=1) or
96                                         PGGRAY (F=0). */
97
98  int nside,i;                        /* nside = symbolic version of side. */
99  const int bot=1,top=2,lft=3,rgt=4;
100  float wedwid, wdginc, vwidth, vdisp, xch, ych, labwid, fg1, bg1;
101  float txtfrc=0.6;                   /* Set the fraction of WIDTH used
102                                             for anotation. */
103  float txtsep=2.2;                   /* Char separation between numbers
104                                             and LABEL. */
105  float wdgarr[WDGPIX];               /* Array to draw wedge in. */
106  float tr[6] = {0.0,1.0,0.0,0.0,0.0,1.0};
107
108/*   if(pgnoto("pgwedg")) return; */
109
110  /* Get a numeric version of SIDE. */
111  nside=bot; /* initialise */
112  horiz=1;   /* initialise */
113  if(tolower(side[0])=='b'){
114    nside = bot;
115    horiz = 1;
116  }
117  else if(tolower(side[0]=='t')){
118    nside = top;
119    horiz = 1;
120  }
121  else if(tolower(side[0]=='l')){
122    nside = lft;
123    horiz = 0;
124  }
125  else if(tolower(side[0]=='r')){
126    nside = rgt;
127    horiz = 0;
128  }
129  /*   else gwarn("Invalid \"SIDE\" argument in PGWEDG.");  */
130  else fprintf(stdout,"%%PGPLOT, Invalid \"SIDE\" argument in CPGWEDGLOG.");
131
132  /* Determine which routine to use. */
133  image=0; /* initialise */
134  if(strlen(side)<2) image = 0;
135  else if(tolower(side[1])=='i') image = 1;
136  else if(tolower(side[1])=='g') image = 0;
137  else fprintf(stdout,"%%PGPLOT, Invalid \"SIDE\" argument in CPGWEDGLOG.");
138
139  cpgbbuf();
140
141  /* Store the current world and viewport coords and the character height. */
142  cpgqwin(&wxa, &wxb, &wya, &wyb);
143  cpgqvp(0, &xa, &xb, &ya, &yb);
144  cpgqch(&oldch);
145
146  /* Determine the unit character height in NDC coords. */
147  cpgsch(1.0);
148  cpgqcs(0, &xch, &ych);
149  if(horiz == 1)  ndcsiz = ych;
150  else ndcsiz = xch;
151
152  /* Convert 'WIDTH' and 'DISP' into viewport units. */
153  vwidth = width * ndcsiz * oldch;
154  vdisp  = disp * ndcsiz * oldch;
155
156  /* Determine the number of character heights required under the wedge. */
157  labwid = txtsep;
158  if(strcmp(label," ")!=0) labwid = labwid + 1.0;
159 
160  /* Determine and set the character height required to fit the wedge
161     anotation text within the area allowed for it. */
162  newch = txtfrc*vwidth / (labwid*ndcsiz);
163  cpgsch(newch);
164
165  /* Determine the width of the wedge part of the plot minus the anotation.
166     (NDC units). */
167  wedwid = vwidth * (1.0-txtfrc);
168
169  /* Use these to determine viewport coordinates for the wedge + annotation.*/
170  vxa = xa;
171  vxb = xb;
172  vya = ya;
173  vyb = yb;
174  if(nside==bot){
175    vyb = ya - vdisp;
176    vya = vyb - wedwid;
177  }
178  else if(nside==top) {
179    vya = yb + vdisp;
180    vyb = vya + wedwid;
181  }
182  else if(nside==lft) {
183    vxb = xa - vdisp;
184    vxa = vxb - wedwid;
185  }
186  else if(nside==rgt) {
187    vxa = xb + vdisp;
188    vxb = vxa + wedwid;
189  }
190
191  /* Set the viewport for the wedge. */
192  cpgsvp(vxa, vxb, vya, vyb);
193
194  /* Swap FG/BG if necessary to get axis direction right. */
195/*   fg1 = max(fg,bg); */
196/*   bg1 = min(fg,bg); */
197  if(fg>bg) {
198    fg1 = fg;
199    bg1 = bg;
200  }
201  else {
202    fg1 = bg;
203    bg1 = fg;
204  }
205
206
207  /* Create a dummy wedge array to be plotted. */
208  wdginc = (fg1-bg1)/(WDGPIX-1);
209  for(i=0;i<WDGPIX;i++)  wdgarr[i] = bg1 + (i-1) * wdginc;
210
211  /* Draw the wedge then change the world coordinates for labelling. */
212  if (horiz==1) {
213    cpgswin(1.0, (float)WDGPIX, 0.9, 1.1);
214    if (image==1) cpgimag(wdgarr, WDGPIX,1, 1,WDGPIX, 1,1, fg,bg, tr);
215    else          cpggray(wdgarr, WDGPIX,1, 1,WDGPIX, 1,1, fg,bg, tr);
216    cpgswin(bg1,fg1,0.0,1.0);
217  }
218  else{
219    cpgswin(0.9, 1.1, 1.0, (float)WDGPIX);
220    if (image==1) cpgimag(wdgarr, 1,WDGPIX, 1,1, 1,WDGPIX, fg,bg, tr);
221    else          cpggray(wdgarr, 1,WDGPIX, 1,1, 1,WDGPIX, fg,bg, tr);
222    cpgswin(0.0, 1.0, bg1, fg1);
223  }
224
225  /* Draw a labelled frame around the wedge -- using a logarithmic scale! */
226  if(nside==bot)  cpgbox("BCNSTL",0.0,0,"BC",0.0,0);
227  else if(nside==top) cpgbox("BCMSTL",0.0,0,"BC",0.0,0);
228  else if(nside==lft) cpgbox("BC",0.0,0,"BCNSTL",0.0,0);
229  else if(nside==rgt) cpgbox("BC",0.0,0,"BCMSTL",0.0,0);
230
231  /* Write the units label. */
232  if((strcmp(label," ")!=0)) cpgmtxt(side,txtsep,1.0,1.0,label);
233
234  /* Reset the original viewport and world coordinates. */
235  cpgsvp(xa,xb,ya,yb);
236  cpgswin(wxa,wxb,wya,wyb);
237  cpgsch(oldch);
238  cpgebuf();
239
240}
241
242
243/********************************************************************/
244/*   CPGCUMUL                                                       */
245/********************************************************************/
246
247void _swap(float *a, float *b)
248{
249  float t;
250  t=*a; *a=*b; *b=t;
251}
252
253void _sort(float *array, int begin, int end)
254{
255  float pivot = array[begin];
256  int i = begin + 1, j = end, k = end;
257  float t;
258
259  while (i < j) {
260    if (array[i] < pivot) i++;
261    else if (array[i] > pivot) {
262      j--; k--;
263      t = array[i];
264      array[i] = array[j];
265      array[j] = array[k];
266      array[k] = t; }
267    else {
268      j--;
269      _swap(&array[i], &array[j]);
270    }  }
271  i--;
272  _swap(&array[begin], &array[i]);       
273  if (i - begin > 1)
274    _sort(array, begin, i);
275  if (end - k   > 1)
276    _sort(array, k, end);                     
277}
278
279
280void cpgcumul(int npts, float *data, float datamin, float datamax, int pgflag)
281{
282  /**
283   *  A new pgplot routine that draws a cumulative distribution.
284   *   The use of pgflag is similar to cpghist & cpghist_log:
285
286   *   <ul><li> 0 --> draw a new graph using cpgenv, going from 0 to 1
287   *                  on the y-axis.
288   *       <li> 2 --> draw the plot on the current graph, without
289   *                  re-drawing any axes. 
290   *   </ul>
291   */
292
293  int i;
294  float *sorted;
295  float MINCOUNT=0.;
296
297  sorted = (float *)calloc(npts,sizeof(float));
298  for(i=0;i<npts;i++) sorted[i] = data[i];
299  _sort(sorted,0,npts);
300
301  cpgbbuf();
302
303  /* DEFINE ENVIRONMENT IF NECESSARY */
304  if(pgflag == 0) cpgenv(datamin,datamax,MINCOUNT,1.0001,0,0);
305  if(pgflag == 2) cpgswin(datamin,datamax,MINCOUNT,1.);
306
307  /* DRAW LINE */
308  cpgmove(datamin,MINCOUNT);
309  for(i=0;i<npts;i++) cpgdraw(sorted[i],(float)(i+1)/(float)(npts));
310  cpgdraw(datamax,1.);
311
312  cpgebuf();
313 
314  free(sorted);
315
316}
317
318/********************************************************************/
319/*   CPGHISTLOG                                                     */
320/********************************************************************/
321
322void cpghistlog(int npts, float *data, float datamin, float datamax, int nbin,
323                int pgflag)
324{
325  /**
326   *  Works exactly as for cpghist, except the y-axis is a logarithmic scale.
327   *
328   */
329
330
331  int i,bin;
332  float *num;
333  float maxNum,binSize,x1,x2,y1,y2,older,newer,fraction;
334  float MINCOUNT=-0.2;
335
336  num = (float *)calloc(nbin,sizeof(float));
337
338  cpgbbuf();
339
340  /* HOW MANY VALUES IN EACH BIN? */
341  for(i=0; i<npts; i++){
342    fraction = (data[i] - datamin) / (datamax - datamin);
343    bin = (int)( floor(fraction*nbin) );
344    if((bin>=0)&&(bin<nbin)) num[bin]+=1.;
345  }
346  for(i=0; i<nbin;i++){
347    if(num[i]>0) num[i] = log10(num[i]);
348    else num[i] = MINCOUNT;
349  }
350  maxNum = num[0];
351  for(i=1; i<nbin; i++) if(num[i]>maxNum) maxNum = num[i];
352  binSize = (datamax - datamin) / (float)nbin;
353
354  /* BOUNDARIES OF PLOT */
355  x1 = datamin;
356  x2 = datamax;
357  y1 = MINCOUNT;
358  y2 = ceil(maxNum);
359
360  /* DEFINE ENVIRONMENT IF NECESSARY */
361  if(pgflag%2 == 0) cpgenv(x1,x2,y1,y2,0,20);
362
363  /* DRAW HISTOGRAM */
364  if(pgflag/2 == 0){
365    older = 0.;
366    x2 = datamin;
367    cpgmove(datamin,MINCOUNT);
368    for(i=0;i<nbin;i++){
369      newer = num[i];
370      x1 = x2;
371      x2 = datamin + i*binSize;
372      if(newer!=MINCOUNT){
373        if(newer<=older){
374          cpgmove(x1,newer);
375          cpgdraw(x2,newer);
376        }
377        else{
378          cpgmove(x1,older);
379          cpgdraw(x1,newer);
380          cpgdraw(x2,newer);
381        }
382      }
383      cpgdraw(x2,MINCOUNT);
384      older=newer;
385    }
386  }
387  else if(pgflag/2 == 1){
388    older = MINCOUNT;
389    x2 = datamin;
390    for(i=0;i<nbin;i++){
391      newer = num[i];
392      x1 = x2;
393      x2 = datamin + i*binSize;
394      if(newer!=MINCOUNT) cpgrect(x1,x2,0.,newer);     
395    }
396  }
397  else if(pgflag/2 == 2){
398    older = 0.;
399    cpgmove(datamin,MINCOUNT);
400    x2 = datamin;
401    for(i=0;i<nbin;i++){
402      newer = num[i];
403      x1 = x2;
404      x2 = datamin + i*binSize;
405      if((newer==MINCOUNT)&&(older==MINCOUNT)) cpgmove(x2,MINCOUNT);
406      else {
407        cpgdraw(x1,newer);
408        if(newer==MINCOUNT) cpgmove(x2,newer);
409        else cpgdraw(x2,newer);
410      }
411      older = newer;
412    }
413  }
414
415  cpgebuf();
416   
417}
418
419/* /\********************************************************************\/ */
420/* /\*   CPGVERTHIST                                                    *\/ */
421/* /\********************************************************************\/ */
422
423/* void cpgverthist(int npts, float *data, float datamin, float datamax, int nbin,  */
424/*               int pgflag) */
425/* { */
426/*   /\** */
427/*    *  Works exactly as for cpghist, except the histogram is draw vertically. */
428/*    * */
429/*    *\/ */
430
431
432/*   int i,bin; */
433/*   float *num; */
434/*   float maxNum,binSize,x1,x2,y1,y2,older,newer,fraction; */
435/*   float MINCOUNT=-0.2; */
436
437/*   num = (float *)calloc(nbin,sizeof(float)); */
438
439/*   cpgbbuf(); */
440
441/*   /\* HOW MANY VALUES IN EACH BIN? *\/ */
442/*   for(i=0; i<npts; i++){ */
443/*     fraction = (data[i] - datamin) / (datamax - datamin); */
444/*     bin = (int)( floor(fraction*nbin) ); */
445/*     if((bin>=0)&&(bin<nbin)) num[bin]+=1.; */
446/*   } */
447/*   for(i=0; i<nbin;i++){ */
448/*     if(num[i]>0) num[i] = log10(num[i]); */
449/*     else num[i] = MINCOUNT; */
450/*   } */
451/*   maxNum = num[0]; */
452/*   for(i=1; i<nbin; i++) if(num[i]>maxNum) maxNum = num[i]; */
453/*   binSize = (datamax - datamin) / (float)nbin; */
454
455/*   /\* BOUNDARIES OF PLOT *\/ */
456/*   x1 = datamin; */
457/*   x2 = datamax; */
458/*   y1 = MINCOUNT; */
459/*   y2 = ceil(maxNum); */
460
461/*   /\* DEFINE ENVIRONMENT IF NECESSARY *\/ */
462/*   if(pgflag%2 == 0) cpgenv(x1,x2,y1,y2,0,20); */
463
464/*   /\* DRAW HISTOGRAM *\/ */
465/*   if(pgflag/2 == 0){ */
466/*     older = 0.; */
467/*     x2 = datamin; */
468/*     cpgmove(datamin,MINCOUNT); */
469/*     for(i=0;i<nbin;i++){ */
470/*       newer = num[i]; */
471/*       x1 = x2; */
472/*       x2 = datamin + i*binSize; */
473/*       if(newer!=MINCOUNT){ */
474/*      if(newer<=older){ */
475/*        cpgmove(x1,newer); */
476/*        cpgdraw(x2,newer); */
477/*      } */
478/*      else{ */
479/*        cpgmove(x1,older); */
480/*        cpgdraw(x1,newer); */
481/*        cpgdraw(x2,newer); */
482/*      } */
483/*       } */
484/*       cpgdraw(x2,MINCOUNT); */
485/*       older=newer; */
486/*     } */
487/*   } */
488/*   else if(pgflag/2 == 1){ */
489/*     older = MINCOUNT; */
490/*     x2 = datamin; */
491/*     for(i=0;i<nbin;i++){ */
492/*       newer = num[i]; */
493/*       x1 = x2; */
494/*       x2 = datamin + i*binSize; */
495/*       if(newer!=MINCOUNT) cpgrect(x1,x2,0.,newer);    */
496/*     } */
497/*   } */
498/*   else if(pgflag/2 == 2){ */
499/*     older = 0.; */
500/*     cpgmove(datamin,MINCOUNT); */
501/*     x2 = datamin; */
502/*     for(i=0;i<nbin;i++){ */
503/*       newer = num[i]; */
504/*       x1 = x2; */
505/*       x2 = datamin + i*binSize; */
506/*       if((newer==MINCOUNT)&&(older==MINCOUNT)) cpgmove(x2,MINCOUNT); */
507/*       else { */
508/*      cpgdraw(x1,newer); */
509/*      if(newer==MINCOUNT) cpgmove(x2,newer); */
510/*      else cpgdraw(x2,newer); */
511/*       } */
512/*       older = newer; */
513/*     } */
514/*   } */
515
516/*   cpgebuf(); */
517   
518/* } */
519
Note: See TracBrowser for help on using the repository browser.