;+ ; 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 Widgets ; 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