; docformat = 'rst' ; ; NAME: ; plotVNIR ; PURPOSE: ; Create graphics of V+NIR spectra, with multiple options ;+ ; :Description: ; Create graphics of V+NIR spectra, with multiple options ; ; :Categories: ; Figure ; ; :Params: ; root: in, required, type=string ; The path where files are stored ; list: in, required, type=string ; The root name of the target list ([list].list) and options ([list].ini) ; ; :Params: ; config: in, optional, type=string ; The path to a configuration file ; ; :Examples: ; ; :Uses: ; readBusDeMeo, plotVNIR_load, plotVNIR_read, Coyote Graphic System ; ; :Author: ; B.Carry (OCA) ; ; :History: ; Change History:: ; Original Version written in 2017, B. Carry (OCA) ; 2018 Mar - B. Carry (OCA) - Added config keyword ;- pro plotVNIR, root, list, config=config compile_opt hidden, idl2 ;-----------------------------------------------------------------------------------------------; ;-----------------------------------------------------------------------------------------------; ;--- TAG --- I -- Initialization And Input Verification -----------------------; ;-----------------------------------------------------------------------------------------------; ;-----------------------------------------------------------------------------------------------; ;--I.1-- Check Input Syntax ------------------------------------------------------------------; if not keyword_set(root) then begin message, /ioError, 'Syntax: plotVNIR, root [, list]' return endif ;--I.2-- Check Root Directory and File List --------------------------------------------------; if not keyword_set(list) then list='sso' if not file_test(root,/Directory) then begin message, 'The root directory does not exist: '+strTrim(root,2) return endif ;--I.3-- Directory Tree ----------------------------------------------------------------------; dirDATA = root+'data/' dirCONF = root+'conf/' ;--I.4-- Load Bus-DeMeo Taxonomy Spectra -----------------------------------------------------; bdm = readBusDeMeo() ;--I.5-- Load the List of Targets ------------------------------------------------------------; readcol, root+list+'.list', format='(A)', /Silent, sso nbSSO = n_elements( sso ) ;--I.6-- Load the Figure Parameters ----------------------------------------------------------; ;--I.6.1-- Defaut Configuration codePATH = routine_filepath( 'plotvnir' ) defIni = strMid( codePATH, 0, strlen(codePATH)-3)+'ini' confDefault = plotVNIR_load(defIni) ;--I.6.2-- Local Configuration if keyword_set(config) then begin if file_test( config, /read) then begin addConf = plotVNIR_load( config ) confDefault = updateStructure( confDefault, addConf ) endif endif ;--I.6.3-- Additional Configuration with the List of Target if file_test( root+list+'.ini', /read) then begin conf = plotVNIR_load( root+list+'.ini' ) conf = updateStructure( confDefault, conf ) endif else conf=confDefault nbAtm = n_elements( conf.atm ) ;--- to be moved ;-- normalization: std VIS or NIR **OR** manual normVIS = [0.47, 0.53] normNIR = [1.22,1.28] normSDSS_Z = [0.835, 0.950 ] ;-----------------------------------------------------------------------------------------------; ;-----------------------------------------------------------------------------------------------; ;--- TAG --- II -- Definition of Graphics Output Parameters -----------------------; ;-----------------------------------------------------------------------------------------------; ;-----------------------------------------------------------------------------------------------; ;--II.1-- Save Current Device Status --------------------------------------------------------- SetDecomposedState, 1, CurrentState=theState thisDevice = !D.Name ;--II.2-- Layout Parameters for Figures ------------------------------------------------------ ;--II.2.1-- Figure Size winPS= [ conf.graph.size.x, conf.graph.size.y] ;--II.2.2-- Plot Positions & CharSize if conf.graph.n.rows*conf.graph.n.cols le 12 then begin xBot = 2500. ;-- Left Margin yBot = 2000 ;-- Bottom Margin xLength = 24000. ;-- Plot X Size yLength = 12000. ;-- Plot Y Size xTop = 600. ;-- Right Margin yTop = 400. ;-- Top Margin xSep = 0 ;-- Plot-to-plot X Separation ySep = 0 ;-- Plot-to-plot Y Separation cSizeTitle = 2.0 ;-Title cSizeAxes = 1.0 ;-Axes notations cSizeSSO = 2.5 ;-Plot title cSizeSpec = 1.5 ;-Spectral label cSizeClass = 2.0 ;-Taxonomic class cSizeChi2 = 2.0 ;-Chi2 on taxonomy thickAxe = 1 ;-Thickness of axes thickBDM = 1 ;-Thickness of Bus-DeMeo symSize = 1 endif else begin xBot = 3000. ;-- Left Margin yBot = 2500 ;-- Bottom Margin xLength = 24000. ;-- Plot X Size yLength = 12000. ;-- Plot Y Size xTop = 600. ;-- Right Margin yTop = 400. ;-- Top Margin xSep = 0 ;-- Plot-to-plot X Separation ySep = 0 ;-- Plot-to-plot Y Separation cSizeTitle = 2.5 ;-Title cSizeAxes = 2.5 ;-Axes notations cSizeSSO = 2.5 ;-Plot title cSizeSpec = 2.5 ;-Spectral label cSizeClass = 2.5 ;-Taxonomic class cSizeChi2 = 2.5 ;-Chi2 on taxonomy thickAxe = 3 ;-Thickness of axes thickBDM = 3 ;-Thickness of Bus-DeMeo symSize = 2 endelse ;--II.2.3-- Plot Characteristics ;--II.2.3/A-- Axes: Time/Phase and Flux xRang = conf.axes.range.x yRang = conf.axes.range.y ;--II.2.3/B-- Tick Intervals nbTickX = (xRang[1]-xRang[0])/conf.axes.tick.x+1 nbTickY = (yRang[1]-yRang[0])/conf.axes.tick.y+1 ;--II.3-- Start Loop over Figure Files ------------------------------------------------------- nbWin = ceil(nbSSO / float(conf.graph.n.rows*conf.graph.n.cols)) winInd = indgen(nbWin)+1 nbPlotted = 0 for kSSO=0, nbSSO-1 do begin ;--II.4-- Open and Set Up a New File ------------------------------------------------------- if (float(kSSO-nbPlotted) mod (conf.graph.n.rows*conf.graph.n.cols)) eq 0 or $ kSSO eq 0 then begin ;--II.4.1-- Close Former Plot if kSSO gt 0 then cgPS_close, /png, Delete_PS=0 ;--II.4.2-- Keep Track of Number of Plotted SSOs, Columns and Rows nbPlotted = kSSO kWin = kSSO/(conf.graph.n.rows*conf.graph.n.cols) trialRow = ceil( (nbSSO-kSSO) / conf.graph.n.cols)+1 trialCol = ceil( (nbSSO-kSSO) mod conf.graph.n.cols) if trialCol eq 0 then trialRow-- if trialRow lt conf.graph.n.rows then conf.graph.n.rows=trialRow if conf.graph.n.rows eq 1 then begin if trialCol lt conf.graph.n.cols and trialCol ne 0 then conf.graph.n.cols=trialCol endif ;--II.4.3-- Adapt the Figure Size winPS[0] = ( xBot + xTop + conf.graph.n.cols*xLength + (conf.graph.n.cols-1)*xSep )/1000. winPS[1] = ( yBot + yTop + conf.graph.n.rows*yLength + (conf.graph.n.rows-1)*ySep )/1000. ;--II.4.4-- Define EPS Device cgPS_open, Filename=root+list+'-'+string(winInd[kWin],format='(I03)')+'.eps', $ /metric, /decomposed, /portrait, /color, $ xsize=winPS[0], ysize=winPS[1], language_level=2, /quiet ;--II.4.5-- Photometry & Rotation Labels cgText, winPS[0]*500., 250, 'Wavelength ('+cgGreek('mu')+'m)', align=0.5, /Device, charSize=cSizeTitle cgText, 750, winPS[1]*500., 'Spectral reflectance', align=0.5, /Device, orient=90, charSize=cSizeTitle endif ;--II.5-- Define Axes ------------------------------------------------------------ kCol = ((kSSO-nbPlotted) mod (conf.graph.n.rows*conf.graph.n.cols)) mod conf.graph.n.cols kRow = ((kSSO-nbPlotted) mod (conf.graph.n.rows*conf.graph.n.cols)) / conf.graph.n.cols ;--II.6-- Define the Plot Environment ------------------------------------------------------ tickNameX = replicate(' ' ,nbTickX) tickNameY = replicate(' ' ,nbTickY) posArr = [xBot + kCol*(xLength+xSep), $ yBot + (conf.graph.n.rows-1-kRow)*(yLength+ySep), $ xBot + kCol*(xLength+xSep) + xLength, $ yBot + (conf.graph.n.rows-1-kRow)*(yLength+ySep) + yLength ] cgPlot, [0],[0], /NoData, /Device, /NoErase, $ xStyle=1, xRange=xRang, xTickInterval=conf.axes.tick.x, xMinor=conf.axes.minor.x, xTickname=tickNameX, $ yStyle=1, yRange=yRang, yTickInterval=conf.axes.tick.y, yMinor=conf.axes.minor.y, yTickname=tickNameY, $ position=posArr, charSize=cSizeAxes, xthick=thickAxe, yThick=thickAxe if (float(kSSO) mod conf.graph.n.cols) eq 0 then $ cgAxis, yAxis=0, yRange=yRang, yStyle=1, yTickInterval=conf.axes.tick.y, yMinor=conf.axes.minor.y, charSize=cSizeAxes if floor(float(kSSO-nbPlotted)/conf.graph.n.cols)+1 eq conf.graph.n.rows or $ kSSO ge nbSSO-conf.graph.n.cols then $ cgAxis, xAxis=0, xRange=xRang, xStyle=1, xTickInterval=conf.axes.tick.x, xMinor=conf.axes.minor.x, charSize=cSizeAxes ;-----------------------------------------------------------------------------------------------; ;-----------------------------------------------------------------------------------------------; ;--- TAG --- II -- Read Datasets: Spectra, and Photometry -----------------------; ;-----------------------------------------------------------------------------------------------; ;-----------------------------------------------------------------------------------------------; ;--II.1-- Read Current SSO Configuration File ----------------------------------------------; ssoConf = plotVNIR_read( dirCONF+sso[kSSO]+'.ini' ) nbSpec = n_elements( ssoConf.spec ) nbClass = n_elements( ssoConf.class ) if nbClass eq 1 then if size(ssoConf.class,/Type) ne 8 then nbClass=0 ;--II.2-- Read Spectral Data ---------------------------------------------------------------; spectrum=replicate({wave:ptr_new(), refl:ptr_new(), unc:ptr_new()}, nbSpec) for kSpec=0, nbSpec-1 do begin ;--II.2.1-- Read Spectral File case strLowCase(ssoConf.spec[kSpec].fmt) of ;--II.2.1/A -- ASCII File 'ascii': begin readcol, dirDATA+ssoConf.spec[kSpec].data, w,r,u, format='(F,F,F)',/Silent if not keyword_Set(w) then begin readcol, dirDATA+ssoConf.spec[kSpec].data, w,r, format='(F,F)',/Silent u=r*0. endif end ;--II.2.1/B -- CSV File 'csv': begin readcol, dirDATA+ssoConf.spec[kSpec].data, w,r,u, format='(F,F,F)',/Silent, delimiter=',' if not keyword_Set(w) then begin readcol, dirDATA+ssoConf.spec[kSpec].data, w,r, format='(F,F)',/Silent, delimiter=',' u=r*0. endif end endcase ;--II.2.2-- Clean Potential Stupid Values valid =where( r gt 0 ) ;--II.2.3-- Store Spectra in Structure spectrum[kSpec].wave = ptr_new(/Allocate_Heap) spectrum[kSpec].refl = ptr_new(/Allocate_Heap) spectrum[kSpec].unc = ptr_new(/Allocate_Heap) *spectrum[kSpec].wave = w[valid] *spectrum[kSpec].refl = r[valid] *spectrum[kSpec].unc = u[valid] undefine, w, r, u ;--II.2.4-- Normalize Spectra waveN = where( *spectrum[kSpec].wave ge normNIR[0] and *spectrum[kSpec].wave le normNIR[1] ) *spectrum[kSpec].refl /= mean( (*spectrum[kSpec].refl)[waveN] ) endfor ;--II.3-- Read SDSS Data -------------------------------------------------------------------; if ssoConf.sdss.yn eq 1 then begin readcol, dirDATA+ssoConf.sdss.data, w,r,u, format='(F,F,F)', /Silent sdss={wave:w, refl:r, unc:u} waveZ = where( *spectrum[0].wave ge normSDSS_Z[0] and *spectrum[0].wave le normSDSS_Z[1] ) sdss.refl *= (mean( (*spectrum[0].refl)[waveZ] )/sdss.refl[4]) endif ;-----------------------------------------------------------------------------------------------; ;-----------------------------------------------------------------------------------------------; ;--- TAG --- III -- Plot Observations, Classes, ... -----------------------; ;-----------------------------------------------------------------------------------------------; ;-----------------------------------------------------------------------------------------------; ;--III.1-- Plot Atmospheric Bands ----------------------------------------------------------; for kA=0, nbAtm-1 do begin if conf.atm[kA].show eq 1 then begin cgColorFill, [conf.atm[kA].min,conf.atm[kA].max,conf.atm[kA].max,conf.atm[kA].min], $ [yRang[0],yRang[0],yRang[1],yRang[1]], color='Light gray' endif endfor ;--III.2-- Plot Spectral Data --------------------------------------------------------------; for kSpec=0, nbSpec-1 do begin ;--III.2.1-- Plot Spectrum and Uncertainties cgErrPlot, *spectrum[kSpec].wave, $ ssoConf.spec[kSpec].offset.val + *spectrum[kSpec].refl-*spectrum[kSpec].unc, $ ssoConf.spec[kSpec].offset.val + *spectrum[kSpec].refl+*spectrum[kSpec].unc, color=ssoConf.spec[kSpec].color cgPlot, /OverPlot, *spectrum[kSpec].wave, ssoConf.spec[kSpec].offset.val + *spectrum[kSpec].refl, $ psym=ssoConf.spec[kSpec].symbol, color=ssoConf.spec[kSpec].color, symSize=symSize cgPlot, /OverPlot, *spectrum[kSpec].wave, ssoConf.spec[kSpec].offset.val + *spectrum[kSpec].refl, color=ssoConf.spec[kSpec].color if ssoConf.spec[kSpec].offset.show eq 1 and ssoConf.spec[kSpec].offset.val ne 0 then begin cgText, max( *spectrum[kSpec].wave, pMax )+0.05, ssoConf.spec[kSpec].offset.val + (*spectrum[kSpec].refl)[pMax], $ strTrim(string(ssoConf.spec[kSpec].offset.val,format='(F+5.2)'),2), color=ssoConf.spec[kSpec].color endif ;--III.2.1/A-- Legend Coordinates xRef = conf.legend.spec.x*(xRang[1]-xRang[0]) + xRang[0] yRef = conf.legend.spec.y*(yRang[1]-yRang[0]) + yRang[0] xShi = conf.legend.spec.shift.x*(xRang[1]-xRang[0]) yShi = conf.legend.spec.shift.y*(yRang[1]-yRang[0]) xVec = conf.legend.spec.vec.x*(xRang[1]-xRang[0]) case ssoConf.label of '(348400) 2005 JF21': begin yRef = 0.7*(yRang[1]-yRang[0]) + yRang[0] end '(2691) Sersic': begin xRef = 0.65*(xRang[1]-xRang[0]) + xRang[0] end else: endcase ;--III.2.1/B-- Spectrum Line cgPlot, /OverPlot, xRef-xVec, yRef+yShi*(kSpec+1) + [1,1]*0.020, color=ssoConf.spec[kSpec].color cgPlot, /OverPlot, mean(xRef-xVec), mean(yRef+yShi*(kSpec+1) + [1,1]*0.020), $ color=ssoConf.spec[kSpec].color, psym=ssoConf.spec[kSpec].symbol, symSize=symSize ;--III.2.1/C-- Spectrum Label cgText, xRef, yRef+yShi*(kSpec+1), ssoConf.spec[kSpec].label, charSize=cSizeSpec endfor ;--III.3-- Plot SDSS Data ------------------------------------------------------------------; if ssoConf.sdss.yn eq 1 then begin ;--III.3.1-- cgErrPlot, sdss.wave, sdss.refl-sdss.unc, sdss.refl+sdss.unc, psym=3 cgPlot, /OverPlot, sdss.wave, sdss.refl, psym='Open Circle', color='Dark Gray' ; ;--III.3.2-- Add Class to Legend ; ;--III.3.2/A-- Legend Coordinates ; xRef = conf.legend.class.x*(xRang[1]-xRang[0]) + xRang[0] ; yRef = conf.legend.class.y*(yRang[1]-yRang[0]) + yRang[0] ; xShi = conf.legend.class.shift.x*(xRang[1]-xRang[0]) ; yShi = conf.legend.class.shift.y*(yRang[1]-yRang[0]) ; xVec = conf.legend.class.vec.x*(xRang[1]-xRang[0]) ; ; ;--III.3.2/B-- Class Line ; cgPlot, /OverPlot, xRef-xVec, yRef+yShi*(kC+1) + [1,1]*0.035, $ ; color=bdm.class[pT].color, lineStyle=bdm.class[pT].style, thick=bdm.class[pT].thick ; ; ;--III.3.2/C-- Class Label ; cgText, xRef, yRef+yShi*(kC+1), ssoConf.class[kC].label, charSize=2.0 endif ;--III.4-- Display Legend ------------------------------------------------------------------; if conf.legend.show eq 1 then begin ;--III.4.1-- SSO Label cgText, conf.legend.label.x*(xRang[1]-xRang[0]) + xRang[0], $ conf.legend.label.y*(yRang[1]-yRang[0]) + yRang[0], $ ssoConf.label, charSize=cSizeSSO, /Data endif ;--III.5-- Plot Taxonomic Classes ----------------------------------------------------------; for kC=0, nbClass-1 do begin ;--III.5.1-- Identify Bus-DeMeo Class pT = where( strCmp(ssoConf.class[kC].label,bdm.class.name) ) spec = bdm.class[pT].spec ;--III.5.2-- Normalize Spectrum bdmWNorm = where( bdm.wave ge normNIR[0] and bdm.wave le normNIR[1] ) spec /= mean( spec[bdmWNorm] ) ;--III.5.3-- Plot Bus-DeMeo Spectrum cgPlot, /OverPlot, bdm.wave, spec, $ color=bdm.class[pT].color, lineStyle=bdm.class[pT].style, thick=bdm.class[pT].thick*thickBDM ;--III.5.4-- Add Class to Legend ;--III.5.4/A-- Legend Coordinates xRef = conf.legend.class.x*(xRang[1]-xRang[0]) + xRang[0] yRef = conf.legend.class.y*(yRang[1]-yRang[0]) + yRang[0] xShi = conf.legend.class.shift.x*(xRang[1]-xRang[0]) yShi = conf.legend.class.shift.y*(yRang[1]-yRang[0]) xVec = conf.legend.class.vec.x*(xRang[1]-xRang[0]) case ssoConf.label of '(2691) Sersic': begin xRef = 0.3*(xRang[1]-xRang[0]) + xRang[0] end else: endcase ;--III.5.4/B-- Class Line cgPlot, /OverPlot, xRef-xVec, yRef+yShi*(kC+1) + [1,1]*0.020, $ color=bdm.class[pT].color, lineStyle=bdm.class[pT].style, thick=bdm.class[pT].thick*thickBDM ;--III.5.4/C-- Class Label cgText, xRef, yRef+yShi*(kC+1), ssoConf.class[kC].label, charSize=cSizeClass ;--III.5.4/D-- Class Chi-Square if ssoConf.class[kC].chi2 ne 0 then $ cgText, xRef+xShi, yRef+yShi*(kC+1), string(ssoConf.class[kC].chi2,format='(F5.3)'), $ charSize=cSizeChi2, align=1 endfor cgPlot, [0],[0], /NoData, /Device, /NoErase, position=posArr, $ xStyle=1, xRange=xRang, xTickInterval=conf.axes.tick.x, xMinor=conf.axes.minor.x, xTickname=tickNameX, $ yStyle=1, yRange=yRang, yTickInterval=conf.axes.tick.y, yMinor=conf.axes.minor.y, yTickname=tickNameY, $ charSize=cSizeAxes, xthick=thickAxe, yThick=thickAxe endfor cgPS_close, /png, Delete_PS=0 end