source: tags/release-1.1.8/src/Cubes/plotting.cc @ 1391

Last change on this file since 1391 was 602, checked in by MatthewWhiting, 15 years ago

Missed a conflict...

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