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

Last change on this file since 1242 was 1242, checked in by MatthewWhiting, 11 years ago

Tickets #193 & #195 - Implementing channel flagging. Still a lot of commented-out code, plus the MW code is still present (although not used anywhere). Also making use of the new plotting classes.

File size: 19.5 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/Cubes/plots.hh>
45#include <duchamp/Plotting/SpectralPlot.hh>
46#include <duchamp/Plotting/SimpleSpectralPlot.hh>
47#include <duchamp/Plotting/ImagePlot.hh>
[393]48#include <duchamp/Utils/utils.hh>
49#include <duchamp/Utils/mycpgplot.hh>
[3]50
[146]51using namespace mycpgplot;
[258]52using namespace PixelInfo;
[3]53
[378]54namespace duchamp
55{
56
[581]57  void Cube::plotDetectionMap(std::string pgDestination)
58  {
59    ///  @details
60    ///  Creates a map of the spatial locations of the detections, which is
61    ///   written to the PGPlot device given by pgDestination.
62    ///  The map is done in greyscale, where the scale indicates the number of
63    ///   velocity channels that each spatial pixel is detected in.
64    ///  The boundaries of each detection are drawn, and each object is numbered
65    ///   (to match the output list and spectra).
66    ///  The primary grid scale is pixel coordinate, and if the WCS is valid,
67    ///   the correct WCS gridlines are also drawn.
68    /// \param pgDestination The PGPLOT device to be opened, in the typical PGPLOT format.
[3]69
[581]70    // These are the minimum values for the X and Y ranges of the box drawn by
71    //   pgplot (without the half-pixel difference).
72    // The -1 is necessary because the arrays we are dealing with start at 0
73    //  index, while the ranges given in the subsection start at 1...
74    float boxXmin = this->par.getXOffset() - 1;
75    float boxYmin = this->par.getYOffset() - 1;
[3]76
[581]77    long xdim=this->axisDim[0];
78    long ydim=this->axisDim[1];
[985]79    long zdim=this->axisDim[2];
[3]80
[985]81    if( this->numNondegDim == 1){
82     
83      float *specx  = new float[zdim];
84      float *specy  = new float[zdim];
85      float *specy2 = new float[zdim];
86      float *base   = new float[zdim];
87      Plot::SimpleSpectralPlot spPlot;
88      int flag = spPlot.setUpPlot(pgDestination.c_str());
89//       int flag=cpgopen(pgDestination.c_str());
90//       cpgpap(spPlot.getPaperWidth(),spPlot.getAspectRatio());
91//       cpgsch(Plot::spLabelSize);
92      if(flag <= 0){
93        DUCHAMPERROR("Plot Detection Map", "Could not open PGPlot device " << pgDestination);
94      }
95      else{
96       
[1242]97//      std::vector<bool> flaggedChans=this->par.getChannelFlags(zdim);
[985]98        this->getSpectralArrays(-1,specx,specy,specy2,base);
99        float vmax,vmin,width;
100        vmax = vmin = specx[0];
101        for(int i=1;i<zdim;i++){
102          if(specx[i]>vmax) vmax=specx[i];
103          if(specx[i]<vmin) vmin=specx[i];
104        }
105     
[1242]106        // // Find the min & max of the spectrum.
107        // float max,min;
108        // int loc=0;
109        // if(this->par.getMinMW()>0) max = min = specy[0];
110        // else max = min = specy[this->par.getMaxMW()+1];
111        // for(int i=0;i<zdim;i++){
112        //   if(!this->par.isInMW(i)){
113        //     if(specy[i]>max) max=specy[i];
114        //     if(specy[i]<min){
115        //       min=specy[i];
116        //       loc = i;
117        //     }
118        //   }
119        // }
120
121        // Find the maximum & minimum values of the spectrum, ignoring flagged channels.
[985]122        float max,min;
[1242]123        bool haveStarted=false;
124        for(int z=0;z<zdim;z++){
125//          if(!flaggedChans[z]){
126            if(!this->par.isFlaggedChannel(z)){
127                if(specy[z]>max && !haveStarted) max=specy[z];
128                if(specy[z]<min && !haveStarted) min=specy[z];
129                haveStarted=true;
[985]130            }
131        }
[1242]132
[985]133        // widen the ranges slightly so that the top & bottom & edges don't
134        // lie on the axes.
135        width = max - min;
136        max += width * 0.15;
137        min -= width * 0.05;
138        width = vmax - vmin;
139        vmax += width * 0.01;
140        vmin -= width * 0.01;
141        std::string label,fluxLabel = "Flux ["+this->head.getFluxUnits()+"]";
142        if(this->head.isWCS()){
143          label = this->head.getSpectralDescription() + " [" +
144            this->head.getSpectralUnits() + "]";
145        }
146        else label="Spectral pixel";
147        std::string filename=this->pars().getImageFile();
148        filename = filename.substr(filename.rfind('/')+1);
149        spPlot.label(label,fluxLabel,"Detection summary : " + filename);
150        spPlot.gotoMainSpectrum(vmin,vmax,min,max);
151        cpgline(zdim,specx,specy);
152        if(this->par.getFlagBaseline()){
153          cpgsci(DUCHAMP_BASELINE_SPECTRA_COLOUR);
154          cpgline(zdim,specx,base);
155          cpgsci(FOREGND);
156        }
157        if(this->reconExists){
158          cpgsci(DUCHAMP_RECON_SPECTRA_COLOUR);
159          cpgline(zdim,specx,specy2);   
160          cpgsci(FOREGND);
161        }
[1242]162        // if(this->par.getFlagMW()){
163        //   double zval = double(this->par.getMinMW()),zero=0.;
164        //   double minMWvel = this->head.pixToVel(zero,zero,zval);
165        //   zval = double(this->par.getMaxMW());
166        //   double maxMWvel = this->head.pixToVel(zero,zero,zval);
167        //   spPlot.drawMWRange(minMWvel,maxMWvel);
168        // }
169        this->drawFlaggedChannels(spPlot,0.,0.);
[3]170
[1013]171        spPlot.markDetectedPixels(this->detectMap,zdim,this->head);
[615]172
[985]173        for(size_t i=0;i<this->getNumObj();i++){
174          drawSpectralRange(spPlot,this->objectList->at(i),this->head);
175        }
[3]176
[985]177        cpgsci(RED);
178        cpgsls(DASHED);
179        float thresh = this->Stats.getThreshold();
180        if(this->par.getFlagNegative()) thresh *= -1.;
181        cpgmove(vmin,thresh);
182        cpgdraw(vmax,thresh);
183        if(this->par.getFlagGrowth()){
184          if(this->par.getFlagUserGrowthThreshold()) thresh= this->par.getGrowthThreshold();
185          else thresh= this->Stats.snrToValue(this->par.getGrowthCut());
186          if(this->par.getFlagNegative()) thresh *= -1.;       
187          cpgsls(DOTTED);
188          cpgmove(vmin,thresh);
189          cpgdraw(vmax,thresh);
190        }
191      }
[3]192
[985]193      spPlot.close();
194    }
[1104]195    else { // num dim > 1
[3]196
[1242]197      Plot::ImagePlot newplot(xdim,ydim);
198      int flag = newplot.setUpPlot(pgDestination);
[985]199
200      if(flag<=0){
201        DUCHAMPERROR("Plot Detection Map", "Could not open PGPlot device " << pgDestination);
[581]202      }
[985]203      else{
[3]204
[985]205        // get the list of objects that should be plotted. Only applies to outlines and labels.
206        std::vector<bool> objectChoice = this->par.getObjectChoices(this->objectList->size());
[3]207
[985]208        std::string filename=this->pars().getImageFile();
209        newplot.makeTitle(filename.substr(filename.rfind('/')+1,filename.size()));
[204]210
[985]211        newplot.drawMapBox(boxXmin+0.5,boxXmin+xdim+0.5,
212                           boxYmin+0.5,boxYmin+ydim+0.5,
213                           "X pixel","Y pixel");
[666]214
[985]215        //     if(this->objectList.size()>0){
216        // if there are no detections, there will be nothing to plot here
217
218        // Define a float equivalent of this->detectMap that can be plotted by cpggray.
219        // Also find the maximum value, so that we can get the greyscale right and plot a colour wedge.
220        float *detectionMap = new float[xdim*ydim];
221        int maxNum = this->detectMap[0];
222        detectionMap[0] = float(maxNum);
223        for(int pix=1;pix<xdim*ydim;pix++){
224          detectionMap[pix] = float(this->detectMap[pix]); 
225          if(this->detectMap[pix] > maxNum)  maxNum = this->detectMap[pix];
226        }
227
228        if(maxNum>0){ // if there are no detections, it will be 0.
229
230          maxNum = 5 * ((maxNum-1)/5 + 1);  // move to next multiple of 5
231
232          float tr[6] = {boxXmin,1.,0.,boxYmin,0.,1.};
233          cpggray(detectionMap,xdim,ydim,1,xdim,1,ydim,maxNum,0,tr); 
234          cpgbox("bcnst",0.,0,"bcnst",0.,0);
235          cpgsch(1.5);
236          cpgwedg("rg",3.2,2,maxNum,0,"Number of detected channels");
237        }
238
239        delete [] detectionMap;
[208]240     
[985]241        drawBlankEdges(this->array,this->axisDim[0],this->axisDim[1],this->par);
[208]242     
[985]243        if(this->head.isWCS()) this->plotWCSaxes();
[3]244 
[985]245        if(this->objectList->size()>0){
246          // now show and label each detection, drawing over the WCS lines.
[3]247
[985]248          cpgsch(1.0);
249          cpgslw(2);   
250          float xoff=0.;
251          float yoff=newplot.cmToCoord(0.5);
252          if(this->par.drawBorders()){
253            cpgsci(DUCHAMP_OBJECT_OUTLINE_COLOUR);
254            for(size_t i=0;i<this->objectList->size();i++)
255              if(objectChoice[i]) this->objectList->at(i).drawBorders(0,0);
[615]256          }
[985]257          cpgsci(DUCHAMP_ID_TEXT_COLOUR);
258          std::stringstream label;
259          cpgslw(1);
260          for(size_t i=0;i<this->objectList->size();i++){
261            if(objectChoice[i]) {
262              cpgpt1(this->par.getXOffset()+this->objectList->at(i).getXPeak(),
263                     this->par.getYOffset()+this->objectList->at(i).getYPeak(),
264                     CROSS);
265              label.str("");
266              label << this->objectList->at(i).getID();
267              cpgptxt(this->par.getXOffset()+this->objectList->at(i).getXPeak()-xoff,
268                      this->par.getYOffset()+this->objectList->at(i).getYPeak()-yoff,
269                      0, 0.5, label.str().c_str());
270            }
271          }
272
[581]273        }
274
[985]275        newplot.close();
[103]276      }
[3]277    }
278  }
279
[581]280  /*********************************************************/
[3]281
[581]282  void Cube::plotMomentMap(std::string pgDestination)
283  {
284    ///  @details
285    ///  Uses the other function
286    ///  Cube::plotMomentMap(std::vector<std::string>) to plot the moment
287    ///  map.
288    /// \param pgDestination The PGPLOT device that the map is to be written to.
[3]289
[581]290    std::vector<std::string> devicelist;
291    devicelist.push_back(pgDestination);
292    this->plotMomentMap(devicelist);
293  }
[3]294
[581]295  /*********************************************************/
[3]296
[581]297  void Cube::plotMomentMap(std::vector<std::string> pgDestination)
298  {
299    ///  @details
300    ///  Creates a 0th moment map of the detections, which is written to each
301    ///   of the PGPlot devices mentioned in pgDestination.
302    ///  The advantage of this function is that the map is only calculated once,
303    ///   even if multiple maps are required.
304    ///  The map is done in greyscale, where the scale indicates the integrated
305    ///   flux at each spatial pixel.
306    ///  The boundaries of each detection are drawn, and each object is numbered
307    ///   (to match the output list and spectra).
308    ///  The primary grid scale is pixel coordinate, and if the WCS is valid,
309    ///   the correct WCS gridlines are also drawn.
310    /// \param pgDestination A set of PGPLOT devices that are to be
311    /// opened, each in the typical PGPLOT format.
[3]312
[581]313    float boxXmin = this->par.getXOffset() - 1;
314    float boxYmin = this->par.getYOffset() - 1;
[203]315
[581]316    long xdim=this->axisDim[0];
317    long ydim=this->axisDim[1];
[203]318
[581]319    int numPlots = pgDestination.size();
[1242]320    std::vector<Plot::ImagePlot> plotList(numPlots,Plot::ImagePlot(xdim,ydim));
[581]321    std::vector<int> plotFlag(numPlots,0);
322    std::vector<bool> doPlot(numPlots,false);
323    bool plotNeeded = false;
[203]324
[581]325    for(int i=0;i<numPlots;i++){
[203]326   
[1242]327      plotFlag[i] = plotList[i].setUpPlot(pgDestination[i]);
[203]328       
[913]329      if(plotFlag[i]<=0){
330        DUCHAMPERROR("Plot Moment Map", "Could not open PGPlot device " << pgDestination[i]);
331      }
[581]332      else{
333        doPlot[i] = true;
334        plotNeeded = true;
335      }
336
[203]337    }
[485]338
[581]339    if(plotNeeded){
[203]340
[581]341      if(this->objectList->size()==0){
342        // if there are no detections, we plot an empty field.
[203]343
[581]344        for(int iplot=0; iplot<numPlots; iplot++){
345          plotList[iplot].goToPlot();
[755]346          std::string filename=this->pars().getImageFile();
347          plotList[iplot].makeTitle(filename.substr(filename.rfind('/')+1,filename.size()));
[203]348       
[581]349          plotList[iplot].drawMapBox(boxXmin+0.5,boxXmin+xdim+0.5,
350                                     boxYmin+0.5,boxYmin+ydim+0.5,
351                                     "X pixel","Y pixel");
[203]352       
[581]353          drawBlankEdges(this->array,this->axisDim[0],this->axisDim[1],this->par);
[203]354       
[581]355          if(this->head.isWCS()) this->plotWCSaxes();
356        }
357
[203]358      }
[581]359      else { 
360        // if there are some detections, do the calculations first before
361        //  plotting anything.
[203]362 
[615]363        // get the list of objects that should be plotted. Only applies to outlines and labels.
364        std::vector<bool> objectChoice = this->par.getObjectChoices(this->objectList->size());
365
[581]366        for(int iplot=0; iplot<numPlots; iplot++){
367          // Although plot the axes so that the user knows something is
368          //  being done (at least, they will if there is an /xs plot)
369          plotList[iplot].goToPlot();
[755]370          std::string filename=this->pars().getImageFile();
371          plotList[iplot].makeTitle(filename.substr(filename.rfind('/')+1,filename.size()));
[203]372   
[581]373          plotList[iplot].drawMapBox(boxXmin+0.5,boxXmin+xdim+0.5,
374                                     boxYmin+0.5,boxYmin+ydim+0.5,
375                                     "X pixel","Y pixel");
[203]376       
[581]377          if(pgDestination[iplot]=="/xs")
378            cpgptxt(boxXmin+0.5+xdim/2., boxYmin+0.5+ydim/2., 0, 0.5,
379                    "Calculating map...");
380        }
[203]381
[668]382        float *momentMap = new float[xdim*ydim];
[665]383        float z1=0.,z2=0.;
[668]384        this->getMomentMapForPlot(momentMap,z1,z2);
[581]385
[203]386
[581]387        // Have now done all necessary calculations for moment map.
388        // Now produce the plot
[203]389
[581]390        for(int iplot=0; iplot<numPlots; iplot++){
391          plotList[iplot].goToPlot();
[203]392     
[581]393          float tr[6] = {boxXmin,1.,0.,boxYmin,0.,1.};
394          cpggray(momentMap,xdim,ydim,1,xdim,1,ydim,z2,z1,tr);
395          cpgbox("bcnst",0.,0,"bcnst",0.,0);
396          cpgsch(1.5);
397          std::string wedgeLabel = "Integrated Flux ";
398          if(this->par.getFlagNegative())
399            wedgeLabel = "-1. " + times + " " + wedgeLabel;
400          if(this->head.isWCS())
401            wedgeLabel += "[" + this->head.getIntFluxUnits() + "]";
402          else wedgeLabel += "[" + this->head.getFluxUnits() + "]";
403          cpgwedglog("rg",3.2,2,z2,z1,wedgeLabel.c_str());
[203]404
405
[581]406          drawBlankEdges(this->array,this->axisDim[0],this->axisDim[1],this->par);
[203]407
[581]408          if(this->head.isWCS()) this->plotWCSaxes();
[203]409 
[581]410          // now show and label each detection, drawing over the WCS lines.
411          cpgsch(1.0);
412          cpgslw(2);
413          float xoff=0.;
414          float yoff=plotList[iplot].cmToCoord(0.5);
415          if(this->par.drawBorders()){
416            cpgsci(DUCHAMP_OBJECT_OUTLINE_COLOUR);
[623]417            for(size_t i=0;i<this->objectList->size();i++)
[615]418              if(objectChoice[i]) this->objectList->at(i).drawBorders(0,0);
[581]419          }
420          cpgsci(DUCHAMP_ID_TEXT_COLOUR);
421          std::stringstream label;
422          cpgslw(1);
[623]423          for(size_t i=0;i<this->objectList->size();i++){
[615]424            if(objectChoice[i]) {
425              cpgpt1(this->par.getXOffset()+this->objectList->at(i).getXPeak(),
426                     this->par.getYOffset()+this->objectList->at(i).getYPeak(),
427                     CROSS);
428              label.str("");
429              label << this->objectList->at(i).getID();
430              cpgptxt(this->par.getXOffset()+this->objectList->at(i).getXPeak()-xoff,
431                      this->par.getYOffset()+this->objectList->at(i).getYPeak()-yoff,
432                      0, 0.5, label.str().c_str());
433            }
[581]434          }
[203]435
[581]436        } // end of iplot loop over number of devices
[203]437
[581]438        delete [] momentMap;
[203]439
[581]440      } // end of else (from if(numdetections==0) )
[203]441
442 
[581]443      for(int iplot=0; iplot<numPlots; iplot++){
444        plotList[iplot].goToPlot();
[985]445        plotList[iplot].close();
[581]446      }
447   
[203]448    }
[581]449 
[203]450  }
451
[581]452  /*********************************************************/
[203]453
[581]454//   void Cube::plotWCSaxes(int textColour, int axisColour)
455//   {
456//     duchamp::plotWCSaxes(this->head.getWCS(), this->axisDim, textColour, axisColour);
457//   }
458 
459 
[884]460  void plotWCSaxes(struct wcsprm *wcs, size_t *axes, int textColour, int axisColour)
[581]461  {
[203]462
[581]463    /// @details
464    ///  A front-end to the cpgsbox command, to draw the gridlines for the WCS
465    ///    over the current plot.
466    ///  Lines are drawn in dark green over the full plot area, and the axis
467    ///    labels are written on the top and on the right hand sides, so as not
468    ///    to conflict with other labels.
469    ///  \param textColour The colour index to use for the text labels --
470    ///  defaults to duchamp::DUCHAMP_ID_TEXT_COLOUR
471    ///  \param axisColour The colour index to use for the axes --
472    ///  defaults to duchamp::DUCHAMP_WCS_AXIS_COLOUR
[3]473
[581]474    float boxXmin=0,boxYmin=0;
[3]475
[581]476    char idents[3][80], opt[2], nlcprm[1];
[103]477
[581]478    strcpy(idents[0], wcs->lngtyp);
479    strcpy(idents[1], wcs->lattyp);
480    strcpy(idents[2], "");
481    if(strcmp(wcs->lngtyp,"RA")==0) opt[0] = 'G';
482    else opt[0] = 'D';
483    opt[1] = 'E';
[3]484
[581]485    float  blc[2], trc[2];
486    //   float  scl; // --> unused here.
487    blc[0] = boxXmin + 0.5;
488    blc[1] = boxYmin + 0.5;
489    trc[0] = boxXmin + axes[0]+0.5;
490    trc[1] = boxYmin + axes[1]+0.5;
[3]491 
[581]492    int existingLineWidth;
493    cpgqlw(&existingLineWidth);
494    int existingColour;
495    cpgqci(&existingColour);
496    float existingSize;
497    cpgqch(&existingSize);
498    cpgsci(textColour);
499    cpgsch(0.8);
500    int    c0[7], ci[7], gcode[2], ic, ierr;
501    for(int i=0;i<7;i++) c0[i] = -1;
502    /* define the WCS axes colour */
503    setWCSGreen();
[3]504
[581]505    gcode[0] = 2;  // type of grid to draw: 0=none, 1=ticks only, 2=full grid
506    gcode[1] = 2;
[3]507
[581]508    double cache[257][4], grid1[9], grid2[9], nldprm[8];
509    grid1[0] = 0.0; 
510    grid2[0] = 0.0;
[3]511
[581]512    // Draw the celestial grid with no intermediate tick marks.
513    // Set LABCTL=2100 to write 1st coord on top, and 2nd on right
[146]514
[581]515    //Colour indices used by cpgsbox: make it all the same colour for thin
516    // line case.
517    ci[0] = axisColour; // grid lines, coord 1
518    ci[1] = axisColour; // grid lines, coord 2
519    ci[2] = axisColour; // numeric labels, coord 1
520    ci[3] = axisColour; // numeric labels, coord 2
521    ci[4] = axisColour; // axis annotation, coord 1
522    ci[5] = axisColour; // axis annotation, coord 2
523    ci[6] = axisColour; // title
[3]524
[581]525    cpgsbox(blc, trc, idents, opt, 2100, 0, ci, gcode, 0.0, 0, grid1, 0, grid2,
526            0, pgwcsl_, 1, WCSLEN, 1, nlcprm, (int *)wcs,
527            nldprm, 256, &ic, cache, &ierr);
[3]528
[581]529    cpgsci(existingColour);
530    cpgsch(existingSize);
531    cpgslw(existingLineWidth);
532  }
[3]533
[581]534
535
[998]536  void drawSpectralRange(Plot::SpectralPlot &plot, Detection &obj, FitsHeader &head)
537  {
538    /// @details
539
540    /// A front-end to drawing the lines delimiting the spectral
541    /// extent of the detection. This takes into account the channel
542    /// widths, offsetting outwards by half a channel (for instance, a
543    /// single-channel detection will not have the separation of one
544    /// channel).
545    /// If the world coordinate is being plotted, the correct offset
546    /// is calcuated by transforming from the central spatial
547    /// positions and the offsetted min/max z-pixel extents
548
549    if(head.isWCS()){
550      double x=obj.getXcentre(),y=obj.getYcentre(),z;
551      z=obj.getZmin()-0.5;
552      float vmin=head.pixToVel(x,y,z);
553      z=obj.getZmax()+0.5;
554      float vmax=head.pixToVel(x,y,z);
555      plot.drawVelRange(vmin,vmax);
556    }
557    else{
558      plot.drawVelRange(obj.getZmin()-0.5,obj.getZmax()+0.5);
559    }
560
561
562  }
563
564  void drawSpectralRange(Plot::SimpleSpectralPlot &plot, Detection &obj, FitsHeader &head)
565  {
566    /// @details
567
568    /// A front-end to drawing the lines delimiting the spectral
569    /// extent of the detection. This takes into account the channel
570    /// widths, offsetting outwards by half a channel (for instance, a
571    /// single-channel detection will not have the separation of one
572    /// channel).
573    /// If the world coordinate is being plotted, the correct offset
574    /// is calcuated by transforming from the central spatial
575    /// positions and the offsetted min/max z-pixel extents
576
577    if(head.isWCS()){
578      double x=obj.getXcentre(),y=obj.getYcentre(),z;
579      z=obj.getZmin()-0.5;
580      float vmin=head.pixToVel(x,y,z);
581      z=obj.getZmax()+0.5;
582      float vmax=head.pixToVel(x,y,z);
583      plot.drawVelRange(vmin,vmax);
584    }
585    else{
586      plot.drawVelRange(obj.getZmin()-0.5,obj.getZmax()+0.5);
587    }
588
589  }
590
591
592
[378]593}
594
Note: See TracBrowser for help on using the repository browser.