;------------------------------------------------------------- ;+ ; NAME: ; EXPLORE ; ; PURPOSE: ; interactive data explorer. Somewhat similar to PROC INSIGHT ; from the SAS system although not that powerful. ; ; CATEGORY: ; widget based main program ; ; CALLING SEQUENCE: ; EXPLORE [,keywords] ; ; INPUTS: ; FILENAME --> (try to) read in data from this file immediately. ; You may need to specify the SKP1, SKP2, AUTOSKIP and DELIM ; keyword parameters. ; ; KEYWORD PARAMETERS: ; DELIM, SKP1, SKP2, AUTOSKIP --> specify the structure of the file ; header. For details see READDATA.PRO. ; ; DATA --> allows you to start with a data array that has already ; been loaded. Must supply HEADER in this case as well. ; ; HEADER --> the corresponding variable names ; ; COMMENTS --> an optional comment array from a file that has ; been read previously. Note: could be somewhat messed up ; if you try to edit the comments and save them to a new file. ; ; /BW -> produces only black and white plots ; ; SYMSIZE -> set defaul tsymbol size (default=0.8) ; ; OUTPUTS: ; Nice plots and optional postscript files :-) ; ; SUBROUTINES: ; several ; ; REQUIREMENTS: ; currently set-up to run under X. Should now only be a matter ; of adapting the OPEN_DEVICE and CLOSE_DEVICE routines. ; ; NOTES: ; For the development of this tool it is especially important ; to report all errors that are reproducible and true programming ; errors to the author. Any suggestions or add-ins are welcome, ; however, my time for development of new code is very limited. ; ; EXAMPLE: ; explore - and off you go. ; ; MODIFICATION HISTORY: ; mgs, 28 Aug 1997: VERSION 1.10 ; - first stable release ; mgs, 01 Dec 1997: VERSION 1.20 ; - improved file dialogs ; - some minor bug fixes ; mgs, 23 Dec 1997: ; - found bug that caused selection to be doubled if points ; are hidden; now more robust using the ind_comb function ; - Info function now more robust, formatting error for ; selected value output removed ; - changed rubberband mechanism to device,copy=[...] as ; suggested by D. Fanning ; - x and y selection arenow updated after rename (and load) ; - pairwise plotting automatically "clones" x or y selection ; if only one entry is given (but multiple entries in the other) ; - pro PLOTONE now uses ind_comb and should be more robust ; - matrix plotting now uses same scale for all axis of one variable ; mgs, 02 Apr 1998: ; - re-installed automatic reading of data if filename is given ; as parameter; added skp and delim options ; (side effect: widget title of first widget will have filename) ; - added global_init procedure ; mgs, 07 Apr 1998: VERSION 2.00 ; - added GROUP feature, better handling of valid and visible values ; mgs, 08 Apr 1998: ; - eliminated use of w_simpleedit and XDisplayfile, now all ; handled by w_edit ; mgs, 14 Apr 1998: ; - hourglass cursor when reading in file by command and for stat. ; - corrected colortable for group selection ; - removed bug in readfromfile which caused double reading ; mgs, 28 Apr 1998: ; - added feature to return data, header and comments of last active ; window when exiting, and introduced NO_BLOCK keyword to xmanager. ; Turns out that only one works at a time ! ; mgs, 14 May 1998: ; - NO_BLOCK feature now automatically turned on if no data (and ; header) are passed ; mgs, 15 Sep 1998: ; - CALL to external procedure now with only one line but info ; about possible parameters. ; mgs, 01 Oct 1998: ; - Opening of new or old windows now preserves window title and ; size and position. Window title gets updated if new data set is ; loaded. ; mgs, 07 Oct 1998: ; - bug fix for zero range axis (now add and subtr. 10% in this ; event) ; mgs, 27 Oct 1998: ; - added Percentiles menu item ; - base widget now resizeable again (use for minimizing only!) ; mgs, 19 Dec 1998: ; - after indexing error occured, now changed major loops to ; running from 0L and declared a few intarrs as lonarr ; mgs, 29 Mar 1999: ; - added output to (windows) printer ; - added bw and symsize keywords ; - added FAST option for large data sets ; ; TODO LIST: ; (NO PROMISE !!) ; - improve response to ill behaved files ; - implement full fletched parser for CALC which allows ; script processing to re-calculate stuff without hurting fingers. ; - implement even more flexible read and save mechanism which ; could e.g. allow to write binary files or spreadsheets etc. ; - create input widget for selection to get it exact ; - groupwise BOXPLOT (?) ; - overlay plot option ? Use one X and all Y entries ! ; ;- ; Copyright (C) 1997, Martin Schultz, Harvard University ; This software is provided as is without any warranty ; whatsoever. It may be freely used, copied or distributed ; for non-commercial purposes. This copyright notice must be ; kept with any copy of this software. If this software shall ; be used commercially or sold as part of a larger package, ; please contact the author to arrange payment. ; Bugs and comments should be directed to mgs@io.harvard.edu ; with subject "IDL routine explore" ;------------------------------------------------------------- ; ====================================================================== ; ; INIT GLOBAL PARAMETERS ; ; edit this section if you want to change plotting symbols etc. ; May at some point be replaced by reading of an .ini file. ; ; ====================================================================== pro global_init,bw=bw,symsize=psymsize common globalparams,missingcode,MAXGROUP,gnames,gsyms,gssyms,gcols,gscols, $ symsize,selsize ; set up list of values that shall be treated as missing missingcode = [ -999., -888., -777., -666., -555., $ -999.99, -999.9, -99.99, -9.99, -9.999, $ -9.99E30, -8.88E30, -7.77E30 ] ; maximum number of groups allowed MAXGROUP = 30 ; group names : default is number gnames = strtrim(indgen(MAXGROUP),2) ; plotting symbols for each group (0=default if no groups defined) gsyms = [ 1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, $ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, $ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ] ; plotting symbols for each group (0=default if no groups defined) gssyms = [ 6, 6, 7, 8, 9, 10, 6, 7, 8, 9, 10, $ 6, 7, 8, 9, 10, 6, 7, 8, 9, 10, $ 6, 7, 8, 9, 10, 6, 7, 8, 9, 10 ] ; colors for each group when selected or no selection was made gcols = [ 1, 2, 7, 3, 4, 6, 1, 13, 5, 2, 3, $ 4, 6, 7, 1, 13, 5, 2, 3, 4, 6, $ 7, 1, 13, 5, 2, 3, 4, 6, 7, 1 ] ; colors for each group when not selected and selection was made gscols = [ 14, 8, 10, 9, 10, 8, 14, 15, 8, 8, 9, $ 10, 8, 10, 15, 15, 8, 8, 9, 10, 8, $ 10, 15, 15, 8, 8, 9, 10, 8, 10, 15 ] if (keyword_set(bw)) then begin gcols = fltarr(31)+1 gscols = gcols endif ; default symbol size (not selected) if (n_elements(psymsize) eq 0) then $ psymsize = 0.8 symsize = psymsize ; increase in symbol size if selected selsize = 1.2 ; some intialization of !P, !X, and !Y !p.multi = 0 !p.position = 0 !p.charsize=1.4 !p.thick=2 !x.thick=2 !x.charsize=1.2 !x.omargin = [ 4,2 ] !y.thick=2 !y.charsize=1.2 !y.omargin = [ 2,6 ] return end ; ====================================================================== ; ; WINDOW HANDLING ; ; get_free_window ; ; ====================================================================== function get_free_window common window_ind,wind if(n_elements(wind) le 1) then wind = intarr(32) ind = where(wind eq 0) return,ind(0) end ; ====================================================================== ; ; FILE HANDLING ; ; uses w_fileopen and readdata ; ; ====================================================================== pro readfromfile,data,header,comments=comments, $ filename=filename,delim=delim, $ skp1=skp1,skp2=skp2,autoskip=autoskip, $ forceparams=force if(not keyword_set(filename)) then filename = 'test.dat' if(n_elements(delim) le 0) then delim = ' ' if(n_elements(skp1) le 0) then skp1 = 0 if(n_elements(skp2) le 0) then skp2 = 0 if(not keyword_set(force)) then begin dlg = w_fileopen(title='Read Data',filename=filename, $ delim=delim, skp1=skp1, skp2=skp2, $ /READ ) widget_control,dlg,/realize event = widget_event(dlg) if(event.value) then begin info = event.info filename = info.filename delim = info.delim skp1 = info.skp1 skp2 = info.skp2 autoskip = info.cbox > 0 ; minimum zero widget_control,/hourglass readdata,filename,data,header,comments=comments, $ delim=delim,skp1=skp1,skp2=skp2, $ autoskip=autoskip endif widget_control,event.top,/destroy endif else begin ; force reading with passed parameters widget_control,/hourglass readdata,filename,data,header,comments=comments, $ delim=delim,skp1=skp1,skp2=skp2, $ autoskip=autoskip endelse ; replace comment line with header information with template if (skp1 lt n_elements(comments)) then $ comments(skp1) = '[%VARIABLE NAMES%]' return end pro savetofile,data,header,comments=comments, $ filename=filename,delim=delim if(not keyword_set(filename)) then filename = 'test.dat' if(n_elements(delim) le 0) then delim = ' ' dlg = w_fileopen(title='Save Data',filename=filename, $ comments=comments, delim=delim, $ /SAVE ) widget_control,dlg,/realize event = widget_event(dlg) if(event.value) then begin info = event.info filename=info.filename delim=info.delim save_com = info.cbox > 0 ; could be -1, if so make it 0 comments = info.comments savegroup = 0 ; info.savegroup ; delete group information from data if (not savegroup) then begin gind = where(strupcase(header) ne 'GROUP') if (gind(0) ge 0) then begin header = header(gind) data = data(gind,*) endif endif template = '[%VARIABLE NAMES%]' if (not save_com) then comments = template ; save only names if (delim eq '') then delim = ' ' headstr = string(header,format='(500(A,:,"'+delim+'"))') ; look for template of variable names and insert header information ; if not found append to the end if (n_elements(comments) eq 1 AND comments(0) eq '') then $ comments(0) = template ; empty field ind = where(comments eq template) if (ind(0) ge 0) then comments(ind) = headstr $ else comments = [ comments, headstr ] ; here we write the data widget_control,dlg,/hourglass writedata,filename,data,comments=comments,/no_warn endif widget_control,event.top,/destroy return end ; ====================================================================== ; ; PLOT ROUTINES ; ; ====================================================================== ; ===== some helper routines ===== function ismissing,x common globalparams,missingcode,MAXGROUP,gnames,gsyms,gssyms,gcols,gscols, $ symsize,selsize ; see global_init for initialization of missingcode ind = where(missingcode eq x) res = ind(0) ge 0 return,res end function valid_ind,x,hidden,all=all,log=log ; return long integer array with 1 for each valid and visible entry of x ; usage : e.g. ind = where(valid_ind(x,hidden) * $ ; valid_ind(y,hidden) gt 0) res = lonarr(n_elements(x)) if (n_elements(hidden) eq 0) then hidden = -1 ; check for missing values for i=0L,n_elements(x)-1 do $ res(i) = (ismissing(x(i)) eq 0) ; remove hidden values from valid list if (not keyword_set(all) and hidden(0) ge 0) then $ res(hidden) = 0 ; remove all negative values if log keyword is set if (keyword_set(log)) then begin ind = where(x le 0.) if (ind(0) ge 0) then res(ind) = 0 endif return,res end function sel_ind,vinda,select ; return long integer array with 1 for each visible and selected entry ; vinda must contain 1 for each valid entry (function valid_ind) sres = lonarr(n_elements(vinda)) if (select(0) ge 0L) then sres(select) = 1L res = vinda*sres return,res end function nsel_ind,vinda,select ; return long integer array with 1 for each visible and selected entry ; vinda must contain 1 for each valid entry (function valid_ind) sres = lonarr(n_elements(vinda))+1 if (select(0) ge 0L) then sres(select) = 0L res = vinda*sres return,res end ; SHALL BE REPLACED !! function wheremissing,x res = -1 for i=0L,n_elements(x)-1 do $ if ismissing(x(i)) then res = [ res, i ] if (n_elements(res) gt 1) then res = res(where(res ge 0)) return,res end ; SHALL BE REPLACED !! function wherenotmissing,x res = -1 for i=0L,n_elements(x)-1 do $ if not(ismissing(x(i))) then res = [ res, i ] if (n_elements(res) gt 1) then res = res(where(res ge 0)) return,res end function one_statistics,x,formstr=formstr,percentiles=percentiles ; compute statistic quantities and return them as vector ; with the following entries ; MIN MAX MEDIAN MEAN STDDEV NVALID ; FORMSTR contains a formatstring to be used for output ; /PERCENTILES computes 10% 25% 50% 75% 90% instead of the above ; quantities ; it is assumed that x contains only valid data. If x consists ; of a single value eq -999.99, then output of a standard vector ; is intiated. FORWARD_FUNCTION percentiles ; create standard format string formstr = '(5(f11.3,1X),i6)' if (n_elements(x) eq 1 AND x(0) eq -999.99) then $ return,[-999.99,-999.99,-999.99,-999.99,-999.99, 0] ; get number of valid values nval = n_elements(x) ; --- proceed with standard statistics ; compute min and max xmax = max(x,min=xmin) amax = max(abs(x)) ; change format to e if min or max out of range if (amax ge 1.e7 OR amax le 1.e-2) then $ formstr = '(5(e11.3,1X),i6)' ; -- compute percentiles and return them if (keyword_set(percentiles)) then begin result = percentiles(x,value=[0.1,0.25,0.5,0.75,0.9]) return,[result,nval] endif ; --- compute median xmed = median(x) ; --- compute mean and std dev if (nval gt 1) then res = moment2(x,/ignore) $ else res = [ x(0), 0. ] xmean = res(0) xdev = sqrt(res(1)) ; return results return,[xmin,xmax,xmed,xmean,xdev,nval] end function statistics,x,hidden,select,group,groupval=groupval, $ percentiles=percentiles,formstr=formstr ; compute statistics of one variable depending on status of ; hidden, select, and group: ; - if select is provided and valid, compute statistics of ; selected data only ; - if group is provided and groupval is found in group, compute ; statistics only for this group (also depending on select) ; - /PERCENTILES returns 10%, 25%, 50%, 75%, 90% instead ; of MIN, MAX, MEDIAN, MEAN, STDDEV ; get valid data valx = valid_ind(x,hidden) ; if select contains information then restrict to selx Nselect = long((n_elements(select)) * (select(0) ge 0L)) if (Nselect gt 0L) then valx=sel_ind(valx,select) ; determine indices of sub array, depending on group information if (n_elements(group) gt 0 AND n_elements(groupval) eq 1) then $ gind = where(group eq groupval AND valx gt 0) $ else $ gind = where(valx gt 0) ; if valid data, compute statistics, else return bogus array if (gind(0) ge 0) then tmpx = x(gind) $ else tmpx = -999.99 result = one_statistics(tmpx,percentiles=percentiles,formstr=formstr) return,result return,0 end pro trackcursor,x1,y1,x2,y2,first=first,pixwin=pixwin ; draws rubberband for data selection ; as of 23 DEC 1997: uses device,copy (idea D.Fanning) ; return pixwin to destroy window afterwards common trackcommon,curwin,pixwinindex ; create pixmap and copy current image if (keyword_set(first)) then begin curwin = !d.window window,/free,xsize=!d.x_size,ysize=!d.y_size,/pixmap pixwin = !d.window pixwinindex = pixwin device,copy=[0,0,!d.x_size,!d.y_size,0,0,curwin] wset,curwin endif ; copy old image from pixwin device,copy=[0,0,!d.x_size,!d.y_size,0,0,pixwinindex] ; overlay red rectangle with new mouse coordinates plots,[x1,x2,x2,x1,x1],[y1,y1,y2,y2,y1],color=2,thick=1 return end pro use_cursor,x1=mx1,x2=mx2,y1=my1,y2=my2 ; activates graphics cursor for rubberband selection !err=0 cursor,mx1,my1,/down trackcursor,mx1,my1,mx1,my1,/first,pixwin=pixwin while (!mouse.button ne 0) do begin cursor,mx2,my2,/change trackcursor,mx1,my1,mx2,my2 endwhile wdelete,pixwin ; print,'X1=',mx1,',Y1=',my1 ; print,'X2=',mx2,',Y2=',my2 end function getystyle,ymin,ymax ; determine value of YSTYLE keyword to plot command sval = 0 if(ymax*ymin lt 0) then return,sval ; opposite signs ; ystyle = "normal" if(abs(ymax-ymin) lt 2*abs(ymin)) then sval = 3 ; do not include 0 return,sval end pro getlistinfo,widget_id,names=names,sel=sel ; get names and selection of x or y list widget_control,widget_id,get_value=names ; determine selection in x or y list ; (requires knowledge of the structure of cw_xysel !!) widget_control,widget_info(widget_id,/child),get_uvalue=xystate sel = widget_info(xystate.listID,/list_select) return end pro validate_names,header,state ; check through names in xlist and ylist and remove invalid ones ; xlist getlistinfo,state.ids(1),names=names for i=0,n_elements(names)-1 do begin ind = where(header eq names(i)) if (ind(0) lt 0) then xysel_remove_value,state.ids(1),names(i) endfor ; ylist getlistinfo,state.ids(2),names=names for i=0,n_elements(names)-1 do begin ind = where(header eq names(i)) if (ind(0) lt 0) then xysel_remove_value,state.ids(2),names(i) endfor return end ; ===== the major plot routines ===== pro plotone,x,y,select,hidden,group, $ xtitle=xtitle,ytitle=ytitle, $ fit=fit,xlog=xlog,ylog=ylog,fast=fast, leg=leg ; leg determines whether to plot a legend ; (Ray Sterner's leg.pro replaced by own legend.pro as of 06/23/98) ; legend is plotted on last plot common globalparams,missingcode,MAXGROUP,gnames,gsyms,gssyms,gcols,gscols, $ symsize,selsize if (not keyword_set(xtitle)) then xtitle = 'X' if (not keyword_set(ytitle)) then ytitle = 'Y' if (not keyword_set(fit)) then fit = 0 ; if no group array is passed, create a dummy array if (n_elements(group) eq 0) then begin group = fltarr(n_elements(x)) endif ; ----------------------------------------------------------------- ; extract valid and visible data for scaling ; NOTE: if log flag is set, only positive values are valid ; ----------------------------------------------------------------- valx = valid_ind(x,hidden,log=xlog) valy = valid_ind(y,hidden,log=ylog) valxy = valx*valy vind = where(valxy gt 0) valid = (n_elements(vind) * (vind(0) ge 0) ) ; count of valid data ; ----------------------------------------------------------------- ; get axis ranges ; NOTE: xmin,xmax AND ymin,ymax are calculated seperately in order to ; preserve the range of each variable individually ! This is needed ; for matrix plots ! ; ----------------------------------------------------------------- ; calculate min, max for plotting xmin = 0 & xmax = 10 ; set default values ymin = 0 & ymax = 10 if (valid gt 0) then begin xtmp = x(where(valx gt 0)) xmin = min(xtmp,max=xmax) ytmp = y(where(valy gt 0)) ymin = min(ytmp,max=ymax) endif ; if min and max are identical, subtract and add 10% each if (xmin eq xmax) then begin xmin = xmin - 0.1*abs(xmin) xmax = xmax + 0.1*abs(xmax) endif if (ymin eq ymax) then begin ymin = ymin - 0.1*abs(ymin) ymax = ymax + 0.1*abs(ymax) endif ; ----------------------------------------------------------------- ; draw empty coordinate system ; ----------------------------------------------------------------- ystyle=getystyle(ymin,ymax) plot,[xmin,xmax],[ymin,ymax],/nodata,color=1, $ xtitle=xtitle,ytitle=ytitle,ystyle=ystyle, $ xrange=[xmin,xmax],yrange=[ymin,ymax], $ xlog=xlog,ylog=ylog if (valid eq 0) then return ; only empty coordinate system ; ----------------------------------------------------------------- ; PLOT DATA group by group, not-selected, then selected ; ----------------------------------------------------------------- ; get uniq group values and loop through them extracting the valid data ; for each group - NOTE: group index determines symbol etc. ugroup = group(uniq(group,sort(group))) ngroups = n_elements(ugroup) ; ugind = where(ugroup ge 0) ; only selected groups ; if (ugind(0) lt 0) then return ; ugroup = ugroup(ugind) if (ngroups gt MAXGROUP) then begin dum=dialog_message('GROUP exceeds maximum allowed value '+ $ '-> no plotting!') return endif ; extract valid, non-selected and valid, selected data selxy = sel_ind(valxy,select) nselxy = nsel_ind(valxy,select) for gg = 1,ngroups do begin ; indices of selected (non-selected) points in group sind = where(group eq ugroup(gg-1) AND selxy gt 0) nsind = where(group eq ugroup(gg-1) AND nselxy gt 0) ; drawing color: if selection is made then use gscols, else gcols ; if only one group exists then use symbol and color of index 0 col = gcols(gg * (ngroups gt 1)) csym = gsyms(gg * (ngroups gt 1)) if (select(0) ge 0) then begin col = gscols(gg * (ngroups gt 1)) csym = gssyms(gg * (ngroups gt 1)) endif if (nsind(0) ge 0) then begin if (keyword_set(FAST)) then $ nsum = fix(n_elements(nsind)/500.)+1 $ else $ nsum = 1 oplot,x(nsind),y(nsind),color=col, $ psym=sym(csym),symsize=symsize,nsum=nsum endif ; =========================================================================== ; oplot desired fits ===>> IMPROVE, better interface ## !!! if(fit le 0) then goto,nofitplot ; truncate data to valid and visible data only tmpx = x(vind) tmpy = y(vind) label = '' if ((fit AND 1) gt 0) then begin ; linear fit m_fit,tmpx,tmpy,fx,fy,fymin,fymax,nsig=2,label=tmplabel label = [ label,tmplabel ] oplot,fx,fy,color=1 if(n_elements(fymin) gt 0) then oplot,fx,fymin,color=1,linestyle=1 if(n_elements(fymax) gt 0) then oplot,fx,fymax,color=1,linestyle=1 endif if ((fit AND 2) gt 0) then begin ; quadratic fit m_fit,tmpx,tmpy,fx,fy,poly=2,nsig=2,label=tmplabel label = [ label,tmplabel ] oplot,fx,fy,color=3,linestyle=0 endif if ((fit AND 4) gt 0) then begin ; cubic fit m_fit,tmpx,tmpy,fx,fy,poly=3,nsig=2,label=tmplabel label = [ label,tmplabel ] oplot,fx,fy,color=3,linestyle=2 endif if ((fit AND 8) gt 0) then begin ; exponential fit m_fit,tmpx,tmpy,fx,fy,/exponential,/no_offset,nsig=2,label=tmplabel label = [ label,tmplabel ] oplot,fx,fy,color=4,linestyle=0 endif if ((fit AND 16) gt 0) then begin ; exp. with offset fit m_fit,tmpx,tmpy,fx,fy,/exponential,nsig=2,label=tmplabel label = [ label,tmplabel ] oplot,fx,fy,color=4,linestyle=2 endif if (fit gt 0) then begin ; write labels ; label position : 5% of x, 95%-i*5% in y lx = fltarr(n_elements(label))+ $ 0.05*(!x.crange(1)-!x.crange(0))+!x.crange(0) ly = fltarr(n_elements(label))+!y.crange(1) for i=1,n_elements(label) do $ ly(i-1) = ly(i-1)-0.05*i*(!y.crange(1)-!y.crange(0)) xyouts,lx,ly,label,color=1,charsize=0.7 endif ; =========================================================================== nofitplot: ; plot selected data ; always use brighter colors if (sind(0) ge 0) then begin if (keyword_set(FAST)) then $ nsum = fix(n_elements(nsind)/500.)+1 $ else $ nsum = 1 oplot,x(sind),y(sind),color=gcols(gg), $ psym=sym(gsyms(gg)),symsize=symsize*selsize,nsum=nsum endif endfor ; loop over groups ; add legend only if more than one group but less than 10 if (keyword_set(leg) and ngroups gt 1 and ngroups lt 10) then begin ; ; compose arrays for leg.pro ; lcolor = 1 ; label color ; tcolor = 1 ; title color ; psym = gsyms(indgen(ngroups)+1) ; scolor = gcols(indgen(ngroups)+1) ; label = strtrim(string(ugroup,format='(f5.1)'),2) ; p = [ 0.6, 0.12, 0.86, 0.4 ] ; hardwired for now ; leg,psym=psym,scolor=scolor,label=label,lcolor=lcolor, $ ; tcolor=tcolor,position=p ; use mgs own legend routine now symbol = gsyms(indgen(ngroups)+1) scolor = gcols(indgen(ngroups)+1) label = strtrim(string(ugroup,format='(f5.1)'),2) legend,symbol=symbol,label=label,color=scolor,title='GROUP' endif return end ; ---------------------------------------------------------------------- pro draw,datastruc,xnames,ynames,xsel=xsel,ysel=ysel,plotinfo=plotinfo, $ plottype=plottype,matrix=matrix,pairs=pairs,single=single,ps=ps, $ retainstat=retainstat,winfo=winfo,printer=printer ; redraw last plot or draw new plots (if keyword is set) ; winfo may contain window size and position information and title if (not keyword_set(plottype)) then plottype = -1 if (keyword_set(plotinfo) AND plottype lt 0) then $ plottype = plotinfo.lastplot if (keyword_set(matrix)) then plottype = 1 ; overwrites given plottype ! if (keyword_set(pairs)) then plottype = 2 if (keyword_set(single)) then plottype = 3 if(plottype lt 0) then return ; no plot to be redrawn if(keyword_set(plotinfo)) then begin fit = plotinfo.fittype xlog = plotinfo.xlog ylog = plotinfo.ylog ps_opt = plotinfo.ps_opt fast = plotinfo.fast endif else begin fit = 0 xlog = 0 ylog = 0 ps_opt = { orient:0, eps:0, timestamp:0, filename:'explore' } fast = 1 endelse ; extract information data = datastruc.data header = datastruc.header select = datastruc.select hidden = datastruc.hidden ; check which items are selected xn = n_elements(xnames) yn = n_elements(ynames) if (xn eq 1 AND xnames(0) eq '') then xn = 0 if (yn eq 1 AND ynames(0) eq '') then yn = 0 if (xn le 0 OR yn le 0) then return ; no plot necessary xind = -1 & yind = -1 for i = 0,xn-1 do xind = [ xind, where(header eq xnames(i)) ] for i = 0,yn-1 do yind = [ yind, where(header eq ynames(i)) ] xind = xind(where(xind ge 0)) yind = yind(where(yind ge 0)) ; extract group information gind = where(strupcase(header) eq 'GROUP') if (gind(0) ge 0) then begin group = data(gind(0),*) ; some debug information ugroup = group(uniq(group,sort(group))) ; print,'# GROUPS:',ugroup endif olddev = !d.name ; open postscript or printer output if desired if (keyword_set(ps)) then begin ; *** NEW: check if psfilename ends with ps already psfilename = ps_opt.filename p = rstrpos(psfilename,"ps") ; print,"DEBUG**: p,strlen(psfilename) = ",p,strlen(psfilename) if (not (p eq strlen(psfilename)-2)) then begin if (ps_opt.eps) then psfilename = ps_opt.filename+'.eps' $ else psfilename = ps_opt.filename+'.ps' endif open_device,/ps,filename=psfilename,encaps=ps_opt.eps, $ /color,portrait=ps_opt.orient ; *** OLD CODE replaced by call to open_device *** ; CHECK CAREFULLY and maybe adjust open_device to suite all needs !!! *** print,'## DEBUG : PRINTER=',keyword_set(printer) endif else if (keyword_set(printer)) then begin res = Dialog_PrinterSetup() if (res) then begin set_plot,'printer' device,/INCHES,xsize=8.5,ysize=11.0,xoffset=0.,yoffset=0.,/index endif else begin return endelse endif else begin ; (not ps) device,window_state=wstate if(wstate(plotinfo.wnum)) then wset,plotinfo.wnum $ else begin if (n_elements(winfo) gt 0) then $ window,plotinfo.wnum,title=winfo.title+':'+strtrim(plotinfo.wnum,2), $ xsize=winfo.wsize[0],ysize=winfo.wsize[1], $ xpos=winfo.wpos[0],ypos=winfo.wpos[1] $ else $ window,plotinfo.wnum,title='Explore:'+strtrim(plotinfo.wnum,2) endelse endelse ; loop through selected names and plot all graphs if (plottype eq 1) then begin !p.multi = [0,xn,yn] for i = 0,yn-1 do begin for j=0,xn-1 do begin x = data(xind(j),*) y = data(yind(i),*) plotone,x,y,select,hidden,group, $ xtitle=header(xind(j)),ytitle=header(yind(i)), $ fit=fit,xlog=xlog,ylog=ylog,fast=fast, $ leg=((i eq yn-1) AND (j eq xn-1)) endfor endfor endif if (plottype eq 2) then begin if (xn ne yn AND xn gt 1 AND yn gt 1) then begin dummy=widget_message('Not the same number of x and y selections !') goto,closeps endif ; determine number of rows and columns nplots = max([xn, yn]) testc = fix(sqrt(nplots)-1.e-6)+1 ; number of cols testr = ceil(nplots/float(testc)) ; (last row may not be complete) !p.multi = [0,testc,testr] for i=0,nplots-1 do begin if (xn gt 1) then currx=xind(i) else currx=xind(0) x = data(currx,*) if (yn gt 1) then curry=yind(i) else curry=yind(0) y = data(curry,*) plotone,x,y,select,hidden,group, $ xtitle=header(currx),ytitle=header(curry), $ fit=fit,xlog=xlog,ylog=ylog,fast=fast,leg=(i eq nplots-1) endfor endif if (plottype eq 3) then begin !p.multi=[0,1,1] ; select last items in x and y list as default if(n_elements(xsel) le 0) then xsel = -1 if(n_elements(ysel) le 0) then ysel = -1 if(xsel lt 0 OR xsel ge xn) then xsel = xn-1 if(ysel lt 0 OR ysel ge yn) then ysel = yn-1 x = data(xind(xsel),*) y = data(yind(ysel),*) plotone,x,y,select,hidden,group, $ xtitle=header(xind(xsel)),ytitle=header(yind(ysel)), $ fit=fit,xlog=xlog,ylog=ylog,fast=fast,/leg endif closeps: ; close postscript output if (keyword_set(ps)) then $ close_device,file=psfilename,timestamp=ps_opt.timestamp if (keyword_set(printer)) then begin device,/close set_plot,olddev print,'### DEBUG: olddev=',olddev endif if (not keyword_set(retainstat)) then plotinfo.lastplot = plottype return end ; ====================================================================== ; ; HANDLE MENU EVENTS ; ; All menu events are handled here in seperate routines. ; Other events (option buttons, selection in main list) are dealt ; with in main event loop further below ; ; ====================================================================== ; ===== FILE ===== pro ReadData_Event,event,force=force stateholder = widget_info(event.top,/child) widget_control,stateholder,get_uvalue=state datastruc = state.data fileinfo = state.fileinfo plotinfo = state.plotinfo ; create dummy template - if reading fails, old data will be used data = 0 header = '' comments = '' select = -1 hidden = -1 filename = fileinfo.filename delim = fileinfo.delim skp1=fileinfo.skp1 skp2=fileinfo.skp2 autoskip = fileinfo.autoskip readfromfile,data,header,comments=comments, $ filename=filename,delim=delim, $ skp1=skp1,skp2=skp2,autoskip=autoskip, $ forceparams=force ; check if reading succeeded if (n_elements(data) lt 2) then return datastruc = { data:data, header:header, select:select, hidden:hidden } fileinfo = { filename:filename, comments:comments, delim:delim, $ skp1:skp1, skp2:skp2, autoskip:autoskip } ; insert header into mainlist mainlist = state.ids(0) newsize=max(strlen(header)) > 20 ; xsize at least 20 widget_control,mainlist,set_value=header,xsize=newsize ; check through names in xlist and ylist and remove invalid ones validate_names,header,state ; reset plotinfo state.plotinfo.lastplot = -1 ; restore status state = { ids:state.ids, data:datastruc, fileinfo:fileinfo, $ plotinfo:state.plotinfo } widget_control,stateholder,set_uvalue=state ; set new title in widget and window wnum = state.plotinfo.wnum widget_control,event.top,tlb_set_title=filename+':'+strtrim(wnum,2) if ((!d.flags AND 256) gt 0) then begin device,window_state=wstate if (wstate[wnum]) then begin wset,wnum xsize = !d.x_size ysize = !d.y_size device,get_window_position=wpos window,wnum,xsize=xsize,ysize=ysize, $ xpos=wpos[0],ypos=wpos[1], $ title=filename+':'+strtrim(wnum,2) endif endif return end pro DoSaveData,event,SELECTION=SELECTION ; Handle the Save Data event. ; SELECTION: save only selected variables and selected cases ; If no cases are selected, save all visible cases. stateholder = widget_info(event.top,/child) widget_control,stateholder,get_uvalue=state datastruc = state.data fileinfo = state.fileinfo data = datastruc.data header = datastruc.header comments = fileinfo.comments filename = fileinfo.filename + '.new' delim = fileinfo.delim if (keyword_set(SELECTION)) then begin hidden = datastruc.hidden select = datastruc.select not_hidden = inv_index(hidden,n_elements(data(0,*))) if (not_hidden(0) lt 0) then return ; no visible data to be saved ; ASSUME that select contains only non hidden values (should be the case !) if (select(0) lt 0) then select = not_hidden ; only for local use data = data(*,select) ; safe, because datastruc is ; not written back. ; get current content of selection lists widget_control,state.ids(1),get_value=xnames widget_control,state.ids(2),get_value=ynames ; get unique variable indices xind = -1 & yind = -1 for i = 0,n_elements(xnames)-1 do $ xind = [ xind, where(header eq xnames(i)) ] for i = 0,n_elements(ynames)-1 do $ yind = [ yind, where(header eq ynames(i)) ] tmpind = [xind, yind] wi = where(tmpind ge 0,c) if (c gt 0) then begin ; found selected variables tmpind = tmpind(wi) bla = uniq(tmpind, sort(tmpind)) if(bla(0) ge 0) then tmpind = tmpind(bla) data = data(tmpind,*) header = header(tmpind) endif endif savetofile,data,header,comments=comments, $ filename=filename,delim=delim fileinfo.filename = filename state.fileinfo = fileinfo widget_control,stateholder,set_uvalue=state return end pro SaveAllData_Event,event DoSaveData,event return end pro SaveSelectedData_Event,event DoSaveData,event,/SELECTION return end pro EditComments_Event,event stateholder = widget_info(event.top,/child) widget_control,stateholder,get_uvalue=state fileinfo = state.fileinfo comments = fileinfo.comments ; call w_edit dialog dlg = w_edit(title='Edit comments',text=comments) widget_control,dlg,/realize event = widget_event(dlg) if(event.value) then begin newcomments = event.info ind = where(newcomments ne '') if (ind(0) ge 0) then comments = newcomments(ind) endif widget_control,event.top,/destroy ; re-create fileinfo and state, store back fileinfo = { filename:fileinfo.filename, comments:comments, $ delim:fileinfo.delim, $ skp1:fileinfo.skp1, skp2:fileinfo.skp2, $ autoskip:fileinfo.autoskip } state = { ids:state.ids, data:state.data, fileinfo:fileinfo, $ plotinfo:state.plotinfo } widget_control,stateholder,set_uvalue=state return end pro Done_Event,event ; is supposed to close all windows, but can only close those that are ; properly registered in wbase common window_ind,wind common widget_bases,wbase common epointers,pdata,pheader,pcomments ; NEW (04/28/98): create a pointer for data, header, and comments and store ; them in a common block so they can be returned by the explore main program. ; Only the data from the current active window will be returned stateholder = widget_info(event.top,/child) widget_control,stateholder,get_uvalue=state data = (state.data).data header = (state.data).header comments = (state.fileinfo).comments ; free pointers if they contain junk from a previous session if (ptr_valid(pdata)) then ptr_free,pdata if (ptr_valid(pheader)) then ptr_free,pheader if (ptr_valid(pcomments)) then ptr_free,pcomments ; create pointers: use NO_COPY pdata = ptr_new(data,/no_copy) pheader = ptr_new(header,/no_copy) pcomments = ptr_new(comments,/no_copy) ; now go ahead and close windows for i=0,31 do $ if(wbase(i) gt 0) then begin stateholder = widget_info(wbase(i),/child) widget_control,stateholder,get_uvalue=state ; close window wdelete,state.plotinfo.wnum wind(state.plotinfo.wnum) = 0 ; mark as free ; kill widget widget_control,wbase(i),/destroy wbase(i) = 0 endif ; reset !p.multi for subsequent applications !p.multi = 0 return end ; ===== WINDOW ===== pro Copy_Event,event stateholder = widget_info(event.top,/child) widget_control,stateholder,get_uvalue=state getlistinfo,state.ids(1),names=xnames,sel=xsel getlistinfo,state.ids(2),names=ynames,sel=ysel ; open new widget and activate newtitle=state.fileinfo.filename if(newtitle eq '') then newtitle = 'explore' plotinfo = state.plotinfo new_widget,base=base,title=newtitle,data=state.data, $ xnames=xnames,ynames=ynames,xsel=xsel,ysel=ysel, $ fileinfo=state.fileinfo,plotinfo=plotinfo ; reproduce the same plot as on the old (current) window if ((!d.flags AND 256) gt 0) then begin ; get size and position of current window device,get_window_position=wpos wsize = [ !d.x_size, !d.y_size ] winfo = { title:state.fileinfo.filename, wsize:wsize, wpos:wpos } endif datastruc = state.data draw,datastruc,xnames,ynames,plotinfo=plotinfo,xsel=xsel,ysel=ysel, $ winfo=winfo ; and return winow handling to manager xmanager,'MAINL',base return end pro Close_Event,event common window_ind,wind common widget_bases,wbase stateholder = widget_info(event.top,/child) widget_control,stateholder,get_uvalue=state ; close window wdelete,state.plotinfo.wnum wind(state.plotinfo.wnum) = 0 ; mark as free wbase(state.plotinfo.wnum) = 0 ; kill widget widget_control,event.top,/destroy return end ; ===== DATA ===== pro sort_event,event stateholder = widget_info(event.top,/child) widget_control,stateholder,get_uvalue=state datastruc = state.data data = datastruc.data header = datastruc.header if(n_elements(data) le 1 OR n_elements(header) le 1) then return dlg = w_sort(header) widget_control,dlg,/realize event = widget_event(dlg) if(event.value) then begin info = event.info handle_sort,data,event.info endif widget_control,event.top,/destroy ; restore status datastruc = {data:data, header:header, $ select:datastruc.select, hidden:datastruc.hidden } state = { ids:state.ids, data:datastruc, fileinfo:state.fileinfo, $ plotinfo:state.plotinfo } widget_control,stateholder,set_uvalue=state return end pro calc_event,event stateholder = widget_info(event.top,/child) widget_control,stateholder,get_uvalue=state datastruc = state.data data = datastruc.data header = datastruc.header if(n_elements(data) le 1 OR n_elements(header) le 1) then return ; it may be better to call CALC repeatedly, but ... ; repeat begin dlg = w_calc(species=header) widget_control,dlg,/realize event = widget_event(dlg) if(event.value) then begin info = event.info handle_calc,data,header,event.info,label = label ; print formula on main screen print,'>>> ',label endif widget_control,event.top,/destroy ; end until (event.value le 0) ; update species list in mainlist widget_control,state.ids(0),set_value=header,set_uvalue=header ; restore status datastruc = {data:data, header:header, select:datastruc.select, $ hidden:datastruc.hidden } state = { ids:state.ids, data:datastruc, fileinfo:state.fileinfo, $ plotinfo:state.plotinfo } widget_control,stateholder,set_uvalue=state return end pro RenVar_event,event stateholder = widget_info(event.top,/child) widget_control,stateholder,get_uvalue=state datastruc = state.data data = datastruc.data header = datastruc.header if(n_elements(data) le 1 OR n_elements(header) le 1) then return mainsel = widget_info(state.ids(0),/list_select) if (mainsel lt 0) then begin dum = dialog_message('No variable selected.',/error) return endif dlg = w_edit(title='RENAME',text=header(mainsel), $ prompt='Rename '+header(mainsel)+' to:', $ lines=1) widget_control,dlg,/realize event = widget_event(dlg) if(event.value) then begin info = event.info ; update x and y selection xysel_change_value,state.ids(1),header(mainsel),info xysel_change_value,state.ids(2),header(mainsel),info ; and change header in mainlist header(mainsel) = info endif widget_control,event.top,/destroy ; update species list in mainlist widget_control,state.ids(0),set_value=header,set_uvalue=header ; restore status datastruc = {data:data, header:header, select:datastruc.select, $ hidden:datastruc.hidden } state = { ids:state.ids, data:datastruc, fileinfo:state.fileinfo, $ plotinfo:state.plotinfo } widget_control,stateholder,set_uvalue=state return end pro delvar_event,event stateholder = widget_info(event.top,/child) widget_control,stateholder,get_uvalue=state datastruc = state.data data = datastruc.data header = datastruc.header if(n_elements(data) le 1 OR n_elements(header) le 1) then return mainsel = widget_info(state.ids(0),/list_select) if (mainsel lt 0) then begin dum = dialog_message('No variable selected.',/error) return endif ind = inv_index(mainsel,n_elements(header)) header = header(ind) data = data(ind,*) ; update species list in mainlist and update x- and y-selections widget_control,state.ids(0),set_value=header,set_uvalue=header, $ set_list_select = -1 validate_names,header,state ; restore status datastruc = {data:data, header:header, select:datastruc.select, $ hidden:datastruc.hidden } state = { ids:state.ids, data:datastruc, fileinfo:state.fileinfo, $ plotinfo:state.plotinfo } widget_control,stateholder,set_uvalue=state return end pro CallExt_event,event ; extract data and header information from state structure and pass ; it to a routine named by the user. After successful completion of ; the procedure, store manipulated data back. stateholder = widget_info(event.top,/child) widget_control,stateholder,get_uvalue=state datastruc = state.data data = datastruc.data header = datastruc.header hidden = datastruc.hidden select = datastruc.select fileinfo = state.fileinfo filename = fileinfo.filename comments = fileinfo.comments delim = fileinfo.delim skp1 = fileinfo.skp1 skp2 = fileinfo.skp2 autoskip = fileinfo.autoskip if(n_elements(data) le 1 OR n_elements(header) le 1) then return ; display edit dialog asking for routine name dlg = w_edit(title='CALL EXTERNAL PROCEDURE',text=[''], $ prompt=['procedure name:'], $ comments=['possible parameters data,header,filename,comments']) widget_control,dlg,/realize event = widget_event(dlg) if(event.value) then begin ; event.info will contain 1 line : routine name with parameters rname = event.info(0) ; set-up catch error because users may do all kinds of things catch,err_stat if (err_stat ne 0) then begin ; print error message print,'*** ERROR ',err_stat,' : ',!err_string success = 0 goto,skip_it endif cmdstr = rname success = execute(cmdstr) if (not success) then $ print,'% Call to external routine not successful!',!err_string skip_it: catch,/cancel if (not success) then goto,no_success ; report math errors dum = check_math(/print) ; re-build mainlist and check through x- and y-lists ; (because header may have changed) mainlist = state.ids(0) newsize=max(strlen(header)) > 20 ; xsize at least 20 widget_control,mainlist,set_value=header,xsize=newsize validate_names,header,state ; store data and fileinfo in struc and restore status datastruc = {data:data, header:header, select:datastruc.select, $ hidden:datastruc.hidden } fileinfo = { filename:filename, comments:comments, delim:delim, $ skp1:skp1, skp2:skp2, autoskip:autoskip } state = { ids:state.ids, data:datastruc, fileinfo:fileinfo, $ plotinfo:state.plotinfo } widget_control,stateholder,set_uvalue=state no_success: endif widget_control,event.top,/destroy return end ; ===== PLOT ===== pro PlotMatrix_Event,event stateholder = widget_info(event.top,/child) widget_control,stateholder,get_uvalue=state datastruc = state.data if(n_elements(datastruc.data) le 1) then return plotinfo = state.plotinfo getlistinfo,state.ids(1),names=xnames getlistinfo,state.ids(2),names=ynames if(plotinfo.ps) then begin draw,datastruc,xnames,ynames,plotinfo=plotinfo,/matrix,/ps plotinfo.ps = 0 widget_control,state.ids(3),get_value=bstate bstate(2) = 0 widget_control,state.ids(3),set_value=bstate endif if(plotinfo.printer) then begin draw,datastruc,xnames,ynames,plotinfo=plotinfo,/matrix,/printer plotinfo.printer = 0 widget_control,state.ids(3),get_value=bstate bstate(1) = 0 widget_control,state.ids(3),set_value=bstate endif ; draw on screen ; *** needs to pass WINFO in case window was closed *** draw,datastruc,xnames,ynames,plotinfo=plotinfo,/matrix ; restore status state.plotinfo = plotinfo widget_control,stateholder,set_uvalue=state return end pro PlotPairs_Event,event stateholder = widget_info(event.top,/child) widget_control,stateholder,get_uvalue=state datastruc = state.data if(n_elements(datastruc.data) le 1) then return plotinfo = state.plotinfo getlistinfo,state.ids(1),names=xnames getlistinfo,state.ids(2),names=ynames if(plotinfo.ps) then begin draw,datastruc,xnames,ynames,plotinfo=plotinfo,/pairs,/ps plotinfo.ps = 0 widget_control,state.ids(3),get_value=bstate bstate(2) = 0 widget_control,state.ids(3),set_value=bstate endif if(plotinfo.printer) then begin draw,datastruc,xnames,ynames,plotinfo=plotinfo,/pairs,/printer plotinfo.printer = 0 widget_control,state.ids(3),get_value=bstate bstate(1) = 0 widget_control,state.ids(3),set_value=bstate endif ; draw on screen ; *** needs to pass WINFO in case window was closed *** draw,datastruc,xnames,ynames,plotinfo=plotinfo,/pairs ; restore status state.plotinfo = plotinfo widget_control,stateholder,set_uvalue=state return end pro PlotSingle_Event,event stateholder = widget_info(event.top,/child) widget_control,stateholder,get_uvalue=state datastruc = state.data if(n_elements(datastruc.data) le 1) then return plotinfo = state.plotinfo getlistinfo,state.ids(1),names=xnames,sel=xsel getlistinfo,state.ids(2),names=ynames,sel=ysel ; print,'DEBUG>>plot single (xsel,ysel):',xsel,ysel if(plotinfo.ps) then begin draw,datastruc,xnames,ynames,xsel=xsel,ysel=ysel, $ plotinfo=plotinfo,/single,/ps plotinfo.ps = 0 widget_control,state.ids(3),get_value=bstate bstate(2) = 0 widget_control,state.ids(3),set_value=bstate endif if(plotinfo.printer) then begin draw,datastruc,xnames,ynames,plotinfo=plotinfo,/single,/printer plotinfo.printer = 0 widget_control,state.ids(3),get_value=bstate bstate(1) = 0 widget_control,state.ids(3),set_value=bstate endif ; draw on screen ; *** needs to pass WINFO in case window was closed *** draw,datastruc,xnames,ynames,xsel=xsel,ysel=ysel, $ plotinfo=plotinfo,/single ; restore status state.plotinfo = plotinfo widget_control,stateholder,set_uvalue=state return end pro Selectfit_event,event stateholder = widget_info(event.top,/child) widget_control,stateholder,get_uvalue=state plotinfo = state.plotinfo dlg = w_options(title='SELECT FIT',value=abs(plotinfo.fittype), options= $ ['linear','quadratic','cubic','exponential','exp. with offset' ]) widget_control,dlg,/realize event = widget_event(dlg) if(event.value) then begin info = event.info plotinfo.fittype = info widget_control,state.ids(3),get_value=bstate if (not bstate(0)) then plotinfo.fittype = -plotinfo.fittype endif widget_control,event.top,/destroy ; restore status state = { ids:state.ids, data:state.data, fileinfo:state.fileinfo, $ plotinfo:plotinfo } widget_control,stateholder,set_uvalue=state return end pro PostOpt_event,event stateholder = widget_info(event.top,/child) widget_control,stateholder,get_uvalue=state plotinfo = state.plotinfo ps_opt = plotinfo.ps_opt dlg = w_psopt(title='POSTSCRIPT OPTIONS', $ orientation=ps_opt.orient, encaps=ps_opt.eps, $ timestamp=ps_opt.timestamp, filename=ps_opt.filename ) widget_control,dlg,/realize event = widget_event(dlg) if(event.value) then begin info = event.info plotinfo = { lastplot:plotinfo.lastplot, fittype:plotinfo.fittype, $ xlog:plotinfo.xlog, ylog:plotinfo.ylog, $ ps:plotinfo.ps, ps_opt:info, printer:plotinfo.printer, $ fast:plotinfo.fast, wnum:plotinfo.wnum } endif widget_control,event.top,/destroy ; restore status state = { ids:state.ids, data:state.data, fileinfo:state.fileinfo, $ plotinfo:plotinfo } widget_control,stateholder,set_uvalue=state return end ; ===== REGION ===== pro Handle_SelectRegion,state,newselect=newselect datastruc = state.data data = datastruc.data if(n_elements(datastruc.data) le 1) then return header = datastruc.header hidden = datastruc.hidden getlistinfo,state.ids(1),names=xnames,sel=xsel getlistinfo,state.ids(2),names=ynames,sel=ysel if (n_elements(xnames) le 0 OR n_elements(ynames) le 0) then return ; draw single plot of selected variables ; ***** IMPROVE HERE : PLOT ONLY IF NECESSARY ********** plotinfo = state.plotinfo ; *** needs to pass WINFO in case window was closed *** draw,datastruc,xnames,ynames,xsel=xsel,ysel=ysel, $ plotinfo=plotinfo,/single,/retain ; if this was the first plot set it in plotinfo if(plotinfo.lastplot lt 0) then begin plotinfo.lastplot = 3 endif ; redraw = 2 ; use_cursor,x1=x1,y1=y1,x2=x2,y2=y2,redraw=redraw use_cursor,x1=x1,y1=y1,x2=x2,y2=y2 ; get x and y data of selection plot ; (this is done AFTER draw, because draw corrects xsel, ysel if necessary xind = where(header eq xnames(xsel)) yind = where(header eq ynames(ysel)) x = data(xind,*) y = data(yind,*) newselect = where(x ge min([x1,x2]) AND x le max([x1,x2]) $ AND y ge min([y1,y2]) AND y le max([y1,y2]) ) nothidden = inv_index(hidden,n_elements(x)) newselect = ind_comb(newselect,nothidden,"AND") return end pro SelectRegion_Event,event stateholder = widget_info(event.top,/child) widget_control,stateholder,get_uvalue=state Handle_SelectRegion,state,newselect=newselect ; extract data information datastruc = state.data getlistinfo,state.ids(1),names=xnames,sel=xsel getlistinfo,state.ids(2),names=ynames,sel=ysel plotinfo = state.plotinfo select = newselect datastruc = { data:datastruc.data, header:datastruc.header, $ select:select, hidden:datastruc.hidden } ; redraw old plot with new selection on screen ; *** needs to pass WINFO in case window was closed *** draw,datastruc,xnames,ynames,plotinfo=plotinfo,xsel=xsel,ysel=ysel ; restore status state = { ids:state.ids, data:datastruc, fileinfo:state.fileinfo, $ plotinfo:plotinfo } widget_control,stateholder,set_uvalue=state return end pro AddToRegion_Event,event stateholder = widget_info(event.top,/child) widget_control,stateholder,get_uvalue=state Handle_SelectRegion,state,newselect=newselect ; extract data information datastruc = state.data getlistinfo,state.ids(1),names=xnames,sel=xsel getlistinfo,state.ids(2),names=ynames,sel=ysel plotinfo = state.plotinfo select = datastruc.select if(max(select) ge 0) then select = [select,newselect] $ else select = newselect select = select(sort(select)) select = select(uniq(select)) datastruc = { data:datastruc.data, header:datastruc.header, select:select, $ hidden:datastruc.hidden } ; redraw old plot with new selection on screen ; *** needs to pass WINFO in case window was closed *** draw,datastruc,xnames,ynames,plotinfo=plotinfo,xsel=xsel,ysel=ysel ; restore status state = { ids:state.ids, data:datastruc, fileinfo:state.fileinfo, $ plotinfo:plotinfo } widget_control,stateholder,set_uvalue=state return end pro InvertRegion_Event,event stateholder = widget_info(event.top,/child) widget_control,stateholder,get_uvalue=state plotinfo = state.plotinfo if(plotinfo.lastplot lt 0) then return ; no plot was previously made ; extract data information getlistinfo,state.ids(1),names=xnames,sel=xsel getlistinfo,state.ids(2),names=ynames,sel=ysel datastruc = state.data data = datastruc.data if(n_elements(data) le 1) then return ; no data available ndat = n_elements(data(0,*)) select = datastruc.select newselect = inv_index(select,ndat) datastruc = { data:data, header:datastruc.header, select:newselect, $ hidden:datastruc.hidden } ; redraw old plot with new selection on screen ; *** needs to pass WINFO in case window was closed *** draw,datastruc,xnames,ynames,plotinfo=plotinfo,xsel=xsel,ysel=ysel ; restore status state = { ids:state.ids, data:datastruc, fileinfo:state.fileinfo, $ plotinfo:plotinfo } state.data = datastruc widget_control,stateholder,set_uvalue=state return end pro HideRegion_Event,event stateholder = widget_info(event.top,/child) widget_control,stateholder,get_uvalue=state plotinfo = state.plotinfo if(plotinfo.lastplot lt 0) then return ; no plot was previously made getlistinfo,state.ids(1),names=xnames,sel=xsel getlistinfo,state.ids(2),names=ynames,sel=ysel datastruc = state.data data = datastruc.data if(n_elements(data) le 1) then return ; no data available ndat = n_elements(data(0,*)) select = datastruc.select hidden = [ datastruc.hidden, select ] ind = where(hidden ge 0, c) if (c gt 0) then hidden = hidden(ind) newselect = -1 datastruc = { data:data, header:datastruc.header, select:newselect, $ hidden:hidden } ; redraw old plot with new selection on screen ; *** needs to pass WINFO in case window was closed *** draw,datastruc,xnames,ynames,plotinfo=plotinfo,xsel=xsel,ysel=ysel ; restore status state = { ids:state.ids, data:datastruc, fileinfo:state.fileinfo, $ plotinfo:plotinfo } widget_control,stateholder,set_uvalue=state return end pro UnHide_Event,event stateholder = widget_info(event.top,/child) widget_control,stateholder,get_uvalue=state plotinfo = state.plotinfo if(plotinfo.lastplot lt 0) then return ; no plot was previously made ; extract data information getlistinfo,state.ids(1),names=xnames,sel=xsel getlistinfo,state.ids(2),names=ynames,sel=ysel datastruc = state.data data = datastruc.data if(n_elements(data) le 1) then return ; no data available ndat = n_elements(data(0,*)) hidden = datastruc.hidden if (max(hidden) lt 0) then return ; no hidden data newselect = hidden datastruc = { data:data, header:datastruc.header, select:newselect, $ hidden:-1 } ; redraw old plot with new selection on screen ; *** needs to pass WINFO in case window was closed *** draw,datastruc,xnames,ynames,plotinfo=plotinfo,xsel=xsel,ysel=ysel ; restore status state = { ids:state.ids, data:datastruc, fileinfo:state.fileinfo, $ plotinfo:plotinfo } widget_control,stateholder,set_uvalue=state return end pro DeleteRegion_Event,event stateholder = widget_info(event.top,/child) widget_control,stateholder,get_uvalue=state plotinfo = state.plotinfo if(plotinfo.lastplot lt 0) then return ; no plot was previously made ; hence there can be no selection ; extract data information getlistinfo,state.ids(1),names=xnames,sel=xsel getlistinfo,state.ids(2),names=ynames,sel=ysel datastruc = state.data data = datastruc.data select = datastruc.select if(select(0) lt 0) then return ; no data to be deleted ; invert select index to get all cases to be kept notsel = inv_index(select,n_elements(data(0,*))) if(notsel(0) lt 0) then data=0 $ else data = data(*,notsel) ; delete all data ; select is now invalid select = -1 ; store new datastruc datastruc = { data:data, header:datastruc.header, select:select, $ hidden:datastruc.hidden } ; redraw old plot with new selection (i.e. none) on screen ; *** needs to pass WINFO in case window was closed *** draw,datastruc,xnames,ynames,plotinfo=plotinfo,xsel=xsel,ysel=ysel ; restore status state = { ids:state.ids, data:datastruc, fileinfo:state.fileinfo, $ plotinfo:plotinfo } widget_control,stateholder,set_uvalue=state return end ; ===== INFO ===== pro Display_InfoTable,event,ALLVARS=ALLVARS ; display table widget with information on selected data or on visible data ; if no selection was made stateholder = widget_info(event.top,/child) widget_control,stateholder,get_uvalue=state ; get current content of selection lists widget_control,state.ids(1),get_value=xnames widget_control,state.ids(2),get_value=ynames ; extract data and variable names datastruc = state.data data = datastruc.data dnames = datastruc.header select = datastruc.select hidden = datastruc.hidden if(n_elements(data) le 1) then return Nselect = 0 ; get unique variable indices ; if no variables are selected or keyword ALLVARS is set: use all if (not keyword_set(ALLVARS)) then begin xind = -1 & yind = -1 for i = 0,n_elements(xnames)-1 do $ xind = [ xind, where(dnames eq xnames(i)) ] for i = 0,n_elements(ynames)-1 do $ yind = [ yind, where(dnames eq ynames(i)) ] tmpind = [xind, yind] wi = where(tmpind ge 0,c) endif else c = -1 ; force usage of all variables if(c le 0) then begin tmpind = indgen(n_elements(dnames)) text = 'all '+strtrim(n_elements(tmpind),2)+' variables, ' endif else begin tmpind = tmpind(wi) text = strtrim(n_elements(tmpind),2)+' selected variables, ' endelse bla = uniq(tmpind, sort(tmpind)) if(bla(0) ge 0) then tmpind = tmpind(bla) ; determine cases to be displayed Nhidden = (n_elements(hidden) * (hidden(0) ge 0)) not_hidden=inv_index(hidden,n_elements(data(0,*))) if (not_hidden(0) lt 0) then begin dummy = dialog_message('No visible observations.') return endif Nselect = (n_elements(select) * (select(0) ge 0)) ; (A) no variables selected: display all visible cases if (Nselect eq 0) then begin cind = not_hidden text = text+'all '+strtrim(n_elements(cind),2)+' visible cases' endif else begin ; (B) display all visible AND selected cases cind = ind_comb(not_hidden,select,"AND") if (cind(0) lt 0) then begin dummy=dialog_message("There are only hidden selected cases !"+ $ "(This should not occur)", /ERROR) return endif text = text+strtrim(n_elements(cind),2)+' selected cases' endelse tmpdat = data(tmpind,*) tmpdat = tmpdat(*,cind) ; create format string array formstr = strarr(n_elements(tmpind),n_elements(cind)) formstr(*) = '(f12.3)' ; change columns to e-format where max(abs) exceeds boundary amax = fltarr(n_elements(tmpind)) for i=0L,n_elements(tmpind)-1 do $ amax(i) = max(abs(tmpdat(i,*))) eind = where(amax ge 1.e7 OR amax le 1.e-2) if (eind(0) ge 0) then formstr(eind,*) = '(e12.3)' ; display dialog with table dlg = w_datatable(title='DATA Display', text=text,data=tmpdat, $ format=formstr,c_header=dnames(tmpind), $ r_header=string(cind+1,format='(i5)') ) widget_control,dlg,/realize event = widget_event(dlg) widget_control,event.top,/destroy return end pro InfoTable_Event,event Display_InfoTable,event return end pro InfoTableAll_Event,event Display_InfoTable,event,/ALLVARS return end pro GeneralStat_Event,event,percentiles=percentiles ; display window with information on visible data and selected data ; improved version: ; - more modular handling of statistics ; - extra group information and save option FORWARD_FUNCTION strdate stateholder = widget_info(event.top,/child) widget_control,stateholder,get_uvalue=state ; get current content of selection lists widget_control,state.ids(1),get_value=xnames widget_control,state.ids(2),get_value=ynames ; extract data and variable names datastruc = state.data data = datastruc.data dnames = datastruc.header select = datastruc.select hidden = datastruc.hidden if(n_elements(data) le 1) then return ; get unique variable indices xind = -1 & yind = -1 for i = 0,n_elements(xnames)-1 do $ xind = [ xind, where(dnames eq xnames(i)) ] for i = 0,n_elements(ynames)-1 do $ yind = [ yind, where(dnames eq ynames(i)) ] tmpind = [xind, yind] wi = where(tmpind ge 0,c) if(c le 0) then begin ; no variables selected dum = dialog_message('No variables selected!') return endif tmpind = tmpind(wi) bla = uniq(tmpind, sort(tmpind)) if(bla(0) ge 0) then tmpind = tmpind(bla) ; determine whether there are selected observations and ; number of groups Nhidden = (n_elements(hidden) * (hidden(0) ge 0)) isselect = select(0) ge 0 gind = where(strupcase(dnames) eq 'GROUP') if (gind(0) ge 0) then begin group = data(gind(0),*) ; determine uniq groups ugroup = group(uniq(group,sort(group))) ngroups = n_elements(ugroup) endif else $ ngroups = 0 ; turn cursor into hourglass if more than 500 obs. and 2 groups if (ngroups gt 2 AND n_elements(data(0,*)) gt 500) then $ widget_control,/hourglass ; create info strings for each variable, header lines and ; storage fpor mean and median values nout = 2+ngroups ; number of output blocks (1 = select may be empty) outtit = strarr(nout) outtit(0) = 'Valid and visible observations:' outtit(1) = 'Selected observations:' for i=0,ngroups-1 do $ outtit(i+2) = 'Observations in group ' $ +strtrim(string(ugroup(i),format='(f10.1)'),2) + ':' if (keyword_set(PERCENTILES)) then begin header1 = string(['Name','10% ','25% ','50% ','75% ','90% ','validN'], $ format='(A24,5A12,A7)') endif else begin header1 = string(['Name','min','max','median','mean','stddev','validN'], $ format='(A24,5A12,A7)') endelse ; header2 = string(['Name','value'],format='(A25,A12)') outs = strarr(n_elements(tmpind),nout) outmean = fltarr(n_elements(tmpind),nout)-999.99 outmed = fltarr(n_elements(tmpind),nout)-999.99 ; loop through variables ; ##### WOULD PROBABLY FASTER TO LOOP OVER GROUPS FIRST !!!! ##### for i=0L,n_elements(tmpind)-1 do begin x = data(tmpind(i),*) ; compute statistics for all valid and visible data res = statistics(x,hidden,-1L,percentiles=percentiles,formstr=formstr) outs(i,0) = string(res,format=formstr) outmean(i,0) = res(3) outmed(i,0) = res(2) ; ... and for selected observations if (isselect) then begin res = statistics(x,hidden,select,percentiles=percentiles) outs(i,1) = string(res,format=formstr) outmean(i,1) = res(3) outmed(i,1) = res(2) endif ; ... and for individual groups if (ngroups gt 0) then begin for gg = 0,ngroups-1 do begin res = statistics(x,hidden,select,group,groupval=ugroup(gg), $ percentiles=percentiles) outs(i,2+gg) = string(res,format=formstr) outmean(i,2+gg) = res(3) outmed(i,2+gg) = res(2) endfor endif ; add variable name to output string outs(i,*) = string(dnames(tmpind(i)),format='(A25)') + outs(i,*) endfor ; compose all information to one big string array to be displayed text = ['Data status :', $ strtrim(n_elements(dnames),2)+' total variables'+ $ ' ('+strtrim(n_elements(tmpind),2)+' variables selected)', $ strtrim(n_elements(data(0,*)),2)+' total observations'+ $ ' ('+strtrim(Nhidden,2)+' hidden observations)' ] for i=0,nout-1 do begin text = [ text, ' ' ] if (i ne 1 OR isselect) then $ text = [ text, outtit(i), header1, outs(*,i) ] $ else $ text = [ text, 'No observations selected.' ] endfor ; call w_edit dialog dlg = w_edit(title='STATISTICS',text=text,/NO_EDIT, $ lines=4+nout*(n_elements(tmpind)+3),xsize=96, $ extrabuttons=[' Save as Table ',' Print to file ']) widget_control,dlg,/realize event = widget_event(dlg) ; if "Save and Exit" was pressed, then store mean and median data ; to file. if(event.value eq 2) then begin ; save means and medians in table format sdat = strdate() comments = ['mean values, generated ' + sdat + ' by EXPLORE' , $ string(dnames(tmpind),format='(512(A,:,1X))') ] filename = (state.fileinfo).filename ; print,'# state.fileinfo.filename ',filename writedata,filename+'.mean',outmean,comment=comments,/NO_WARN comments(0) = 'median values' writedata,filename+'.median',outmed,comment=comments,/NO_WARN endif if(event.value eq 3) then begin ; save statistics output as shown curfilename = (state.fileinfo).filename ; print,'# state.fileinfo.filename ',curfilename sdat = strdate() comments = ['statistics for data in file ' + curfilename + $ ', generated ' + sdat + ' by EXPLORE' ] filename = DIALOG_PICKFILE(title='Print statistics to file ...', $ file=curfilename+'.stat',filter='*') ; print,'# new filename ',filename if (filename ne '') then begin openw,olun,filename,/get_lun,width=512 printf,olun,comments for i=0L,n_elements(text)-1 do $ printf,olun,text(i) free_lun,olun endif endif widget_control,event.top,/destroy return end pro InfoStat_Event,event GeneralStat_Event,event return end pro InfoPerc_Event,event GeneralStat_Event,event,/PERCENTILES return end ; ====================================================================== ; ; MAIN EVENT HANDLER ; ; (menu events are handled in seperate routines above) ; ; ====================================================================== pro mainl_event,event stateholder = widget_info(event.top,/child) widget_control,stateholder,get_uvalue=state ; check if event is coming from mainlist or option button mainlist = state.ids(0) xlist = state.ids(1) ylist = state.ids(2) options = state.ids(3) plotinfo = state.plotinfo ; print,'ID,Handler:',event.id,event.handler ; print,'State :',state.ids if(event.id eq mainlist) then begin ; selection in mainlist ; print,event.index ; widget_control,mainlist,set_uvalue=event.index endif if(event.id eq xlist) then begin ; add to xlist mainsel = widget_info(mainlist,/list_select) if(mainsel ge 0) then begin header = state.data.header if(n_elements(state.data.data) gt 1) then $ widget_control,xlist,set_value=header(mainsel) endif endif if(event.id eq ylist) then begin ; add to ylist mainsel = widget_info(mainlist,/list_select) if(mainsel ge 0) then begin header = state.data.header if(n_elements(state.data.data) gt 1) then $ widget_control,ylist,set_value=header(mainsel) endif endif if(event.id eq options) then begin widget_control,event.id,get_value=bstate ; bstate(0) controls overlay of fit. If never set before, ; make it a linear fit if(plotinfo.fittype eq 0 AND bstate(0)) then plotinfo.fittype = 1 if(bstate(0)) then plotinfo.fittype = abs(plotinfo.fittype) $ else plotinfo.fittype = -abs(plotinfo.fittype) ; bstate(1) contains printer option plotinfo.printer = bstate(1) ; bstate(2) contains postscript option plotinfo.ps = bstate(2) ; bstate(3) contains x log option plotinfo.xlog = bstate(3) ; bstate(4) contains y log option plotinfo.ylog = bstate(4) ; bstate(5) contains fast option plotinfo.fast = bstate(5) if (plotinfo.ps eq 1 AND plotinfo.printer eq 1) then begin message,'Cannot activate PRINTER and PS at the same time!', $ /INFO,/NoName plotinfo.ps = 0 bstate(2) = 0 widget_control,event.id,set_value=bstate endif endif ; handle unforeseen events (should not occur but is helpful for ; future additions) if(event.id ne mainlist AND event.id ne xlist AND event.id ne ylist $ AND event.id ne options) then $ print,'EVENT:',event.id,' = ',event.value state.plotinfo = plotinfo widget_control,stateholder,set_uvalue=state return end ; ====================================================================== pro new_widget,base=base, title=title,wnum=wnum,data=datastruc, $ xnames=xnames,ynames=ynames,xsel=xsel,ysel=ysel, $ fileinfo=fileinfo,plotinfo=plotinfo common window_ind,wind common widget_bases,wbase if(n_elements(wbase) le 1) then wbase = lonarr(32) ; window management first if(not keyword_set(title)) then title = 'explore' if(not keyword_set(wnum)) then wnum = get_free_window() if(wnum lt 0) then begin dummy=dialog_message('Maximum number of windows exceeded!',/ERROR) return ; no windows left endif ; set-up xy selection window if (not keyword_set(xnames)) then xnames = '' if (not keyword_set(ynames)) then ynames = '' if (n_elements(xsel) le 0) then xsel = -1 if (n_elements(ysel) le 0) then ysel = -1 ; create datastruc if necessary if (n_elements(datastruc) le 0) then datastruc = $ { data:0, header:'', select:-1, hidden:-1 } ; create fileinfo struc if (n_elements(fileinfo) le 0) then fileinfo = $ { filename:'', comments:'', delim:' ', $ skp1:0, skp2:0, autoskip:0 } ; create new postscript options structure ps_opt = { orient:0, eps:0, timestamp:0, filename:'explore' } ; create plotinfo struc if necessary if(not keyword_set(plotinfo)) then $ plotinfo = { lastplot:-1, fittype:0, xlog:0, ylog:0, $ ps:0, ps_opt:ps_opt, printer:0, fast:1, $ wnum:wnum } ; ----------------------------------------------- ; set up base widget, main list, x- and y-lists ; ----------------------------------------------- ; base widget not resizeable base = widget_base(/row, title=title, tlb_frame_attr=0) left = widget_base(base) ; more or less dummy container, will hold state mainlist = widget_list(left, value=datastruc.header, $ xsize=20,ysize=26 ) right = widget_base(base,/column) xlist = cw_xysel(right,title='X',value=xnames,select=xsel) ylist = cw_xysel(right,title='Y',value=ynames,select=ysel) ; menu descriptor desc = [ '1\File', $ '0\Read Data\ReadData_Event', $ '0\Save Data\SaveAllData_Event', $ '0\Save Selected Data\SaveSelectedData_Event', $ '0\Edit Comments\EditComments_Event', $ '2\Done\Done_Event', $ '1\Window', $ '0\Copy Window\Copy_Event', $ '2\Close Window\Close_Event', $ '1\Data', $ '0\Sort\Sort_Event', $ '0\Calculate\Calc_Event', $ '0\Rename Variable\RenVar_Event', $ '0\Delete Variable\DelVar_Event', $ '2\Call external procedure\CallExt_Event', $ '1\Plot', $ '0\Matrix\PlotMatrix_Event', $ '0\Pairs\PlotPairs_Event', $ '0\Single\PlotSingle_Event', $ '0\Select Fit\SelectFit_Event', $ '2\Postscript Options\PostOpt_Event', $ '1\Region', $ '0\Select\SelectRegion_Event', $ '0\Add to Selection\AddToRegion_Event', $ '0\Invert\InvertRegion_Event', $ '0\Hide\HideRegion_Event', $ '0\Unhide\UnHide_Event', $ '2\Delete Region Data\DeleteRegion_Event', $ '3\Info', $ '0\Table\InfoTable_Event', $ '0\Table with all variables\InfoTableAll_Event', $ '0\Statistics\InfoStat_Event', $ '2\Percentiles\InfoPerc_Event' ] menu=cw_pdmenu(right,desc,/RETURN_FULL_NAME) bo = cw_bgroup(right,/column, /nonexclusive, $ ['overlay fit', 'print (lpt1:)', 'generate postscript', $ 'x log', 'y log', 'fast plot']) ; if (plotinfo.fittype gt 0) then $ ; widget_control,bo,set_value=[1,0] widget_control,bo,set_value=[(plotinfo.fittype gt 0),0,0, $ (plotinfo.xlog),(plotinfo.ylog), 1 ] ; create a new window (must be done now to get window number) if((!d.flags AND 256) le 0) then begin dummy = dialog_message('Device does not support windows !' + $ '!CClose device and set_plot to X.',/ERROR) close_device endif ; take window size from current window ; *** SHOULD ADD WINDOW SIZE TO PLOTINFO !! *** xsize = (!d.x_size > 300) < 1028 ysize = (!d.y_size > 200) < 780 window,wnum,retain=2,title=title+':'+strtrim(wnum,2),xsize=xsize,ysize=ysize plotinfo.wnum = wnum plotinfo.ps = 0 ; (old debug should not occur) if(!d.window ne wnum) then begin print,'****** WHY is WNUM different ? ***' print,'Please report this error to mgs@io.harvard.edu. ' endif if(n_elements(wind) ge wnum) then begin wind(wnum) = 1 ; mark as occupied wbase(wnum) = base ; save base for Done_Event endif ; set window title title = title+':'+strtrim(wnum,2) widget_control,base,tlb_set_title=title ; the state structure contains ALL information ! state = { ids:[mainlist, xlist, ylist, bo], data:datastruc, $ fileinfo:fileinfo, plotinfo:plotinfo } ; enter the state as uvalue in the first child widget_control,widget_info(base,/child),set_uvalue=state ; and show the widget widget_control,base,/realize return end pro explore,filename,data=data,header=header,comments=comments, $ delim=delim,skp1=skp1,skp2=skp2,autoskip=autoskip, $ bw=bw,symsize=symsize ; common block holds pointers to data, header and comments for program exit common epointers,pdata,pheader,pcomments ; pre-compile some necessary routines resolve_routine,'w_calc',/is_function resolve_routine,'w_datatable',/is_function resolve_routine,'w_edit',/is_function resolve_routine,'w_fileopen',/is_function resolve_routine,'w_sort',/is_function ; global initialization (plot symbols etc.) global_init,bw=bw,symsize=symsize if(n_elements(comments) le 0) then comments='[%VARIABLE NAMES%]' if(n_elements(filename) le 0) then filename='' if(n_elements(data) gt 1 AND n_elements(header) gt 0) then begin datastruc = { data:data, header:header, $ select:-1, hidden:-1 } no_block = 0 endif else no_block = 1 if (n_elements(delim) eq 0) then delim = ' ' if (n_elements(skp1) eq 0) then skp1 = 1 if (n_elements(skp2) eq 0) then skp2 = 1 if (not keyword_set(autoskip)) then autoskip = 0 fileinfo = { filename:filename, comments:comments, delim:delim, $ skp1:skp1, skp2:skp2, autoskip:autoskip } if (filename ne '') then wtitle = filename else wtitle='EXPLORE' new_widget,base=base,title=wtitle,wnum=0,data=datastruc,fileinfo=fileinfo ; if filename was given, simulate READ_DATA event and force reading if (filename ne '') then begin Event = {ID:base, top:base, handler:base } ReadData_Event,Event,/force endif xmanager,'MAINL',base,NO_BLOCK=no_block ; retrieve data, header, and comments from pointers ; and free pointers if (ptr_valid(pdata)) then begin data = *pdata ptr_free,pdata endif if (ptr_valid(pheader)) then begin header = *pheader ptr_free,pheader endif if (ptr_valid(pcomments)) then begin comments = *pcomments ptr_free,pcomments endif end