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

Last change on this file since 1391 was 1366, checked in by MatthewWhiting, 10 years ago

Only write the subsection string after the filename if flagSubsection has been set.

File size: 16.2 KB
RevLine 
[299]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// -----------------------------------------------------------------------
[3]29#include <iostream>
30#include <iomanip>
31#include <sstream>
32#include <math.h>
[656]33#include <string.h>
[3]34#include <cpgplot.h>
[401]35#include <wcslib/cpgsbox.h>
36#include <wcslib/pgwcsl.h>
[394]37#include <wcslib/wcs.h>
[393]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>
[463]43#include <duchamp/Cubes/cubeUtils.hh>
[1242]44#include <duchamp/Plotting/SpectralPlot.hh>
45#include <duchamp/Plotting/SimpleSpectralPlot.hh>
46#include <duchamp/Plotting/ImagePlot.hh>
[393]47#include <duchamp/Utils/utils.hh>
48#include <duchamp/Utils/mycpgplot.hh>
[3]49
[146]50using namespace mycpgplot;
[258]51using namespace PixelInfo;
[3]52
[378]53namespace duchamp
54{
55
[581]56  void Cube::plotDetectionMap(std::string pgDestination)
57  {
58    ///  @details
59    ///  Creates a map of the spatial locations of the detections, which is
60    ///   written to the PGPlot device given by pgDestination.
61    ///  The map is done in greyscale, where the scale indicates the number of
62    ///   velocity channels that each spatial pixel is detected in.
63    ///  The boundaries of each detection are drawn, and each object is numbered
64    ///   (to match the output list and spectra).
65    ///  The primary grid scale is pixel coordinate, and if the WCS is valid,
66    ///   the correct WCS gridlines are also drawn.
67    /// \param pgDestination The PGPLOT device to be opened, in the typical PGPLOT format.
[3]68
[581]69    // These are the minimum values for the X and Y ranges of the box drawn by
70    //   pgplot (without the half-pixel difference).
71    // The -1 is necessary because the arrays we are dealing with start at 0
72    //  index, while the ranges given in the subsection start at 1...
73    float boxXmin = this->par.getXOffset() - 1;
74    float boxYmin = this->par.getYOffset() - 1;
[3]75
[581]76    long xdim=this->axisDim[0];
77    long ydim=this->axisDim[1];
[985]78    long zdim=this->axisDim[2];
[3]79
[985]80    if( this->numNondegDim == 1){
81     
82      float *specx  = new float[zdim];
83      float *specy  = new float[zdim];
84      float *specy2 = new float[zdim];
85      float *base   = new float[zdim];
86      Plot::SimpleSpectralPlot spPlot;
87      int flag = spPlot.setUpPlot(pgDestination.c_str());
88      if(flag <= 0){
89        DUCHAMPERROR("Plot Detection Map", "Could not open PGPlot device " << pgDestination);
90      }
91      else{
92       
93        this->getSpectralArrays(-1,specx,specy,specy2,base);
94        float vmax,vmin,width;
95        vmax = vmin = specx[0];
96        for(int i=1;i<zdim;i++){
97          if(specx[i]>vmax) vmax=specx[i];
98          if(specx[i]<vmin) vmin=specx[i];
99        }
100     
[1242]101        // Find the maximum & minimum values of the spectrum, ignoring flagged channels.
[985]102        float max,min;
[1242]103        bool haveStarted=false;
104        for(int z=0;z<zdim;z++){
105            if(!this->par.isFlaggedChannel(z)){
[1251]106                if(specy[z]>max || !haveStarted) max=specy[z];
107                if(specy[z]<min || !haveStarted) min=specy[z];
[1242]108                haveStarted=true;
[985]109            }
110        }
[1242]111
[985]112        // widen the ranges slightly so that the top & bottom & edges don't
113        // lie on the axes.
114        width = max - min;
115        max += width * 0.15;
116        min -= width * 0.05;
117        width = vmax - vmin;
118        vmax += width * 0.01;
119        vmin -= width * 0.01;
120        std::string label,fluxLabel = "Flux ["+this->head.getFluxUnits()+"]";
121        if(this->head.isWCS()){
122          label = this->head.getSpectralDescription() + " [" +
123            this->head.getSpectralUnits() + "]";
124        }
125        else label="Spectral pixel";
126        std::string filename=this->pars().getImageFile();
127        filename = filename.substr(filename.rfind('/')+1);
[1366]128        if(this->par.getFlagSubsection()) filename += this->par.getSubsection();
[985]129        spPlot.label(label,fluxLabel,"Detection summary : " + filename);
130        spPlot.gotoMainSpectrum(vmin,vmax,min,max);
131        cpgline(zdim,specx,specy);
132        if(this->par.getFlagBaseline()){
133          cpgsci(DUCHAMP_BASELINE_SPECTRA_COLOUR);
134          cpgline(zdim,specx,base);
135          cpgsci(FOREGND);
136        }
137        if(this->reconExists){
138          cpgsci(DUCHAMP_RECON_SPECTRA_COLOUR);
139          cpgline(zdim,specx,specy2);   
140          cpgsci(FOREGND);
141        }
[1242]142        this->drawFlaggedChannels(spPlot,0.,0.);
[3]143
[1013]144        spPlot.markDetectedPixels(this->detectMap,zdim,this->head);
[615]145
[985]146        for(size_t i=0;i<this->getNumObj();i++){
147          drawSpectralRange(spPlot,this->objectList->at(i),this->head);
148        }
[3]149
[1258]150        if(this->par.getFlagBaseline())
151            spPlot.drawThresholds(this->par,this->Stats,specx,base,zdim);
152        else
153            spPlot.drawThresholds(this->par,this->Stats);
154
155
156        // cpgsci(RED);
157        // cpgsls(DASHED);
158        // float thresh = this->Stats.getThreshold();
159        // if(this->par.getFlagNegative()) thresh *= -1.;
160        // cpgmove(vmin,thresh);
161        // cpgdraw(vmax,thresh);
162        // if(this->par.getFlagGrowth()){
163        //   if(this->par.getFlagUserGrowthThreshold()) thresh= this->par.getGrowthThreshold();
164        //   else thresh= this->Stats.snrToValue(this->par.getGrowthCut());
165        //   if(this->par.getFlagNegative()) thresh *= -1.;     
166        //   cpgsls(DOTTED);
167        //   cpgmove(vmin,thresh);
168        //   cpgdraw(vmax,thresh);
169        // }
[985]170      }
[3]171
[985]172      spPlot.close();
173    }
[1104]174    else { // num dim > 1
[3]175
[1242]176      Plot::ImagePlot newplot(xdim,ydim);
177      int flag = newplot.setUpPlot(pgDestination);
[985]178
179      if(flag<=0){
180        DUCHAMPERROR("Plot Detection Map", "Could not open PGPlot device " << pgDestination);
[581]181      }
[985]182      else{
[3]183
[985]184        // get the list of objects that should be plotted. Only applies to outlines and labels.
185        std::vector<bool> objectChoice = this->par.getObjectChoices(this->objectList->size());
[3]186
[985]187        std::string filename=this->pars().getImageFile();
188        newplot.makeTitle(filename.substr(filename.rfind('/')+1,filename.size()));
[204]189
[985]190        newplot.drawMapBox(boxXmin+0.5,boxXmin+xdim+0.5,
191                           boxYmin+0.5,boxYmin+ydim+0.5,
192                           "X pixel","Y pixel");
[666]193
[985]194        //     if(this->objectList.size()>0){
195        // if there are no detections, there will be nothing to plot here
196
197        // Define a float equivalent of this->detectMap that can be plotted by cpggray.
198        // Also find the maximum value, so that we can get the greyscale right and plot a colour wedge.
199        float *detectionMap = new float[xdim*ydim];
200        int maxNum = this->detectMap[0];
201        detectionMap[0] = float(maxNum);
202        for(int pix=1;pix<xdim*ydim;pix++){
203          detectionMap[pix] = float(this->detectMap[pix]); 
204          if(this->detectMap[pix] > maxNum)  maxNum = this->detectMap[pix];
205        }
206
207        if(maxNum>0){ // if there are no detections, it will be 0.
208
209          maxNum = 5 * ((maxNum-1)/5 + 1);  // move to next multiple of 5
210
211          float tr[6] = {boxXmin,1.,0.,boxYmin,0.,1.};
212          cpggray(detectionMap,xdim,ydim,1,xdim,1,ydim,maxNum,0,tr); 
213          cpgbox("bcnst",0.,0,"bcnst",0.,0);
214          cpgsch(1.5);
215          cpgwedg("rg",3.2,2,maxNum,0,"Number of detected channels");
216        }
217
218        delete [] detectionMap;
[208]219     
[985]220        drawBlankEdges(this->array,this->axisDim[0],this->axisDim[1],this->par);
[208]221     
[985]222        if(this->head.isWCS()) this->plotWCSaxes();
[3]223 
[985]224        if(this->objectList->size()>0){
225          // now show and label each detection, drawing over the WCS lines.
[3]226
[985]227          cpgsch(1.0);
228          cpgslw(2);   
229          float xoff=0.;
230          float yoff=newplot.cmToCoord(0.5);
231          if(this->par.drawBorders()){
232            cpgsci(DUCHAMP_OBJECT_OUTLINE_COLOUR);
233            for(size_t i=0;i<this->objectList->size();i++)
234              if(objectChoice[i]) this->objectList->at(i).drawBorders(0,0);
[615]235          }
[985]236          cpgsci(DUCHAMP_ID_TEXT_COLOUR);
237          std::stringstream label;
238          cpgslw(1);
239          for(size_t i=0;i<this->objectList->size();i++){
240            if(objectChoice[i]) {
241              cpgpt1(this->par.getXOffset()+this->objectList->at(i).getXPeak(),
242                     this->par.getYOffset()+this->objectList->at(i).getYPeak(),
243                     CROSS);
244              label.str("");
245              label << this->objectList->at(i).getID();
246              cpgptxt(this->par.getXOffset()+this->objectList->at(i).getXPeak()-xoff,
247                      this->par.getYOffset()+this->objectList->at(i).getYPeak()-yoff,
248                      0, 0.5, label.str().c_str());
249            }
250          }
251
[581]252        }
253
[985]254        newplot.close();
[103]255      }
[3]256    }
257  }
258
[581]259  /*********************************************************/
[3]260
[581]261  void Cube::plotMomentMap(std::string pgDestination)
262  {
263    ///  @details
264    ///  Uses the other function
265    ///  Cube::plotMomentMap(std::vector<std::string>) to plot the moment
266    ///  map.
267    /// \param pgDestination The PGPLOT device that the map is to be written to.
[3]268
[581]269    std::vector<std::string> devicelist;
270    devicelist.push_back(pgDestination);
271    this->plotMomentMap(devicelist);
272  }
[3]273
[581]274  /*********************************************************/
[3]275
[581]276  void Cube::plotMomentMap(std::vector<std::string> pgDestination)
277  {
278    ///  @details
279    ///  Creates a 0th moment map of the detections, which is written to each
280    ///   of the PGPlot devices mentioned in pgDestination.
281    ///  The advantage of this function is that the map is only calculated once,
282    ///   even if multiple maps are required.
283    ///  The map is done in greyscale, where the scale indicates the integrated
284    ///   flux at each spatial pixel.
285    ///  The boundaries of each detection are drawn, and each object is numbered
286    ///   (to match the output list and spectra).
287    ///  The primary grid scale is pixel coordinate, and if the WCS is valid,
288    ///   the correct WCS gridlines are also drawn.
289    /// \param pgDestination A set of PGPLOT devices that are to be
290    /// opened, each in the typical PGPLOT format.
[3]291
[581]292    float boxXmin = this->par.getXOffset() - 1;
293    float boxYmin = this->par.getYOffset() - 1;
[203]294
[581]295    long xdim=this->axisDim[0];
296    long ydim=this->axisDim[1];
[203]297
[581]298    int numPlots = pgDestination.size();
[1242]299    std::vector<Plot::ImagePlot> plotList(numPlots,Plot::ImagePlot(xdim,ydim));
[581]300    std::vector<int> plotFlag(numPlots,0);
301    std::vector<bool> doPlot(numPlots,false);
302    bool plotNeeded = false;
[203]303
[581]304    for(int i=0;i<numPlots;i++){
[203]305   
[1242]306      plotFlag[i] = plotList[i].setUpPlot(pgDestination[i]);
[203]307       
[913]308      if(plotFlag[i]<=0){
309        DUCHAMPERROR("Plot Moment Map", "Could not open PGPlot device " << pgDestination[i]);
310      }
[581]311      else{
312        doPlot[i] = true;
313        plotNeeded = true;
314      }
315
[203]316    }
[485]317
[581]318    if(plotNeeded){
[203]319
[581]320      if(this->objectList->size()==0){
321        // if there are no detections, we plot an empty field.
[203]322
[581]323        for(int iplot=0; iplot<numPlots; iplot++){
324          plotList[iplot].goToPlot();
[755]325          std::string filename=this->pars().getImageFile();
326          plotList[iplot].makeTitle(filename.substr(filename.rfind('/')+1,filename.size()));
[203]327       
[581]328          plotList[iplot].drawMapBox(boxXmin+0.5,boxXmin+xdim+0.5,
329                                     boxYmin+0.5,boxYmin+ydim+0.5,
330                                     "X pixel","Y pixel");
[203]331       
[581]332          drawBlankEdges(this->array,this->axisDim[0],this->axisDim[1],this->par);
[203]333       
[581]334          if(this->head.isWCS()) this->plotWCSaxes();
335        }
336
[203]337      }
[581]338      else { 
339        // if there are some detections, do the calculations first before
340        //  plotting anything.
[203]341 
[615]342        // get the list of objects that should be plotted. Only applies to outlines and labels.
343        std::vector<bool> objectChoice = this->par.getObjectChoices(this->objectList->size());
344
[581]345        for(int iplot=0; iplot<numPlots; iplot++){
346          // Although plot the axes so that the user knows something is
347          //  being done (at least, they will if there is an /xs plot)
348          plotList[iplot].goToPlot();
[755]349          std::string filename=this->pars().getImageFile();
350          plotList[iplot].makeTitle(filename.substr(filename.rfind('/')+1,filename.size()));
[203]351   
[581]352          plotList[iplot].drawMapBox(boxXmin+0.5,boxXmin+xdim+0.5,
353                                     boxYmin+0.5,boxYmin+ydim+0.5,
354                                     "X pixel","Y pixel");
[203]355       
[581]356          if(pgDestination[iplot]=="/xs")
357            cpgptxt(boxXmin+0.5+xdim/2., boxYmin+0.5+ydim/2., 0, 0.5,
358                    "Calculating map...");
359        }
[203]360
[668]361        float *momentMap = new float[xdim*ydim];
[665]362        float z1=0.,z2=0.;
[668]363        this->getMomentMapForPlot(momentMap,z1,z2);
[581]364
[203]365
[581]366        // Have now done all necessary calculations for moment map.
367        // Now produce the plot
[203]368
[581]369        for(int iplot=0; iplot<numPlots; iplot++){
370          plotList[iplot].goToPlot();
[203]371     
[581]372          float tr[6] = {boxXmin,1.,0.,boxYmin,0.,1.};
373          cpggray(momentMap,xdim,ydim,1,xdim,1,ydim,z2,z1,tr);
374          cpgbox("bcnst",0.,0,"bcnst",0.,0);
375          cpgsch(1.5);
376          std::string wedgeLabel = "Integrated Flux ";
377          if(this->par.getFlagNegative())
378            wedgeLabel = "-1. " + times + " " + wedgeLabel;
379          if(this->head.isWCS())
380            wedgeLabel += "[" + this->head.getIntFluxUnits() + "]";
381          else wedgeLabel += "[" + this->head.getFluxUnits() + "]";
382          cpgwedglog("rg",3.2,2,z2,z1,wedgeLabel.c_str());
[203]383
384
[581]385          drawBlankEdges(this->array,this->axisDim[0],this->axisDim[1],this->par);
[203]386
[581]387          if(this->head.isWCS()) this->plotWCSaxes();
[203]388 
[581]389          // now show and label each detection, drawing over the WCS lines.
390          cpgsch(1.0);
391          cpgslw(2);
392          float xoff=0.;
393          float yoff=plotList[iplot].cmToCoord(0.5);
394          if(this->par.drawBorders()){
395            cpgsci(DUCHAMP_OBJECT_OUTLINE_COLOUR);
[623]396            for(size_t i=0;i<this->objectList->size();i++)
[615]397              if(objectChoice[i]) this->objectList->at(i).drawBorders(0,0);
[581]398          }
399          cpgsci(DUCHAMP_ID_TEXT_COLOUR);
400          std::stringstream label;
401          cpgslw(1);
[623]402          for(size_t i=0;i<this->objectList->size();i++){
[615]403            if(objectChoice[i]) {
404              cpgpt1(this->par.getXOffset()+this->objectList->at(i).getXPeak(),
405                     this->par.getYOffset()+this->objectList->at(i).getYPeak(),
406                     CROSS);
407              label.str("");
408              label << this->objectList->at(i).getID();
409              cpgptxt(this->par.getXOffset()+this->objectList->at(i).getXPeak()-xoff,
410                      this->par.getYOffset()+this->objectList->at(i).getYPeak()-yoff,
411                      0, 0.5, label.str().c_str());
412            }
[581]413          }
[203]414
[581]415        } // end of iplot loop over number of devices
[203]416
[581]417        delete [] momentMap;
[203]418
[581]419      } // end of else (from if(numdetections==0) )
[203]420
421 
[581]422      for(int iplot=0; iplot<numPlots; iplot++){
423        plotList[iplot].goToPlot();
[985]424        plotList[iplot].close();
[581]425      }
426   
[203]427    }
[581]428 
[203]429  }
430
[581]431  /*********************************************************/
[203]432
[998]433  void drawSpectralRange(Plot::SpectralPlot &plot, Detection &obj, FitsHeader &head)
434  {
435    /// @details
436
437    /// A front-end to drawing the lines delimiting the spectral
438    /// extent of the detection. This takes into account the channel
439    /// widths, offsetting outwards by half a channel (for instance, a
440    /// single-channel detection will not have the separation of one
441    /// channel).
442    /// If the world coordinate is being plotted, the correct offset
443    /// is calcuated by transforming from the central spatial
444    /// positions and the offsetted min/max z-pixel extents
445
446    if(head.isWCS()){
447      double x=obj.getXcentre(),y=obj.getYcentre(),z;
448      z=obj.getZmin()-0.5;
449      float vmin=head.pixToVel(x,y,z);
450      z=obj.getZmax()+0.5;
451      float vmax=head.pixToVel(x,y,z);
452      plot.drawVelRange(vmin,vmax);
453    }
454    else{
455      plot.drawVelRange(obj.getZmin()-0.5,obj.getZmax()+0.5);
456    }
457
458
459  }
460
461  void drawSpectralRange(Plot::SimpleSpectralPlot &plot, Detection &obj, FitsHeader &head)
462  {
463    /// @details
464
465    /// A front-end to drawing the lines delimiting the spectral
466    /// extent of the detection. This takes into account the channel
467    /// widths, offsetting outwards by half a channel (for instance, a
468    /// single-channel detection will not have the separation of one
469    /// channel).
470    /// If the world coordinate is being plotted, the correct offset
471    /// is calcuated by transforming from the central spatial
472    /// positions and the offsetted min/max z-pixel extents
473
474    if(head.isWCS()){
475      double x=obj.getXcentre(),y=obj.getYcentre(),z;
476      z=obj.getZmin()-0.5;
477      float vmin=head.pixToVel(x,y,z);
478      z=obj.getZmax()+0.5;
479      float vmax=head.pixToVel(x,y,z);
480      plot.drawVelRange(vmin,vmax);
481    }
482    else{
483      plot.drawVelRange(obj.getZmin()-0.5,obj.getZmax()+0.5);
484    }
485
486  }
487
488
489
[378]490}
491
Note: See TracBrowser for help on using the repository browser.