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

Last change on this file since 1441 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
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/Plotting/SpectralPlot.hh>
45#include <duchamp/Plotting/SimpleSpectralPlot.hh>
46#include <duchamp/Plotting/ImagePlot.hh>
47#include <duchamp/Utils/utils.hh>
48#include <duchamp/Utils/mycpgplot.hh>
49
50using namespace mycpgplot;
51using namespace PixelInfo;
52
53namespace duchamp
54{
55
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.
68
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;
75
76    long xdim=this->axisDim[0];
77    long ydim=this->axisDim[1];
78    long zdim=this->axisDim[2];
79
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     
101        // Find the maximum & minimum values of the spectrum, ignoring flagged channels.
102        float max,min;
103        bool haveStarted=false;
104        for(int z=0;z<zdim;z++){
105            if(!this->par.isFlaggedChannel(z)){
106                if(specy[z]>max || !haveStarted) max=specy[z];
107                if(specy[z]<min || !haveStarted) min=specy[z];
108                haveStarted=true;
109            }
110        }
111
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);
128        if(this->par.getFlagSubsection()) filename += this->par.getSubsection();
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        }
142        this->drawFlaggedChannels(spPlot,0.,0.);
143
144        spPlot.markDetectedPixels(this->detectMap,zdim,this->head);
145
146        for(size_t i=0;i<this->getNumObj();i++){
147          drawSpectralRange(spPlot,this->objectList->at(i),this->head);
148        }
149
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        // }
170      }
171
172      spPlot.close();
173    }
174    else { // num dim > 1
175
176      Plot::ImagePlot newplot(xdim,ydim);
177      int flag = newplot.setUpPlot(pgDestination);
178
179      if(flag<=0){
180        DUCHAMPERROR("Plot Detection Map", "Could not open PGPlot device " << pgDestination);
181      }
182      else{
183
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());
186
187        std::string filename=this->pars().getImageFile();
188        newplot.makeTitle(filename.substr(filename.rfind('/')+1,filename.size()));
189
190        newplot.drawMapBox(boxXmin+0.5,boxXmin+xdim+0.5,
191                           boxYmin+0.5,boxYmin+ydim+0.5,
192                           "X pixel","Y pixel");
193
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;
219     
220        drawBlankEdges(this->array,this->axisDim[0],this->axisDim[1],this->par);
221     
222        if(this->head.isWCS()) this->plotWCSaxes();
223 
224        if(this->objectList->size()>0){
225          // now show and label each detection, drawing over the WCS lines.
226
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);
235          }
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
252        }
253
254        newplot.close();
255      }
256    }
257  }
258
259  /*********************************************************/
260
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.
268
269    std::vector<std::string> devicelist;
270    devicelist.push_back(pgDestination);
271    this->plotMomentMap(devicelist);
272  }
273
274  /*********************************************************/
275
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.
291
292    float boxXmin = this->par.getXOffset() - 1;
293    float boxYmin = this->par.getYOffset() - 1;
294
295    long xdim=this->axisDim[0];
296    long ydim=this->axisDim[1];
297
298    int numPlots = pgDestination.size();
299    std::vector<Plot::ImagePlot> plotList(numPlots,Plot::ImagePlot(xdim,ydim));
300    std::vector<int> plotFlag(numPlots,0);
301    std::vector<bool> doPlot(numPlots,false);
302    bool plotNeeded = false;
303
304    for(int i=0;i<numPlots;i++){
305   
306      plotFlag[i] = plotList[i].setUpPlot(pgDestination[i]);
307       
308      if(plotFlag[i]<=0){
309        DUCHAMPERROR("Plot Moment Map", "Could not open PGPlot device " << pgDestination[i]);
310      }
311      else{
312        doPlot[i] = true;
313        plotNeeded = true;
314      }
315
316    }
317
318    if(plotNeeded){
319
320      if(this->objectList->size()==0){
321        // if there are no detections, we plot an empty field.
322
323        for(int iplot=0; iplot<numPlots; iplot++){
324          plotList[iplot].goToPlot();
325          std::string filename=this->pars().getImageFile();
326          plotList[iplot].makeTitle(filename.substr(filename.rfind('/')+1,filename.size()));
327       
328          plotList[iplot].drawMapBox(boxXmin+0.5,boxXmin+xdim+0.5,
329                                     boxYmin+0.5,boxYmin+ydim+0.5,
330                                     "X pixel","Y pixel");
331       
332          drawBlankEdges(this->array,this->axisDim[0],this->axisDim[1],this->par);
333       
334          if(this->head.isWCS()) this->plotWCSaxes();
335        }
336
337      }
338      else { 
339        // if there are some detections, do the calculations first before
340        //  plotting anything.
341 
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
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();
349          std::string filename=this->pars().getImageFile();
350          plotList[iplot].makeTitle(filename.substr(filename.rfind('/')+1,filename.size()));
351   
352          plotList[iplot].drawMapBox(boxXmin+0.5,boxXmin+xdim+0.5,
353                                     boxYmin+0.5,boxYmin+ydim+0.5,
354                                     "X pixel","Y pixel");
355       
356          if(pgDestination[iplot]=="/xs")
357            cpgptxt(boxXmin+0.5+xdim/2., boxYmin+0.5+ydim/2., 0, 0.5,
358                    "Calculating map...");
359        }
360
361        float *momentMap = new float[xdim*ydim];
362        float z1=0.,z2=0.;
363        this->getMomentMapForPlot(momentMap,z1,z2);
364
365
366        // Have now done all necessary calculations for moment map.
367        // Now produce the plot
368
369        for(int iplot=0; iplot<numPlots; iplot++){
370          plotList[iplot].goToPlot();
371     
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());
383
384
385          drawBlankEdges(this->array,this->axisDim[0],this->axisDim[1],this->par);
386
387          if(this->head.isWCS()) this->plotWCSaxes();
388 
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);
396            for(size_t i=0;i<this->objectList->size();i++)
397              if(objectChoice[i]) this->objectList->at(i).drawBorders(0,0);
398          }
399          cpgsci(DUCHAMP_ID_TEXT_COLOUR);
400          std::stringstream label;
401          cpgslw(1);
402          for(size_t i=0;i<this->objectList->size();i++){
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            }
413          }
414
415        } // end of iplot loop over number of devices
416
417        delete [] momentMap;
418
419      } // end of else (from if(numdetections==0) )
420
421 
422      for(int iplot=0; iplot<numPlots; iplot++){
423        plotList[iplot].goToPlot();
424        plotList[iplot].close();
425      }
426   
427    }
428 
429  }
430
431  /*********************************************************/
432
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
490}
491
Note: See TracBrowser for help on using the repository browser.