source: tags/release-1.0.7/src/Cubes/plotting.cc

Last change on this file was 208, checked in by Matthew Whiting, 18 years ago
  • Enabled saving and reading in of a smoothed array, in manner directly analogous to that for the recon array.
    • New file : src/Cubes/readSmooth.cc
    • The other new functions go in existing files eg. saveImage.cc
    • Renamed some functions (like writeHeader...) to be more obvious what they do.
    • The reading in is taken care of by new function Cube::readSavedArrays() -- handles both smoothed and recon'd arrays.
    • Associated parameters in Param class
    • Clarified names of FITS header strings in duchamp.hh.
  • Updated the documentation to describe the ability to smooth a cube.
  • Added description of feedback mechanisms in the Install appendix.
  • Also, Hanning class improved to guard against memory leaks.


File size: 18.0 KB
Line 
1#include <iostream>
2#include <iomanip>
3#include <sstream>
4#include <math.h>
5#include <cpgplot.h>
6#include <cpgsbox.h>
7#include <pgwcsl.h>
8#include <wcs.h>
9#include <duchamp.hh>
10#include <param.hh>
11#include <Cubes/cubes.hh>
12#include <Cubes/plots.hh>
13#include <Utils/utils.hh>
14#include <Utils/mycpgplot.hh>
15
16using namespace mycpgplot;
17
18void Cube::plotDetectionMap(string pgDestination)
19{
20  /**
21   *  Cube::plotDetectionMap(string)
22   *    Creates a map of the spatial locations of the detections, which is
23   *     written to the PGPlot device given by pgDestination.
24   *    The map is done in greyscale, where the scale indicates the number of
25   *     velocity channels that each spatial pixel is detected in.
26   *    The boundaries of each detection are drawn, and each object is numbered
27   *     (to match the output list and spectra).
28   *    The primary grid scale is pixel coordinate, and if the WCS is valid,
29   *     the correct WCS gridlines are also drawn.
30   */
31
32  // These are the minimum values for the X and Y ranges of the box drawn by
33  //   pgplot (without the half-pixel difference).
34  // The -1 is necessary because the arrays we are dealing with start at 0
35  //  index, while the ranges given in the subsection start at 1...
36  float boxXmin = this->par.getXOffset() - 1;
37  float boxYmin = this->par.getYOffset() - 1;
38
39  long xdim=this->axisDim[0];
40  long ydim=this->axisDim[1];
41  Plot::ImagePlot newplot;
42  int flag = newplot.setUpPlot(pgDestination.c_str(),float(xdim),float(ydim));
43
44  if(flag<=0){
45    duchampError("plotDetectionMap",
46                 "Could not open PGPlot device " + pgDestination + ".\n");
47  }
48  else{
49
50    newplot.makeTitle(this->pars().getImageFile());
51
52    newplot.drawMapBox(boxXmin+0.5,boxXmin+xdim+0.5,
53                       boxYmin+0.5,boxYmin+ydim+0.5,
54                       "X pixel","Y pixel");
55
56    //     if(this->objectList.size()>0){
57    // if there are no detections, there will be nothing to plot here
58
59    float *detectMap = new float[xdim*ydim];
60    int maxNum = this->detectMap[0];
61    detectMap[0] = float(maxNum);
62    for(int pix=1;pix<xdim*ydim;pix++){
63      detectMap[pix] = float(this->detectMap[pix]); 
64      if(this->detectMap[pix] > maxNum)  maxNum = this->detectMap[pix];
65    }
66
67    if(maxNum>0){ // if there are no detections, it will be 0.
68
69      maxNum = 5 * ((maxNum-1)/5 + 1);  // move to next multiple of 5
70
71      float tr[6] = {boxXmin,1.,0.,boxYmin,0.,1.};
72      cpggray(detectMap,xdim,ydim,1,xdim,1,ydim,maxNum,0,tr); 
73       
74      //       delete [] detectMap;
75      cpgbox("bcnst",0.,0,"bcnst",0.,0);
76      cpgsch(1.5);
77      cpgwedg("rg",3.2,2,maxNum,0,"Number of detected channels");
78    }
79    delete [] detectMap;
80     
81    this->plotBlankEdges();
82     
83    if(this->head.isWCS()) this->plotWCSaxes();
84 
85    if(this->objectList.size()>0){
86      // now show and label each detection, drawing over the WCS lines.
87
88      cpgsch(1.0);
89      cpgslw(2);   
90      float xoff=0.;
91      float yoff=newplot.cmToCoord(0.5);
92      if(this->par.drawBorders()){
93        cpgsci(BLUE);
94        for(int i=0;i<this->objectList.size();i++)
95          this->objectList[i].drawBorders(0,0);
96      }
97      cpgsci(RED);
98      std::stringstream label;
99      cpgslw(1);
100      for(int i=0;i<this->objectList.size();i++){
101        cpgpt1(this->par.getXOffset()+this->objectList[i].getXcentre(),
102               this->par.getYOffset()+this->objectList[i].getYcentre(),
103               CROSS);
104        label.str("");
105        label << this->objectList[i].getID();
106        cpgptxt(this->par.getXOffset()+this->objectList[i].getXcentre()-xoff,
107                this->par.getYOffset()+this->objectList[i].getYcentre()-yoff,
108                0, 0.5, label.str().c_str());
109      }
110
111    }
112
113    cpgclos();
114  }
115}
116
117/*********************************************************/
118
119void Cube::plotMomentMap(string pgDestination)
120{
121  /**
122   *  Cube::plotMomentMap(string)
123   *    Creates a 0th moment map of the detections, which is written to the
124   *     PGPlot device given by pgDestination.
125   *    The map is done in greyscale, where the scale indicates the integrated
126   *     flux at each spatial pixel.
127   *    The boundaries of each detection are drawn, and each object is numbered
128   *     (to match the output list and spectra).
129   *    The primary grid scale is pixel coordinate, and if the WCS is valid,
130   *     the correct WCS gridlines are also drawn.
131   */
132
133  float boxXmin = this->par.getXOffset() - 1;
134  float boxYmin = this->par.getYOffset() - 1;
135
136  long xdim=this->axisDim[0];
137  long ydim=this->axisDim[1];
138  long zdim=this->axisDim[2];
139
140  Plot::ImagePlot newplot;
141
142  int flag = newplot.setUpPlot(pgDestination.c_str(),float(xdim),float(ydim));
143   
144  if(flag<=0){
145    duchampError("plotMomentMap",
146                 "Could not open PGPlot device " + pgDestination + ".\n");
147  }
148  else{
149
150    if(this->objectList.size()==0){
151      // if there are no detections, we plot an empty field.
152
153      newplot.makeTitle(this->pars().getImageFile());
154   
155      newplot.drawMapBox(boxXmin+0.5,boxXmin+xdim+0.5,
156                         boxYmin+0.5,boxYmin+ydim+0.5,
157                         "X pixel","Y pixel");
158
159      this->plotBlankEdges();
160
161      if(this->head.isWCS()) this->plotWCSaxes();
162
163    }
164    else { 
165      // if there are some detections, do the calculations first before
166      //  plotting anything.
167 
168      newplot.makeTitle(this->pars().getImageFile());
169   
170      newplot.drawMapBox(boxXmin+0.5,boxXmin+xdim+0.5,
171                         boxYmin+0.5,boxYmin+ydim+0.5,
172                         "X pixel","Y pixel");
173
174      if(pgDestination=="/xs")
175        cpgptxt(boxXmin+0.5+xdim/2., boxYmin+0.5+ydim/2., 0, 0.5,
176                "Calculating map...");
177
178      bool *isObj = new bool[xdim*ydim*zdim];
179      for(int i=0;i<xdim*ydim*zdim;i++) isObj[i] = false;
180      for(int i=0;i<this->objectList.size();i++){
181        for(int p=0;p<this->objectList[i].getSize();p++){
182          int pixelpos = this->objectList[i].getX(p) +
183            xdim*this->objectList[i].getY(p) +
184            xdim*ydim*this->objectList[i].getZ(p);
185          isObj[pixelpos] = true;
186        }
187      }
188
189      float *momentMap = new float[xdim*ydim];
190      // Initialise to zero
191      for(int i=0;i<xdim*ydim;i++) momentMap[i] = 0.;
192
193      // if we are looking for negative features, we need to invert the
194      //  detected pixels for the moment map
195      float sign = 1.;
196      if(this->pars().getFlagNegative()) sign = -1.;
197
198      float deltaVel;
199      double x,y;
200
201      double *zArray  = new double[zdim];
202      for(int z=0; z<zdim; z++) zArray[z] = double(z);
203   
204      double *world  = new double[zdim];
205
206      for(int pix=0; pix<xdim*ydim; pix++){
207
208        x = double(pix%xdim);
209        y = double(pix/xdim);
210
211        delete [] world;
212        world = this->head.pixToVel(x,y,zArray,zdim);
213     
214        for(int z=0; z<zdim; z++){     
215          int pos =  z*xdim*ydim + pix;  // the voxel in the cube
216          if(isObj[pos]){ // if it's an object pixel...
217            // delta-vel is half the distance between adjacent channels.
218            // if at end, then just use 0-1 or (zdim-1)-(zdim-2) distance
219            if(z==0){
220              if(zdim==1) deltaVel=1.; // pathological case -- if 2D image.
221              else deltaVel = world[z+1] - world[z];
222            }
223            else if(z==(zdim-1)) deltaVel = world[z-1] - world[z];
224            else deltaVel = (world[z+1] - world[z-1]) / 2.;
225
226            momentMap[pix] += sign * this->array[pos] * fabs(deltaVel);
227
228          }
229        }
230
231      }
232   
233      delete [] world;
234      delete [] zArray;
235
236      float *temp = new float[xdim*ydim];
237      int count=0;
238      for(int i=0;i<xdim*ydim;i++) {
239        if(momentMap[i]>0.){
240          bool addPixel = false;
241          for(int z=0;z<zdim;z++) addPixel = addPixel || isObj[z*xdim*ydim+i];
242          if(addPixel) temp[count++] = log10(momentMap[i]);
243        }
244      }
245      float z1,z2;
246      z1 = z2 = temp[0];
247      for(int i=1;i<count;i++){
248        if(temp[i]<z1) z1 = temp[i];
249        if(temp[i]>z2) z2 = temp[i];
250      }
251
252      for(int i=0;i<xdim*ydim;i++) {
253        bool addPixel = false;
254        for(int z=0;z<zdim;z++) addPixel = addPixel || isObj[z*xdim*ydim+i];
255        addPixel = addPixel && (momentMap[i]>0.);
256        if(!addPixel) momentMap[i] = z1-1.;
257        else momentMap[i] = log10(momentMap[i]);
258      }
259
260      // Have now done all necessary calculations for moment map.
261      // Now produce the plot
262
263      float tr[6] = {boxXmin,1.,0.,boxYmin,0.,1.};
264      cpggray(momentMap,xdim,ydim,1,xdim,1,ydim,z2,z1,tr);
265      cpgbox("bcnst",0.,0,"bcnst",0.,0);
266      cpgsch(1.5);
267      string wedgeLabel = "Integrated Flux ";
268      if(this->par.getFlagNegative())
269        wedgeLabel = "-1. " + times + " " + wedgeLabel;
270      if(this->head.isWCS())
271        wedgeLabel += "[" + this->head.getIntFluxUnits() + "]";
272      else wedgeLabel += "[" + this->head.getFluxUnits() + "]";
273      cpgwedglog("rg",3.2,2,z2,z1,wedgeLabel.c_str());
274
275      delete [] momentMap;
276      delete [] temp;
277      delete [] isObj;
278
279      this->plotBlankEdges();
280
281      if(this->head.isWCS()) this->plotWCSaxes();
282 
283      // now show and label each detection, drawing over the WCS lines.
284      cpgsch(1.0);
285      cpgslw(2);
286      float xoff=0.;
287      float yoff=newplot.cmToCoord(0.5);
288      if(this->par.drawBorders()){
289        cpgsci(BLUE);
290        for(int i=0;i<this->objectList.size();i++)
291          this->objectList[i].drawBorders(0,0);
292      }
293      cpgsci(RED);
294      std::stringstream label;
295      cpgslw(1);
296      for(int i=0;i<this->objectList.size();i++){
297        cpgpt1(this->par.getXOffset()+this->objectList[i].getXcentre(),
298               this->par.getYOffset()+this->objectList[i].getYcentre(),
299               CROSS);
300        label.str("");
301        label << this->objectList[i].getID();
302        cpgptxt(this->par.getXOffset()+this->objectList[i].getXcentre()-xoff,
303                this->par.getYOffset()+this->objectList[i].getYcentre()-yoff,
304                0, 0.5, label.str().c_str());
305      }
306
307    }
308
309 
310    cpgclos();
311  }
312 
313}
314
315/*********************************************************/
316
317void Cube::plotMomentMap(vector<string> pgDestination)
318{
319  /**
320   *  Cube::plotMomentMap(vector<string>)
321   *    Creates a 0th moment map of the detections, which is written to each
322   *     of the PGPlot devices mentioned in pgDestination.
323   *    The advantage of this function is that the map is only calculated once,
324   *     even if multiple maps are required.
325   *    The map is done in greyscale, where the scale indicates the integrated
326   *     flux at each spatial pixel.
327   *    The boundaries of each detection are drawn, and each object is numbered
328   *     (to match the output list and spectra).
329   *    The primary grid scale is pixel coordinate, and if the WCS is valid,
330   *     the correct WCS gridlines are also drawn.
331   */
332
333  float boxXmin = this->par.getXOffset() - 1;
334  float boxYmin = this->par.getYOffset() - 1;
335
336  long xdim=this->axisDim[0];
337  long ydim=this->axisDim[1];
338  long zdim=this->axisDim[2];
339
340  int numPlots = pgDestination.size();
341  vector<Plot::ImagePlot> plotList(numPlots);
342  vector<int> plotFlag(numPlots,0);
343  vector<bool> doPlot(numPlots,false);
344  bool plotNeeded = false;
345
346  for(int i=0;i<numPlots;i++){
347   
348    plotFlag[i] = plotList[i].setUpPlot(pgDestination[i].c_str(),
349                                        float(xdim),float(ydim));
350       
351    if(plotFlag[i]<=0) duchampError("plotMomentMap",
352                                    "Could not open PGPlot device "
353                                    + pgDestination[i] + ".\n");
354    else{
355      doPlot[i] = true;
356      plotNeeded = true;
357    }
358  }
359
360  if(plotNeeded){
361
362    if(this->objectList.size()==0){
363      // if there are no detections, we plot an empty field.
364
365      for(int iplot=0; iplot<numPlots; iplot++){
366        plotList[iplot].goToPlot();
367        plotList[iplot].makeTitle(this->pars().getImageFile());
368       
369        plotList[iplot].drawMapBox(boxXmin+0.5,boxXmin+xdim+0.5,
370                                   boxYmin+0.5,boxYmin+ydim+0.5,
371                                   "X pixel","Y pixel");
372       
373        this->plotBlankEdges();
374       
375        if(this->head.isWCS()) this->plotWCSaxes();
376      }
377
378    }
379    else { 
380      // if there are some detections, do the calculations first before
381      //  plotting anything.
382 
383      for(int iplot=0; iplot<numPlots; iplot++){
384        // Although plot the axes so that the user knows something is
385        //  being done (at least, they will if there is an /xs plot)
386        plotList[iplot].goToPlot();
387        plotList[iplot].makeTitle(this->pars().getImageFile());
388   
389        plotList[iplot].drawMapBox(boxXmin+0.5,boxXmin+xdim+0.5,
390                                   boxYmin+0.5,boxYmin+ydim+0.5,
391                                   "X pixel","Y pixel");
392       
393        if(pgDestination[iplot]=="/xs")
394          cpgptxt(boxXmin+0.5+xdim/2., boxYmin+0.5+ydim/2., 0, 0.5,
395                  "Calculating map...");
396      }
397
398      bool *isObj = new bool[xdim*ydim*zdim];
399      for(int i=0;i<xdim*ydim*zdim;i++) isObj[i] = false;
400      for(int i=0;i<this->objectList.size();i++){
401        for(int p=0;p<this->objectList[i].getSize();p++){
402          int pixelpos = this->objectList[i].getX(p) +
403            xdim*this->objectList[i].getY(p) +
404            xdim*ydim*this->objectList[i].getZ(p);
405          isObj[pixelpos] = true;
406        }
407      }
408
409      float *momentMap = new float[xdim*ydim];
410      // Initialise to zero
411      for(int i=0;i<xdim*ydim;i++) momentMap[i] = 0.;
412
413      // if we are looking for negative features, we need to invert the
414      //  detected pixels for the moment map
415      float sign = 1.;
416      if(this->pars().getFlagNegative()) sign = -1.;
417
418      float deltaVel;
419      double x,y;
420
421      double *zArray  = new double[zdim];
422      for(int z=0; z<zdim; z++) zArray[z] = double(z);
423   
424      double *world  = new double[zdim];
425
426      for(int pix=0; pix<xdim*ydim; pix++){
427
428        x = double(pix%xdim);
429        y = double(pix/xdim);
430
431        delete [] world;
432        world = this->head.pixToVel(x,y,zArray,zdim);
433     
434        for(int z=0; z<zdim; z++){     
435          int pos =  z*xdim*ydim + pix;  // the voxel in the cube
436          if(isObj[pos]){ // if it's an object pixel...
437            // delta-vel is half the distance between adjacent channels.
438            // if at end, then just use 0-1 or (zdim-1)-(zdim-2) distance
439            if(z==0){
440              if(zdim==1) deltaVel=1.; // pathological case -- if 2D image.
441              else deltaVel = world[z+1] - world[z];
442            }
443            else if(z==(zdim-1)) deltaVel = world[z-1] - world[z];
444            else deltaVel = (world[z+1] - world[z-1]) / 2.;
445
446            momentMap[pix] += sign * this->array[pos] * fabs(deltaVel);
447
448          }
449        }
450
451      }
452   
453      delete [] world;
454      delete [] zArray;
455
456      float *temp = new float[xdim*ydim];
457      int count=0;
458      for(int i=0;i<xdim*ydim;i++) {
459        if(momentMap[i]>0.){
460          bool addPixel = false;
461          for(int z=0;z<zdim;z++) addPixel = addPixel || isObj[z*xdim*ydim+i];
462          if(addPixel) temp[count++] = log10(momentMap[i]);
463        }
464      }
465      float z1,z2;
466      z1 = z2 = temp[0];
467      for(int i=1;i<count;i++){
468        if(temp[i]<z1) z1 = temp[i];
469        if(temp[i]>z2) z2 = temp[i];
470      }
471      delete [] temp;
472
473      for(int i=0;i<xdim*ydim;i++) {
474        bool addPixel = false;
475        for(int z=0;z<zdim;z++) addPixel = addPixel || isObj[z*xdim*ydim+i];
476        addPixel = addPixel && (momentMap[i]>0.);
477        if(!addPixel) momentMap[i] = z1-1.;
478        else momentMap[i] = log10(momentMap[i]);
479      }
480
481      delete [] isObj;
482
483      // Have now done all necessary calculations for moment map.
484      // Now produce the plot
485
486      for(int iplot=0; iplot<numPlots; iplot++){
487        plotList[iplot].goToPlot();
488     
489        float tr[6] = {boxXmin,1.,0.,boxYmin,0.,1.};
490        cpggray(momentMap,xdim,ydim,1,xdim,1,ydim,z2,z1,tr);
491        cpgbox("bcnst",0.,0,"bcnst",0.,0);
492        cpgsch(1.5);
493        string wedgeLabel = "Integrated Flux ";
494        if(this->par.getFlagNegative())
495          wedgeLabel = "-1. " + times + " " + wedgeLabel;
496        if(this->head.isWCS())
497          wedgeLabel += "[" + this->head.getIntFluxUnits() + "]";
498        else wedgeLabel += "[" + this->head.getFluxUnits() + "]";
499        cpgwedglog("rg",3.2,2,z2,z1,wedgeLabel.c_str());
500
501
502        this->plotBlankEdges();
503
504        if(this->head.isWCS()) this->plotWCSaxes();
505 
506        // now show and label each detection, drawing over the WCS lines.
507        cpgsch(1.0);
508        cpgslw(2);
509        float xoff=0.;
510        float yoff=plotList[iplot].cmToCoord(0.5);
511        if(this->par.drawBorders()){
512          cpgsci(BLUE);
513          for(int i=0;i<this->objectList.size();i++)
514            this->objectList[i].drawBorders(0,0);
515        }
516        cpgsci(RED);
517        std::stringstream label;
518        cpgslw(1);
519        for(int i=0;i<this->objectList.size();i++){
520          cpgpt1(this->par.getXOffset()+this->objectList[i].getXcentre(),
521                 this->par.getYOffset()+this->objectList[i].getYcentre(),
522                 CROSS);
523          label.str("");
524          label << this->objectList[i].getID();
525          cpgptxt(this->par.getXOffset()+this->objectList[i].getXcentre()-xoff,
526                  this->par.getYOffset()+this->objectList[i].getYcentre()-yoff,
527                  0, 0.5, label.str().c_str());
528        }
529
530      } // end of iplot loop over number of devices
531
532      delete [] momentMap;
533
534    } // end of else (from if(numdetections==0) )
535
536 
537    for(int iplot=0; iplot<numPlots; iplot++){
538      plotList[iplot].goToPlot();
539      cpgclos();
540    }
541
542  }
543 
544}
545
546/*********************************************************/
547
548
549void Cube::plotWCSaxes()
550{
551  /**
552   *  Cube::plotWCSaxes()
553   *    A front-end to the cpgsbox command, to draw the gridlines for the WCS
554   *      over the current plot.
555   *    Lines are drawn in dark green over the full plot area, and the axis
556   *      labels are written on the top and on the right hand sides, so as not
557   *      to conflict with other labels.
558   */
559
560  float boxXmin=0,boxYmin=0;
561
562  char idents[3][80], opt[2], nlcprm[1];
563
564  struct wcsprm *tempwcs;
565  tempwcs = this->head.getWCS();
566
567  strcpy(idents[0], tempwcs->lngtyp);
568  strcpy(idents[1], tempwcs->lattyp);
569  strcpy(idents[2], "");
570  if(strcmp(tempwcs->lngtyp,"RA")==0) opt[0] = 'G';
571  else opt[0] = 'D';
572  opt[1] = 'E';
573
574  float  blc[2], scl, trc[2];
575  blc[0] = boxXmin + 0.5;
576  blc[1] = boxYmin + 0.5;
577  trc[0] = boxXmin + this->axisDim[0]+0.5;
578  trc[1] = boxYmin + this->axisDim[1]+0.5;
579 
580  int lineWidth;
581  cpgqlw(&lineWidth);
582  int colour;
583  cpgqci(&colour);
584  float size;
585  cpgqch(&size);
586  cpgsci(GREEN);
587  cpgsch(0.8);
588  int    c0[7], ci[7], gcode[2], ic, ierr;
589  for(int i=0;i<7;i++) c0[i] = -1;
590  /* define a Dark Green colour. */
591  cpgscr(17, 0.3, 0.5, 0.3);
592
593  gcode[0] = 2;  // type of grid to draw: 0=none, 1=ticks only, 2=full grid
594  gcode[1] = 2;
595
596  double cache[257][4], grid1[9], grid2[9], nldprm[8];
597  grid1[0] = 0.0; 
598  grid2[0] = 0.0;
599
600  // Draw the celestial grid with no intermediate tick marks.
601  // Set LABCTL=2100 to write 1st coord on top, and 2nd on right
602
603  //Colour indices used by cpgsbox: make it all the same colour for thin
604  // line case.
605  ci[0] = 17; // grid lines, coord 1
606  ci[1] = 17; // grid lines, coord 2
607  ci[2] = 17; // numeric labels, coord 1
608  ci[3] = 17; // numeric labels, coord 2
609  ci[4] = 17; // axis annotation, coord 1
610  ci[5] = 17; // axis annotation, coord 2
611  ci[6] = 17; // title
612
613  cpgsbox(blc, trc, idents, opt, 2100, 0, ci, gcode, 0.0, 0, grid1, 0, grid2,
614          0, pgwcsl_, 1, WCSLEN, 1, nlcprm, (int *)tempwcs,
615          nldprm, 256, &ic, cache, &ierr);
616
617  wcsfree(tempwcs);
618
619  cpgsci(colour);
620  cpgsch(size);
621  cpgslw(lineWidth);
622}
623
Note: See TracBrowser for help on using the repository browser.