;Widget control of calibrate 6262 PRO Cal6262_CalcFit,ptr ;Calculate statistics of the fit gd = where((*ptr).goodvals EQ 1b,ngd) IF ngd GT 2 THEN BEGIN x = ((*ptr).x)[gd] y = ((*ptr).y)[gd] co = poly_fit(x,y,1,/double) ma = co(1) ba = co(0) IF ma NE 0 THEN m = 1/ma ELSE m = nan() IF ma NE 0 THEN b = -ba/ma ELSE b = nan() n = n_elements(x) sigysq = (1./(n-2))*total((y-ba-ma*x)^2) delta = n*total(x^2)-(total(x))^2 sigbasq = sigysq*total(x^2)/delta sigmasq = n*sigysq/delta xbar = mean(x) ybar = mean(y) rsq = total((x-xbar)*(y-ybar))/sqrt(total(((x-xbar)^2)*total((y-ybar)^2))) extra = abs((max(x)-min(x))*.25) xev = (min(x)-extra)+(max(x)-min(x)+2*extra)*findgen(101)/100 yev = ma*xev+ba (*ptr).mandb = [ma,ba,m,b] (*ptr).stats = [sigmasq,sigbasq,sigysq,delta,n,rsq] (*ptr).xev = xev (*ptr).yev = yev ENDIF ELSE BEGIN (*ptr).mandb= [nan(),nan(),nan(),nan()] (*ptr).stats= [nan(),nan(),nan(),nan(),nan(),nan()] (*ptr).xev = replicate(nan(),101) (*ptr).yev = replicate(nan(),101) ENDELSE END PRO Cal6262_Setcolors,ptr ;Create an array to determine the colors of each data point usecolor = (*ptr).usecolor tm = (*ptr).tm IF (*ptr).usecolor EQ 0 THEN (*ptr).drawcolors = replicate(0,n_elements(tm)) ELSE BEGIN drawcolors = (*ptr).drawcolors hr = tm/60.0 drawcolors = (fix(fix(hr+0.001)/12)+((-1)*(hr LT 0)) + (!d.table_size-20)) > (!d.table_size-20-4) < (!d.table_size-20+5) (*ptr).drawcolors = drawcolors ENDELSE END PRO calplot_6262,doy,yr,kind,x,y,xev,yev,mandb,stats,goodflag,days=days,notext=notext,colors=colors ;Plot the actual data in the fit window ; mandb = [ma,ba,m,b] (y=mx+b) (legacy stats) ; stats = [sigmasq,sigbasq,sigysq,delta,n,rsq] ;get the ranges xmax = max(x,/nan) xmin = min(x,/nan) ymax = max(y,/nan) ymin = min(y,/nan) xrng = [(xmin-abs((xmax-xmin)*.05)),(xmax+abs((xmax-xmin)*.05))] yrng = [(ymin-abs((ymax-ymin)*.05)),(ymax+abs((ymax-ymin)*.05))] ; Get the appropriate subtitles for the plots if kind eq 'c' then begin subtitle1 = 'CO2' subtitle2 = '(c*(!4e!3/(!4e!3+r))-cref)' subtitle3 = 'V*(p0/p)' endif if kind eq 'q' then begin subtitle1 = 'H2O' subtitle2 = 'q*(!4e!3/(!4e!3+r))' subtitle3 = 'V*(p0/p)' endif ;plot the data and fit IF goodflag EQ 1 THEN gtitle = ' GOOD' ELSE gtitle = ' BAD' IF keyword_set(days) THEN dtitle = ' ('+strtrim(string(days,format='(i3)'),2)+' Days)' ELSE dtitle = '' IF NOT keyword_set(colors) THEN colors = intarr(n_elements(x)) plot,x,y,xrange = xrng,yrange = yrng,xtitle=subtitle2+'*(T0/T)',ytitle=subtitle3,title='Fit for Day '+string(doy,yr MOD 100,format='(i3.3," Year ",i2.2)')+dtitle+gtitle plots,x,y,psym = 2,color=colors oplot,xev,yev,thick = 3 IF NOT keyword_set(notext) THEN BEGIN ;write the stats xyouts,.2,.9,'ma = '+strtrim(string(mandb[0]),2),/normal xyouts,.2,.87,'ba = '+strtrim(string(mandb[1]),2),/normal xyouts,.2,.84,'m = '+strtrim(string(mandb[2]),2),/normal xyouts,.2,.81,'b = '+strtrim(string(mandb[3]),2),/normal xyouts,.2,.78,'rsq = '+strtrim(string(stats[5]),2),/normal xyouts,.7,.18,'n = '+strtrim(string(stats[4]),2),/normal xyouts,.7,.15,'sigmasq = '+strtrim(string(stats[0]),2),/normal xyouts,.7,.12,'sigbasq = '+strtrim(string(stats[1]),2),/normal ENDIF END PRO Cal6262_FitWin_draw,ptr ;Draw or redraw the fit window win = (*ptr).FitWinNum wset,win !p.multi = 0 gd = where((*ptr).goodvals EQ 1b,ngd) IF ngd GT 0 THEN calplot_6262,(*ptr).doy,(*ptr).yr,(*ptr).kind,((*ptr).x)[gd],$ ((*ptr).y)[gd],(*ptr).xev,(*ptr).yev,(*ptr).mandb,(*ptr).stats,(*ptr).goodflag,$ days=(*ptr).days,colors=((*ptr).drawcolors)[gd],/notext ELSE plot,[0,0],[0,0],title='No data' END PRO Cal6262_DataWin_draw,ptr ;Draw or redraw the time series data window win = (*ptr).DataWinNum wset,win !p.multi = 0 r = where((*ptr).goodvals EQ 1b,nr) b = where((*ptr).goodvals EQ 0b,nb) IF nr GT 0 THEN BEGIN tm = (*ptr).tm hr = tm/60.0 slow = (*ptr).slow v = (*ptr).v w = (*ptr).w pl = (*ptr).pl tl = (*ptr).tl kind = (*ptr).kind IF nb GT 0 THEN BEGIN slow[b] = nan() v[b] = nan() w[b] = nan() pl[b] = nan() tl[b] = nan() ENDIF ticklocs = where((hr MOD 12) EQ 0,nhr) IF nhr GT 2 THEN BEGIN xticks = nhr-1 xtickv = hr[ticklocs] xticklen = 1 ENDIF drawcolors = (*ptr).drawcolors if (kind eq 'c') then begin !p.multi=[0,1,6,0,0] plot,hr,slow,/ynozero,title = 'Profiler CO!D2',ytitle = 'CO2 (ppm)',xticks=xticks,xtickv=xtickv,xticklen=xticklen,/nodata plots,hr,slow,color=drawcolors plot,hr,v,/ynozero,title='Flux CO!D2 Voltage',ytitle = 'CO2 V (mV)',xticks=xticks,xtickv=xtickv,xticklen=xticklen,/nodata plots,hr,v,color=drawcolors plot,hr,w,/ynozero,title = 'H!D2!NO Mixing Ratio',ytitle = 'W (g/kg)',xticks=xticks,xtickv=xtickv,xticklen=xticklen,/nodata plots,hr,w,color=drawcolors plot,hr,pl,/ynozero,title='Licor Pressure',ytitle = 'PR (hPa)',xticks=xticks,xtickv=xtickv,xticklen=xticklen,/nodata plots,hr,pl,color=drawcolors plot,hr,tl,/ynozero,title='Licor Temperature',ytitle = 'T (C)',xtitle = 'Hours from state date (UTC)',xticks=xticks,xtickv=xtickv,xticklen=xticklen,/nodata plots,hr,tl,color=drawcolors endif if (kind eq 'q') then BEGIN !p.multi=[0,1,5,0,0] plot,hr,w,/ynozero,title = 'H!D2!NO Mixing Ratio',ytitle = 'g/kg',xticks=xticks,xtickv=xtickv,xticklen=xticklen,/nodata plots,hr,w,color=drawcolors plot,hr,v,/ynozero,title='Flux H!D2!NO Voltage',ytitle = 'mV',xticks=xticks,xtickv=xtickv,xticklen=xticklen,/nodata plots,hr,v,color=drawcolors plot,hr,pl,/ynozero,title='Licor Pressure',ytitle = 'hPa',xticks=xticks,xtickv=xtickv,xticklen=xticklen,/nodata plots,hr,pl,color=drawcolors plot,hr,tl,/ynozero,title='Licor Temperature',ytitle = 'C',xtitle = 'Hours from start date (UTC)',xticks=xticks,xtickv=xtickv,xticklen=xticklen,/nodata plots,hr,tl,color=drawcolors ENDIF mandb = (*ptr).mandb stats = (*ptr).stats xyouts,.2,.8/6.,'ma = '+strtrim(string(mandb[0]),2),/normal,charsize=1 xyouts,.2,.6/6.,'ba = '+strtrim(string(mandb[1]),2),/normal,charsize=1 xyouts,.2,.4/6.,'m = '+strtrim(string(mandb[2]),2),/normal,charsize=1 xyouts,.2,.2/6.,'b = '+strtrim(string(mandb[3]),2),/normal,charsize=1 xyouts,.6,.8/6.,'rsq = '+strtrim(string(stats[5]),2),/normal,charsize=1 xyouts,.6,.6/6.,'n = '+strtrim(string(stats[4]),2),/normal,charsize=1 xyouts,.6,.4/6.,'sigmasq = '+strtrim(string(stats[0]),2),/normal,charsize=1 xyouts,.6,.2/6.,'sigbasq = '+strtrim(string(stats[1]),2),/normal,charsize=1 !p.multi=0 ENDIF ELSE plot,[0,0],[0,0],title='No good data' END ;EVENT HANDLERS PRO Cal6262_Slider_Event,event ;Changing slider changes fuzzy tolerance WIDGET_CONTROL, event.top, GET_UVALUE = ptr (*ptr).fuzzytol = float(event.value) END PRO Cal6262_Checkbox_event,event ;If checkbox changes, turn color on or off WIDGET_CONTROL, event.top, GET_UVALUE = ptr IF event.select EQ 0 THEN (*ptr).usecolor = 0 ELSE (*ptr).usecolor = 1 Cal6262_Setcolors,ptr Cal6262_FitWin_draw,ptr Cal6262_DataWin_draw,ptr END PRO Cal6262_DataWin_event,event ;Clicking in the data window removes datapoints IF event.release EQ 1 THEN BEGIN WIDGET_CONTROL, event.top, GET_UVALUE = ptr tm = (*ptr).tm hr = tm / 60.0 goodvals = (*ptr).goodvals r = where(goodvals EQ 1b,nr) Cal6262_DataWin_draw,ptr xcoord = event.x ycoord = event.y dataloc = convert_coord(event.x,event.y,/device,/to_data) xbad = dataloc[0] tokill = abs(xbad-hr) LT ((*ptr).fuzzytol/5.0) wheretk = where(tokill,nwm) IF nwm GT 0 THEN BEGIN ;push current state onto the undo stack undovals = (*ptr).undovals undovals[*,1:9] = undovals[*,0:8] undovals[*,0] = (*ptr).goodvals (*ptr).undovals = undovals goodvals[wheretk] = 0 (*ptr).goodvals = goodvals Cal6262_CalcFit,ptr Cal6262_FitWin_draw,ptr Cal6262_DataWin_draw,ptr ENDIF ENDIF END PRO Cal6262_FitWin_event,event ;Clicking in the fit window removes data points IF event.release EQ 1 THEN BEGIN WIDGET_CONTROL, event.top, GET_UVALUE = ptr x = (*ptr).x y = (*ptr).y goodvals = (*ptr).goodvals r = where(goodvals EQ 1b,nr) Cal6262_FitWin_draw,ptr xcoord = event.x ycoord = event.y dataloc = convert_coord(event.x,event.y,/device,/to_data) xbad = dataloc[0] ybad = dataloc[1] tokill = sqrt((xbad-x)^2 + (ybad-y)^2) LT (*ptr).fuzzytol wheretk = where(tokill,nwm) IF nwm GT 0 THEN BEGIN ;push current state onto the undo stack undovals = (*ptr).undovals undovals[*,1:9] = undovals[*,0:8] undovals[*,0] = (*ptr).goodvals (*ptr).undovals = undovals goodvals[wheretk] = 0 (*ptr).goodvals = goodvals Cal6262_CalcFit,ptr Cal6262_FitWin_draw,ptr Cal6262_DataWin_draw,ptr ENDIF ENDIF END PRO Cal6262_base_event, event ;Deal with button and base-resizing events WIDGET_CONTROL, event.id, GET_UVALUE = aptr whichevent = (*aptr).myname CASE whichevent OF 'THEBUTTON' : BEGIN CASE EVENT.VALUE OF ;Accept 0: BEGIN WIDGET_CONTROL, EVENT.TOP, GET_UVALUE = PTR rjc = 1 IF abs((*ptr).stats[5]) LT 0.8 THEN BEGIN dlg = '' dlg = dialog_message('Correlation is low. Are you sure you want to accept?',/default_no,/question,title='Accept',dialog_parent=event.top) IF dlg EQ 'No' THEN rjc = 0 ENDIF IF rjc EQ 1 THEN BEGIN (*PTR).GOODFLAG = 1 (*ptr).cancelflag = 0 WIDGET_CONTROL, EVENT.TOP, /DESTROY ENDIF END ;Reject 1: BEGIN WIDGET_CONTROL, EVENT.TOP, GET_UVALUE = PTR rjc = 1 IF abs((*ptr).stats[5]) GT 0.9 THEN BEGIN dlg = '' dlg = dialog_message('Correlation is high. Are you sure you want to reject?',/default_no,/question,title='Reject',dialog_parent=event.top) IF dlg EQ 'No' THEN rjc = 0 ENDIF IF rjc EQ 1 THEN BEGIN (*PTR).GOODFLAG = 0 (*ptr).cancelflag = 0 WIDGET_CONTROL, EVENT.TOP, /DESTROY ENDIF END ;Reset 2: BEGIN WIDGET_CONTROL, EVENT.TOP, GET_UVALUE = PTR undovals = (*ptr).undovals undovals[*,1:9] = undovals[*,0:8] undovals[*,0] = (*ptr).goodvals (*ptr).undovals = undovals (*PTR).GOODVALS = (*PTR).OLDGOODVALS Cal6262_CalcFit,ptr CAL6262_FITWIN_DRAW,PTR cal6262_datawin_draw,ptr END ;Undo 3: BEGIN WIDGET_CONTROL, EVENT.TOP, GET_UVALUE = PTR ;pop most recent undo state undovals = (*ptr).undovals (*PTR).GOODVALS = undoVALS[*,0] undovals[*,0:8] = undovals[*,1:9] (*ptr).undovals = undovals Cal6262_CalcFit,ptr CAL6262_FITWIN_DRAW,PTR cal6262_datawin_draw,ptr END ;Cancel 4: BEGIN WIDGET_CONTROL, EVENT.TOP, GET_UVALUE = PTR (*PTR).cancelFLAG = 1 WIDGET_CONTROL, EVENT.TOP, /DESTROY END ENDCASE END 'THEBASE' : BEGIN ;If base window resizes, then change the draw window size fitwin = (*aptr).fitwin datawin = (*aptr).datawin fitwinx = (*aptr).fitwinx fitwiny = (*aptr).fitwiny datawinx = (*aptr).datawinx datawiny = (*aptr).datawiny oldsize = (*aptr).winsize newsize = float([event.x,event.y]) (*aptr).winsize = newsize basexchange = newsize[0]-oldsize[0] baseychange = newsize[1]-oldsize[1] fitwinx = fitwinx + (basexchange/2.0) fitwiny = fitwiny + (baseychange) datawinx = datawinx + (basexchange/2.0) datawiny = datawiny + (baseychange) (*aptr).fitwinx = fitwinx (*aptr).fitwiny = fitwiny (*aptr).datawinx = datawinx (*aptr).datawiny = datawiny widget_control,fitwin,draw_xsize=fitwinx,draw_ysize=fitwiny widget_control,datawin,draw_xsize=datawinx,draw_ysize=datawiny,xoffset=fitwinx CAL6262_FITWIN_DRAW,aPTR cal6262_datawin_draw,aptr END ENDCASE END PRO Cal6262_base_kill_event,wid ;Check to see if user kills widget without pressing one of the buttons WIDGET_CONTROL, wid, GET_UVALUE = PTR IF (*ptr).cancelflag EQ 3 THEN (*PTR).cancelflag = 1 END PRO CalWidget,doy,yr,kind,tm,x,y,slow,v,w,pl,tl,goodflag=goodflag,mandb=mandb,stats=stats,xft=xft,yft=yft,xev=xev,yev=yev,goodvals=goodvals,days=days,cancelflag=cancelflag,nocolor=nocolor ;MAIN CALIBRATION WIDGET PROGRAM ;Creates the widget to run the calibration code ;This function is called by calfit_6262 in calibrate.pro ;Input variables: ;doy = Day of Year (just for the title) ;yr = Year (4 or 2 digit) ;kind = 'c' for CO2, 'q' for H2O ;tm = array of time for each point (minutes into day DOY - can be negative) ;x = array of x data (slow data muliplied by water vapor and temperature corrections) ;y = array of y data (averaged pressure corrected licor voltages) ;where: eps = 18.016/28.97 ; x = (slow*(eps/(eps+w/1000))-ref)*tref/(tl+273.15) ; y = v*pref/pl ;slow = actual slow data (co2 or mixing ratio) ;v = actual uncorrected licor voltages ;w = h2o mixing ratio ;pl = licor pressure ;tl = licor temp ;Data can have badvals - badval for Sylvania is nan() ;days = number of days we are calibrating on ;nocolor = use black and white ;Output variables: ;goodflag = user pressed the Accept fit button then this is true ;cancelflag = user pressed the cancel button ;mandb = [ma,ba,m,b] fits y = ma*x+ba, m = 1 / ma and b = -ba/ma ;stats = [sigmasq,sigbasq,sigysq,delta,n,rsq] ;xft,yft = good x and y values to be fitted ;xev,yev = best line through x and y ;goodvals = array that = 1 where x and y are good (not badval), 0 otherwise ;PART 1. Set up our widget ;Base Window IF kind EQ 'c' THEN title = 'CO2 Calibration' ELSE title = 'H2O Calibration' Base = WIDGET_BASE(TITLE = title, GROUP_LEADER=GROUP_ID, /tlb_size_events,xoffset=50,yoffset=100,kill_notify='Cal6262_base_kill_event') ;Button Group btndata = {myname:'THEBUTTON'} btnptr = PTR_NEW(btndata,/NO_COPY) menu = Cw_Bgroup( Base, ['Accept', 'Reject', 'Reset','Undo', 'Cancel'], /row, IDS=IDS, UVALUE=btnptr) ;Fuzzy tolerance slider fuzzytol = float(co2_const('fuzzytol')) slider = widget_slider(Base,event_pro='Cal6262_slider_event',maximum=300,minimum=1,xoffset=300,yoffset=0,title='Fuzzy Tolerance',value=fuzzytol) ;Color checkbox checkboxbase = widget_base(base,xoffset=500,yoffset=0,/nonexclusive) checkbox = widget_button(checkboxbase,value='Color',event_PRO='Cal6262_checkbox_event') ;Calibration fit window fitwinx = 450 fitwiny = 450 fitwin = widget_draw(Base,/button_events,event_PRO='Cal6262_FitWin_event',xsize=fitwinx,ysize=fitwiny,xoffset=0,yoffset=50) ;Calibration data window datawinx = fitwinx datawiny = fitwiny datawin = widget_draw(Base,event_PRO='Cal6262_DataWin_event',xsize=datawiny,ysize=datawinx,xoffset=fitwinx,yoffset=50,/button_events) ;PART 2. Set up the data variables IF NOT keyword_set(days) THEN days = fix(1) IF NOT keyword_set(goodflag) THEN goodflag = 0b mandb= [nan(),nan(),nan(),nan()] stats= [nan(),nan(),nan(),nan(),nan(),nan()] xev = replicate(nan(),101) yev = replicate(nan(),101) winsize = [nan(),nan()] IF NOT keyword_set(goodvals) THEN goodvals = (isnotnan(x) AND isnotnan(y)) ;Setup flags and multiple undo oldgoodvals = goodvals cancelflag = 3b IF keyword_set(nocolor) THEN usecolor = 0b ELSE usecolor = 1b undovals = reform(replicate_arr(goodvals,10),n_elements(goodvals),10) drawcolors = intarr(n_elements(tm)) ;Create a pointer to a structure containing all the info for widget events dta = {myname: 'THEBASE', FitWinNum:0, DataWinNum:0, FitWin:FitWin, DataWin:DataWin, Fitwinx:fitwinx, FitWiny:fitwiny, datawinx:datawinx, $ datawiny:datawiny, winsize:winsize, kind:kind, x:x, y:y, slow:slow, v:v, w:w, pl:pl, tl:tl, mandb:mandb, stats:stats, xev:xev, yev:yev, $ goodvals:goodvals, undovals:undovals, oldgoodvals: oldgoodvals, days:fix(days), doy:float(doy), yr:float(yr), tm:float(tm), goodflag:goodflag, $ fuzzytol:float(fuzzytol), cancelflag:cancelflag, usecolor:usecolor, drawcolors:drawcolors} ptrdta = PTR_NEW(dta,/NO_COPY) ;Calculate initial fit - this routine calculates the actual fit given data Cal6262_CalcFit,ptrdta ;PART 3. Start the widget! ;Setup Colors loadct,0 !p.background=255 !p.color=0 !x.style=1 !y.style=1 col1 = fsc_color("Light Cyan",!d.table_size-20-4) col2 = fsc_color("Brown",!d.table_size-20-3) col3 = fsc_color("Green",!d.table_size-20-2) col4 = fsc_color("Orange",!d.table_size-20-1) col5 = fsc_color("Blue",!d.table_size-20+0) col6 = fsc_color("Red",!d.table_size-20+1) col7 = fsc_color("Cyan",!d.table_Size-20+2) col8 = fsc_color("Magenta",!d.table_size-20+3) col9 = fsc_color("Yellow",!d.table_size-20+4) col10 = fsc_color("Maroon",!d.table_size-20+5) Cal6262_setcolors,ptrdta ;Realize widget WIDGET_CONTROL, Base,set_uvalue=ptrdta WIDGET_CONTROL, Base, /REALIZE ;Find the window numbers of the draw windows and base size and set checkbox WIDGET_CONTROL, FitWin, GET_VALUE = FitWinNum WIDGET_CONTROL, DataWin, GET_VALUE = DataWinNum (*ptrdta).FitWinNum = FitWinNum (*ptrdta).DataWinNum = DataWinNum widget_control,Base,tlb_get_Size=origsize (*ptrdta).winsize = origsize WIDGET_CONTROL, checkbox, SET_BUTTON = (*ptrdta).usecolor ;Draw the original data Cal6262_FitWin_Draw,ptrdta Cal6262_DataWin_Draw,ptrdta ;Run Xmanager - Now the widge starts running and calling event handlers XManager, "Cal6262_base", Base ;PART 4. Clean up and get return values ;Get the return values goodflag=(*ptrdta).goodflag cancelflag = (*ptrdta).cancelflag mandb=(*ptrdta).mandb stats=(*ptrdta).stats xev = (*ptrdta).xev yev = (*ptrdta).yev goodvals = (*ptrdta).goodvals gd = where(goodvals EQ 1,ng) IF ng GT 0 THEN BEGIN xft = ((*ptrdta).x)[gd] yft = ((*ptrdta).y)[gd] ENDIF ELSE BEGIN xft = nan() yft = nan() plotflag = 0b goodflag = 0b ENDELSE ;Put the colors back loadct,0 !p.background=255 !p.color=0 !p.multi = 0 ;Destroy pointers ptr_free,btnptr ptr_free,ptrdta END PRO start_calwid ;Some test code to run with calwidget just to see if it works ;normally calfit would set this up and call calwidget kind = 'c' x = ((randomu(100,100)*1000.0)/3.0)+200.0 y = (x+(randomu(200,100)*1000.0))*2.0 slow = randomu(300,100) v = randomu(400,100) w = randomu(500,100) pl = randomu(600,100) tl = randomu(700,100) tm = (findgen(100)-30.0)*28.0 calwidget,330.0,2002.0,kind,tm,x,y,slow,v,w,pl,tl,days=1,stats=s,mandb=m,goodflag=g print,g print,s print,m END