source: tags/release-1.1.5/src/Cubes/plotting.cc @ 1441

Last change on this file since 1441 was 401, checked in by MatthewWhiting, 16 years ago

Added wcslib/ to front of include calls to cpgsbox.h and pgwcsl.h

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