source: trunk/src/Cubes/plotting.cc @ 965

Last change on this file since 965 was 921, checked in by MatthewWhiting, 12 years ago

Another bunch of int --> size_t conversions...

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