Viewing contents of file '../idllib/contrib/buie/cw_osipl.pro'
;+
; NAME:
; cw_osipl
; PURPOSE:
; Display the various spectra generated by xdavg
; DESCRIPTION:
;
; This program takes spectra, badflags, and profiles and displays them via a
; multiple page format. Several spectra can be plotted at once by selecting
; the number of columns and rows to use to display the spectra. If profiles
; are provided then they are plotted alongside the spectra. A smoothing
; factor can also be applied to the spectra to reduce the effects of noise.
; The y-range of the plots can be specified by switching to the "fixed"
; option. The automatic y-range is a min-max range. The current page can
; also be printed out or all pages and the printer to which they go be
; specified
;
; CATEGORY:
; Compound widget
; CALLING SEQUENCE:
; cw_osipl,leader,type
; INPUTS:
; leader - the Id of the mainbase of the calling widget
; type - a flag indicating whether or not the the plot is called from the top
; or the bottom of the xdavg tool. Different defaults are implied by
; this for the number of rows and columns as well as the size cw_osipl
; OPTIONAL INPUT PARAMETERS:
; KEYWORD INPUT PARAMETERS:
; TITLE - Optional title of widget, default = 'OSIRIS XD PLOT'
; OUTPUTS:
; Spectra and profiles are plotted to the screen and can be printed
; KEYWORD OUTPUT PARAMETERS:
; COMMON BLOCKS:
; SIDE EFFECTS:
; RESTRICTIONS:
; PROCEDURE:
;
; This plot widget is used by creating it as a compound widget from within the
; calling program and recording its Id. Plots are then displayed by the
; program by setting its value to the following data structure in a
; widget_control statement:
;
; data={
;
; *Required information*
;
; nspecs: The number of spectra that need to be plotted
; calib: The calibration structure for the spectra
; pref: The index of the spectrum that is prefered to be displayed
; filenam: The filename of the spectrum, this added to the objname field
; is displayed as the title of the plot
; objname: The name of the object
; display: The array of spectra to be plotted
; badflag: The array of badflags to be plotted
; pflag: Flag indicating whether profiles are to be hidden
; cflag: Flag indicating whether a each order of the spetrum should be
; plotted in a different color
; pageflg: Flag to indicate that the plotter should only replot if the
; prefered spectrum is not on the current page
;
; *Optional information*
;
; (required if pflag is set)
; prof: The array of profiles values
; index: The indices for the profile points
; upbnd: The upper bound values for the sky level for the profiles
; lwbnd: The lower bound values for the sky level for the profiles
; relsig: The signal relative to the brightest spectrum in the set
; mate: The mate used in the extraction by xdspec
;
; airmass: The airmass for each spectrum
; juldate: The Julian date of the exposure
; exptime: The exposure time of the spectrum
; ncoads: The # of coadds used to make the spectrum
;
; } - UVALUE of state.mainbase
;
; MODIFICATION HISTORY:
; 98/06/12 - Written by Chris Dalla Piazza, Lycoming College
;-
;-------------------------------------------------------------------------------
; Procedure cw_osipl_display
;
; This procedure takes the selected page number, data, and plots them. It
; figures out what the bounds of the various windows are for multiple plots and
; sets defaults for things like the y-range, color table, and smoothing factor.
; The profiles are also plotted if they are requested.
;-------------------------------------------------------------------------------
pro cw_osipl_display,state,data,calib
; Make sure that the page number selected by the various user inputs does not
; exceed the total number of pages required to display the spectra
if state.page gt state.tot then state.page=state.tot
; Find the begining and end indices for the spectra on that page
idx=state.col*state.row*(state.page-1)
if idx+1 gt data.nspecs then idx=idx-state.col*state.row
en=idx+state.col*state.row
if en gt data.nspecs-1 then en=data.nspecs
en=en-1
; Figure out the various size parameters for the plots and the coordinates
; of the lower left and upper right corners for each plot.
i=idx-1
erase
; A little bit of space is required on all sides of the plots so labels do
; not clash. These are the insets
li=67.0/state.xsize ;left
ri=5.0/state.xsize ;right
ti=35.0/state.ysize ;top
bi=42.0/state.ysize ;bottom
; Insets for the profile plot windows
pli=30.0/state.xsize
pri=5.0/state.xsize
pbi=24.0/state.ysize
pti=5.0/state.ysize
; Set the values for the smoothing and color keywords
if state.smooth eq 1 then smooth=0 else smooth=state.smooth
if !d.name eq 'PS' then color=0 else if data.cflag then begin
tvlct,[0,255,0,0,255],[0,0,255,0,255],[0,0,0,255,255]
color=[1,2,3,1]
endif else color=!d.n_colors-1
; Cycle through the columns first and the rows second to produce the plots
; Changing the order of for loops here changes column, row order of plotting
; Changing the increment between +1 to -1 changes top to bottom, bottom to
; top order of plotting as well as right to left, left to right.
for k=state.row-1,0,-1 do begin
for j=0,state.col-1 do begin
if data.pflag eq 1 then begin
; These are the coordinates for the plot without profiles included
x0=float(j)/state.col+li
y0=float(k)/state.row+bi
x1=float(j+1)/state.col-ri
y1=float(k+1)/state.row-ti
endif else begin
; These are the coordinates for the plot with profiles
specxsize=0.75/state.col
profxsize=0.25/state.col
x0=float(j)/state.col+li
y0=float(k)/state.row+bi
x1=(j+1)*specxsize+j*profxsize-ri
y1=float(k+1)/state.row-ti
endelse
i=i+1
if i le en then begin
; set the y range for the plot, excluding badpoints and NaN's
yr=fltarr(2)
case state.scale OF
0: begin
z=where(data.badflag[*,i] eq 0 and $
finite(data.display[*,i]) eq 1,count)
if count ne 0 then begin
newdat=data.display[z,i]
newdat=newdat[sort(newdat)]
midpt=long(n_elements(newdat)/2)
lowpt=long(n_elements(newdat)*0.1)
hipt=long(n_elements(newdat)*0.9)
yr[0]= newdat[midpt] - (newdat[midpt]-newdat[lowpt])*5.5/4.0
yr[1]= newdat[midpt] + (newdat[hipt]-newdat[midpt])*5.5/4.0
endif else begin
yr=[0.,1.]
endelse
end
1: begin
z=where(data.badflag[*,i] eq 0 and $
finite(data.display[*,i]) eq 1,count)
if count ne 0 then begin
yr[0]=min(data.display[z,i])
yr[1]=max(data.display[z,i])
endif else begin
yr=[0.,1.]
endelse
end
2: begin
widget_control,state.scalelow,get_value=low
yr[0]=float(low)
widget_control,state.scalehi,get_value=hi
yr[1]=float(hi)
end
endcase
if state.scale eq 1 then begin
endif else begin
endelse
; Plot the spectrum
case state.smotype OF
0: begin
lowess=2
end
1: begin
lowess=0
end
endcase
plotspec,data.calib,data.display[*,i],BADFLAGS=data.badflag[*,i], $
title=data.filenam[i]+' '+data.objname[i],yr=yr,LOWESS=lowess, $
SMOOTH=smooth,position=[x0,y0,x1,y1],/noerase,COLOR=color, $
PSYM=state.psym*state.psymsign
; Plot the profiles if they have been requested
if data.pflag eq 0 then begin
; Find the coordinates of its plot window, it uses the same y
; dimensions as the spectrum plot
x0=(j+1)*specxsize+j*profxsize+pli
x1=float(j+1)/state.col-pri
tstring=string(data.mate[i],data.relsig[i], $
format='("mate:",i3.3,1x,"RelSig=",f4.2)')
; Plot the profiles and the bounds of the sky background
plot,data.index[*,i],data.prof[*,i],position=[x0,y0,x1,y1], $
/noerase,yr=[-1.0,1.0],xtitle='Row number', $
PSYM=state.psym*state.psymsign,title=tstring
oplot,data.index[*,i],data.lwbnd[*,i],linestyle=2
oplot,data.index[*,i],data.upbnd[*,i],linestyle=2
endif
endif
endfor ; column loop
endfor ; row loop
; Extra plot page annotation if this is a hardcopy.
if state.hard ne 0 then begin
jdstr,data.juldate[0],100,str
xyouts,0.98,0.02,str,align=1.0,/normal
endif
end
;-------------------------------------------------------------------------------
; Procedure cw_osipl_plot
;
; This procedure figures out what the format of the plot will be and handles
; printing options. It figures out how many pages are in the plot and which
; page to be on. It also sets up the required commands for printing out the
; plots. Sensitization of the paging buttons is also handled here
;-------------------------------------------------------------------------------
pro cw_osipl_plot,state
widget_control,state.mainbase,update=0
widget_control,state.mainbase,get_uvalue=data,/no_copy
; Figure out which page number the prefered spectrum is on
if data.pref eq 0 then begin
data.pref=where(data.filenam eq state.prefnam)+1
if data.pref eq 0 then data.pref=1
endif
; IF the plotter is to only update the plot if the prefered spectrum is not on
; the page and the page isn't different then just drop everything and stop
oldpage=state.page
state.page=ceil(float(data.pref)/float(state.col*state.row))
if data.pageflg eq 1 and oldpage eq state.page then begin
data.pageflg=0
data.pref=(state.page-1)*state.col*state.row
state.prefnam=data.filenam[data.pref]
data.pref=0
widget_control,state.mainbase,set_uvalue=data,/no_copy
widget_control,state.mainbase,update=1
return
endif
; Set the device to printer if a hardcopy is needed
if state.hard gt 0 then begin
mydevice=!D.NAME
set_plot,'ps'
cd,'.',current=dir
dir=dir+'/'
if state.row gt state.col then begin
setpage,/portrait
endif else begin
setpage,/landscape
endelse
endif else begin
;Direct graphics to the draw widget.
windo = !d.window
WIDGET_CONTROL, state.plotid, GET_VALUE=dwin
wset, dwin
endelse
; Figure out the page number and page format
state.tot=ceil(float(data.nspecs)/float(state.col*state.row))
if state.hard eq 2 then begin
store=state.page
for page=1,state.tot do begin
state.page=page
cw_osipl_display,state,data,data.calib
endfor
state.page=store
endif else begin
cw_osipl_display,state,data,data.calib
endelse
; Print the hardcopy and reset the printing flag
if state.hard gt 0 then begin
device,/close
if state.printer eq '' then begin
spawn,'lp idl.ps'
endif else begin
spawn,'lp -d '+state.printer+' idl.ps'
endelse
set_plot,mydevice
state.hard=0
endif else begin
;Reset the draw window.
wset, windo
endelse
; Sensitize the paging buttons
if state.page eq state.tot then begin
widget_control,state.butforw,sensitive=0
endif else begin
widget_control,state.butforw,sensitive=1
endelse
if state.page eq 1 then begin
widget_control,state.butback,sensitive=0
endif else begin
widget_control,state.butback,sensitive=1
endelse
; Find the name of the new prefered spectrum
data.pref=(state.page-1)*state.col*state.row
state.prefnam=data.filenam[data.pref]
data.pref=0
widget_control,state.lblhere,set_value=strcompress(state.page)
widget_control,state.lbltot,set_value=strcompress(state.tot)
widget_control,state.mainbase,set_uvalue=data,/no_copy
widget_control,state.mainbase,update=1
end
;-------------------------------------------------------------------------------
; Procedure cw_osipl_svl
;
; This is the procedure to be followed when the plot widget's value is set.
; This essentially consists of running the plot procedure just as if an event
; had been generated.
;-------------------------------------------------------------------------------
pro cw_osipl_svl,id,data
stash=widget_info(id,/CHILD)
widget_control,stash,get_uvalue=state,/no_copy
widget_control,state.mainbase,set_uvalue=data,/no_copy
cw_osipl_plot,state
widget_control,stash,set_uvalue=state,/no_copy
end
;-------------------------------------------------------------------------------
; Procedure cw_osipl_eve
;
; Event handler for the cw_osipl widget
;-------------------------------------------------------------------------------
pro cw_osipl_eve,event
WIDGET_CONTROL, event.id, /HOURGLASS
stash = WIDGET_INFO( event.handler, /CHILD )
WIDGET_CONTROL, stash, GET_UVALUE=state, /NO_COPY
case event.id of
state.mainbase: begin
; Get the size of the widget holding the options and subtract it off of
; the size of the mainbase, then set the size of the plot window to this
; and refresh the plot
baseinfo=widget_info(state.baseid,/geometry)
state.xsize=event.x
state.ysize=event.y-baseinfo.ysize
widget_control,state.plotid,xsize=state.xsize,ysize=state.ysize
cw_osipl_plot,state
end
state.butcol: begin
state.col=event.index+1
cw_osipl_plot,state
end
state.butrow: begin
state.row=event.index+1
cw_osipl_plot,state
end
state.butforw: begin
; Increase the value of the current page number by one and replot
widget_control,state.lblhere,get_value=value
widget_control,state.lblhere,set_value=strcompress(value+1)
widget_control,state.mainbase,get_uvalue=data,/no_copy
state.prefnam=data.filenam[(value)*state.row*state.col]
widget_control,state.mainbase,set_uvalue=data,/no_copy
cw_osipl_plot,state
end
state.butback: begin
; Decrease the value of the current page number by one and replot
widget_control,state.lblhere,get_value=value
widget_control,state.lblhere,set_value=strcompress(value-1)
widget_control,state.mainbase,get_uvalue=data,/no_copy
state.prefnam=data.filenam[(value-2)*state.row*state.col]
widget_control,state.mainbase,set_uvalue=data,/no_copy
cw_osipl_plot,state
end
state.psymid: begin
state.psym=event.index
cw_osipl_plot,state
end
state.psymsignid: begin
if event.index eq 0 then $
state.psymsign = -1 $
else $
state.psymsign = 1
cw_osipl_plot,state
end
state.smoothid: begin
state.smooth=event.value
cw_osipl_plot,state
end
state.smotypeid: begin
state.smotype=event.index
cw_osipl_plot,state
end
state.butscale: begin
state.scale=event.index
case event.index OF
; Auto scaling
0: begin
; Desensitize the min-max text widgets
widget_control,state.scalelow,sensitive=0
widget_control,state.scalehi,sensitive=0
end
; Min/max scaling
1: begin
; Desensitize the min-max text widgets
widget_control,state.scalelow,sensitive=0
widget_control,state.scalehi,sensitive=0
end
; Fixed scaling
2: begin
; Set the value of the min-max to be the min-max of the first
; spectrum in the set as a default value
widget_control,state.mainbase,get_uvalue=data,/no_copy
z=where(data.badflag[*,0] eq 0 and $
finite(data.display[*,0]) eq 1,count)
if count ne 0 then begin
newdat=data.display[z,0]
newdat=newdat[sort(newdat)]
midpt=long(n_elements(newdat)/2)
lowpt=long(n_elements(newdat)*0.1)
hipt=long(n_elements(newdat)*0.9)
lowval = 0.0
hival = newdat[midpt] + (newdat[hipt]-newdat[midpt])*5.5/4.0
endif else begin
lowval = 0.
hival = 0.
endelse
widget_control,state.scalelow,set_value= $
strcompress(string(lowval,format='(g8.2)'),/remove_all)
widget_control,state.scalehi,set_value= $
strcompress(string(hival,format='(g8.2)'),/remove_all)
widget_control,state.mainbase,set_uvalue=data,/no_copy
widget_control,state.scalelow,sensitive=1
widget_control,state.scalehi,sensitive=1
end
else: begin
print,'CW_OSIPL: Warning! Illegal scaling index.'
end
endcase
cw_osipl_plot,state
end
state.scalelow: begin
cw_osipl_plot,state
end
state.scalehi: begin
cw_osipl_plot,state
end
state.butphard: begin
state.hard=1
cw_osipl_plot,state
end
state.butahard: begin
state.hard=2
cw_osipl_plot,state
end
state.printid: begin
; Get the new printer and make sure that it is a valid printer
widget_control,state.printid,get_value=printer
printer=strcompress(printer)
spawn,'lpq -P '+printer[0],result
if result[0] eq '' then begin
print,'Invalid printer. Keeping old setting.'
widget_control,state.printid,set_value=state.printer
endif else begin
state.printer=printer[0]
endelse
end
ELSE : BEGIN
MESSAGE, 'Unknown event:', /INFO
HELP, event, /STRUCTURE
END
endcase
WIDGET_CONTROL, stash, SET_UVALUE=state, /NO_COPY
end
;-------------------------------------------------------------------------------
; Function cw_osipl
;
; This Function returns the Id of the mainbase and creates the layout of the
; widget
;-------------------------------------------------------------------------------
function cw_osipl,leader,type,TITLE=title
if badpar(title,[0,7],0,caller='CW_OSIPL: (TITLE) ', $
default='OSIRIS XD PLOT') then begin
help,title
title='OSIRIS XD PLOT'
print,'CW_OSIPL: Warning, illegal TITLE value provided, using default.'
endif
; Set the default size and number of rows depending on the type of plot
if type eq 0 then begin
xsize=740
ysize=600
row=4
endif else begin
xsize=730
ysize=300
row=1
endelse
setusym,1
; Define the state structure
state={mainbase: 0L, $ ; Id of the mainbase
; labelid: 0L, $ ; Id of the widget bas holding the user options widgets
plotid: 0L, $ ; Id of the plot widget
baseid: 0L, $ ; Id of base holding all of the widgets
xsize: xsize, $ ; The current width of the widget
ysize: ysize, $ ; The current height of the widget
prefnam: '', $ ; The spectrum name of the last prefered spectrum
hard: 0, $ ; The flag indicating the which kind of print is
; requested: 0 - indicates no print, 1 - indicates print
; just that page, 2 - indicates print all pages
col: 1, $ ; The current number of columns to plot spectra in
row: row, $ ; The current number of rows to plot spectra in
scale: 0, $ ; Flag indicating whether auto or fixed scaling is to be
; used for the y-range of the plot
page: 1, $ ; The current page number selected
tot: 1, $ ; The total number of pages
printer: '', $ ; The name of the printer to use
smooth: 1, $ ; The smoothing scale to use
psym: 0, $ ; Plot symbol to use.
psymsign: -1, $ ; Positive: just symbols, negative: connect the dots.
smotype: 0, $ ; Smoothing type to use on plots.
smoothid: 0L, $ ; Id of the smoothing slider
psymid: 0L, $ ; Id of the plot symbol droplist
psymsignid: 0L, $ ; Id of the plot line droplist
smotypeid: 0L, $ ; Id of the smoothing type widget
printid: 0L, $ ; Id of the printer text
scalelow: 0L, $ ; Id of the min text
scalehi: 0L, $ ; Id of the max text
butrow: 0L, $ ; Id of the row droplist
butcol: 0L, $ ; Id of the col droplist
butback: 0L, $ ; Id of the prev page button
butscale: 0L, $ ; Id of the scaling selection button group
butphard: 0L, $ ; Id of the one page printing button
butahard: 0L, $ ; Id of the all pages printing button
lblhere: 0L, $ ; Id of the currently selected page label
lbltot: 0L, $ ; Id of the total # of pages label
butforw: 0L} ; Id of the next page button
; Define the main base
mainbase=WIDGET_BASE(TITLE=title, EVENT_PRO='cw_osipl_eve', $
PRO_SET_VALUE='cw_osipl_svl',/COLUMN,/TLB_SIZE_EVENTS, $
GROUP_LEADER=leader)
state.baseid=WIDGET_BASE(mainbase,/column,/FRAME)
b2=state.baseid
; Top part of the widget that contains the user options
b=widget_base(b2,/row)
c=widget_base(b,/column,/frame)
state.butrow=WIDGET_DROPLIST(c,TITLE=' Rows ',VALUE=['1','2','3','4','5','6', $
'7','8','9','10','11','12','13','14','15','16','17','18','19','20'], $
UVALUE=1)
widget_control,state.butrow,set_droplist_select=row-1
; state.labelid=WIDGET_LABEL(b,VALUE='by')
state.butcol=WIDGET_DROPLIST(c,TITLE='Columns',VALUE=['1','2','3','4','5'], $
UVALUE=1)
c=widget_base(b,/column,/frame)
cc=widget_base(c,/row)
state.butback=WIDGET_BUTTON(c,VALUE='Prev Page')
state.butforw=WIDGET_BUTTON(c,VALUE='Next Page')
b1=WIDGET_LABEL(cc,VALUE='Page')
state.lblhere=WIDGET_LABEL(cc,VALUE='1',/DYNAMIC_RESIZE)
b1=WIDGET_LABEL(cc,VALUE='of')
state.lbltot=WIDGET_LABEL(cc,VALUE='1',/DYNAMIC_RESIZE)
c=widget_base(b,/column,/frame)
state.smoothid=widget_slider(c,minimum=1,maximum=10,TITLE='Smoothing Factor')
state.smotypeid=widget_droplist(c,TITLE='', $
VALUE=['Lowess','Boxcar'])
c=widget_base(b,/column,/frame)
c=widget_base(b,/column,/frame)
state.butphard=WIDGET_BUTTON(c,VALUE='Page Hardcopy')
state.butahard=WIDGET_BUTTON(c,VALUE='All Hardcopy')
cc=widget_base(c,/row)
b1=widget_label(cc,value='Printer:')
state.printid=widget_text(cc,value='',/editable,xsize=4)
b=widget_base(b2,/row)
; state.butscale=CW_BGROUP(b,['Auto Scaling','Fixed Scaling'],/no_release, $
; /frame,/exclusive,row=1,set_value=0)
state.butscale=WIDGET_DROPLIST(b,TITLE='', $
VALUE=['Auto Scaling','Min/max Scaling','Fixed Scaling'])
b1=WIDGET_LABEL(b,value='Ymin:')
state.scalelow=widget_text(b,value='',/editable,xsize=8)
b1=widget_label(b,value='Ymax:')
state.scalehi=widget_text(b,value='',/editable,xsize=8)
state.psymid=WIDGET_DROPLIST(b, $
VALUE=['No Sym','Plus','Asterisk','Dot','Diamond', $
'Triangle','Square','X','Circle'])
state.psymsignid=WIDGET_DROPLIST(b,VALUE=['Lines','No Lines'])
; Bottom part of the widget that is the plotting window
state.plotid=WIDGET_DRAW(mainbase,xsize=state.xsize,ysize=state.ysize)
state.mainbase=mainbase
widget_control,state.scalelow,sensitive=0
widget_control,state.scalehi,sensitive=0
stash=WIDGET_INFO(mainbase,/CHILD)
WIDGET_CONTROL,stash,SET_UVALUE=state,/NO_COPY
WIDGET_CONTROL,mainbase,/REALIZE,/MAP
return,mainbase
end