#pragma rtGlobals=1 // Use modern global access method. #pragma version=2.00 // 2.00 // 1/2/15 made it work for X-Y data // added wave notes to output waves // 1.50 // finally fixed offsets // 1.22 // fixed offset calculation // 1.21 // 12/10/09 // 1.20 // 6/24/08 // line between cursors // 1.12 // 6/9/08 // 1.11 // 9/12/07 // 1.10 // 7/23/07 added smoothed spline baseline // 1.00 // 7/3/07 Menu "GraphMarquee" submenu "Baselines" "Initialise...", /Q, MenuInitBaselineFitting() FitMenu("Add Region to Fit"), /Q, GetMarquee /K bottom; ResetFitRegion(V_left, V_right, 1) FitMenu("Remove Region From Fit"), /Q, GetMarquee /K bottom; ResetFitRegion(V_left, V_right, 0) FitMenu("Clear All Fit Regions"), /Q, ClearFitRegion() "Clear Everything", /Q, ClearEverything() submenu "fit" FitMenu("line"), /Q, MenuFitBaseline() FitMenu("poly 3"), /Q, MenuFitBaseline() FitMenu("poly 4"), /Q, MenuFitBaseline() FitMenu("gauss"), /Q, MenuFitBaseline() FitMenu("lor"), /Q, MenuFitBaseline() FitMenu("exp"), /Q, MenuFitBaseline() FitMenu("gauss3"), /Q, MenuFitBaseline() FitMenu("sin"), /Q, MenuFitBaseline() FitMenu("sigmoid"), /Q, MenuFitBaseline() FitMenu("spline"), /Q, MenuFitBaseline() FitMenu("line between cursors"), /Q, MenuFitBaseline() // "exp_XOffset", /Q, MenuFitBaseline() // "dblexp_XOffset", /Q, MenuFitBaseline() end FitMenu("Subtract Baseline"), /Q, MenuSubtractBaseline() end End Menu "TracePopup" submenu "Baselines" "Initialise...", /Q, MenuInitBaselineFitting() "Clear Everything", /Q, ClearEverything() submenu "fit" FitMenu("line"), /Q, MenuFitBaseline() FitMenu("poly 3"), /Q, MenuFitBaseline() FitMenu("poly 4"), /Q, MenuFitBaseline() FitMenu("gauss"), /Q, MenuFitBaseline() FitMenu("lor"), /Q, MenuFitBaseline() FitMenu("exp"), /Q, MenuFitBaseline() FitMenu("gauss3"), /Q, MenuFitBaseline() FitMenu("sin"), /Q, MenuFitBaseline() FitMenu("sigmoid"), /Q, MenuFitBaseline() FitMenu("spline"), /Q, MenuFitBaseline() FitMenu("line between cursors"), /Q, MenuFitBaseline() // "exp_XOffset", /Q, MenuFitBaseline() // "dblexp_XOffset", /Q, MenuFitBaseline() end FitMenu("Subtract Baseline"), /Q, MenuSubtractBaseline() end End Menu "AllTracesPopup" submenu "Fit baseline to all traces on plot" "line", /Q, FitAllTraces() "poly 3", /Q, FitAllTraces() "poly 4", /Q, FitAllTraces() "gauss", /Q, FitAllTraces() "lor", /Q, FitAllTraces() "exp", /Q, FitAllTraces() "gauss3", /Q, FitAllTraces() "sin", /Q, MenuFitBaseline() "sigmoid", /Q, MenuFitBaseline() "spline", /Q, FitAllTraces() "line between cursors", /Q, FitAllTraces() // "exp_XOffset", /Q, MenuFitBaseline() // "dblexp_XOffset", /Q, MenuFitBaseline() end end Menu "Macros" submenu "Baselines" "Initialise...", /Q, MenuInitBaselineFitting() "Clear Everything", /Q, ClearEverything() FitMenu("Add Region to Fit"), /Q, AddRegionToFit() FitMenu("Remove Region From Fit"), /Q, GetMarquee /K bottom; ResetFitRegion(V_left, V_right, 0) FitMenu("Clear All Fit Regions"), /Q, ClearFitRegion() submenu "fit" FitMenu("line"), /Q, MenuFitBaseline() FitMenu("poly 3"), /Q, MenuFitBaseline() FitMenu("poly 4"), /Q, MenuFitBaseline() FitMenu("gauss"), /Q, MenuFitBaseline() FitMenu("lor"), /Q, MenuFitBaseline() FitMenu("exp"), /Q, MenuFitBaseline() FitMenu("gauss3"), /Q, MenuFitBaseline() FitMenu("sin"), /Q, MenuFitBaseline() FitMenu("sigmoid"), /Q, MenuFitBaseline() FitMenu("spline"), /Q, MenuFitBaseline() FitMenu("line between cursors"), /Q, MenuFitBaseline() // "exp_XOffset", /Q, MenuFitBaseline() // "dblexp_XOffset", /Q, MenuFitBaseline() end FitMenu("Subtract Baseline"), /Q, MenuSubtractBaseline() end end Function/S FitMenu(str) string str SVAR S_dataWave= root:Packages:Baselines:BaselineFitDataWaveName if (SVAR_exists(S_dataWave)) if (strlen(S_dataWave)) // initialised; allow all menu items return str endif endif // not initialised string menuList="line;poly 3;poly 4;gauss;lor;exp;gauss3;sin;sigmoid;spline;line between cursors;" menulist += "Add Region to Fit;Remove Region From Fit;Clear All Fit Regions;Subtract Baseline" if (WhichListItem(str, menuList)> -1) return "" endif return str end // a wrapper function for InitBaselineFit function MenuInitBaselineFitting() // need to select data wave string strDataTrace if (wintype("")!=1) doalert 0, "Oops: target wave must be plotted in a graph window\rto initialise baseline fitting" return 0 endif prompt strDataTrace, "Data Wave", popup, TraceNameList("", ";", 1) doPrompt "Initialise Baseline Fit", strDataTrace if (V_flag) return 0 endif wave W_data=TraceNameToWaveRef("", strDataTrace ) wave W_Xwave=XWaveRefFromTrace("", strDataTrace) // null if not X-Y InitBaselineFitting(W_data, W_x=W_Xwave) end function AddRegionToFit() GetMarquee /K bottom if (V_flag) ResetFitRegion(V_left, V_right, 1) else DoAlert 0, "drag to select region on graph" endif end // value = 1 to include, 0 to exclude. function ResetFitRegion(V_left, V_right, value) variable V_left, V_right, value wave W_mask=root:Packages:Baselines:W_mask if (waveexists(W_mask)==0) return 0 endif NVAR isXY=root:Packages:Baselines:isXY if (isXY) SVAR wname=root:Packages:Baselines:BaselineFitXWaveName wave w_x=$wname endif SVAR wname=root:Packages:Baselines:BaselineFitDataWaveName wave W_data=$wname wave W_display=root:Packages:Baselines:W_display variable p_low, p_high, p_left, p_right if (isXY) variable xmax=wavemax(w_x) variable xmin=wavemin(w_x) v_left=min(v_left,xmax) v_left=max(v_left,xmin) v_right=min(v_right,xmax) v_right=max(v_right,xmin) findlevel /Q/P w_x, v_left if (v_flag) print "baseline error: problem with findlevel" return 0 endif p_left=V_LevelX findlevel /Q/P w_x, v_right if (v_flag) print "baseline error: problem with findlevel" return 0 endif p_right=V_LevelX p_low=min(p_left, p_right) p_high=max(p_left, p_right) else p_low=min(x2pnt(W_data,V_left), x2pnt(W_data,V_right)) p_high=max(x2pnt(W_data,V_left), x2pnt(W_data,V_right)) endif W_mask[p_low, p_high]=value W_display = W_mask[p] ? W_data[p] : NaN printf "ResetFitRegion(%d, %d, %d)\r", V_left, V_right, value end function ClearFitRegion() wave W_mask=root:Packages:Baselines:W_mask wave W_display=root:Packages:Baselines:W_display W_mask=0 W_display=nan end function ClearEverything() SVAR s_targetGraph=root:Packages:Baselines:s_targetGraph string s_win="" if (SVAR_exists(s_targetGraph)) s_win=s_targetGraph dowindow /f $s_targetGraph else s_win=winname(0,1) doalert 1, "Remove any baseline paraphernalia from "+s_win+"?" if (V_flag==2) return 0 endif endif RemoveBaselineWaves(s_win) // delete some stuff wave W_mask=root:Packages:Baselines:W_mask if (waveexists(W_mask)) KillWaves /Z root:Packages:Baselines:W_mask, root:Packages:Baselines:W_base KillWaves /Z root:Packages:Baselines:W_NoBase, root:Packages:Baselines:W_display KillStrings /Z root:Packages:Baselines:BaselineFitDataWaveName KillStrings /Z root:Packages:Baselines:BaselineFitXWaveName endif if (SVAR_exists(s_targetGraph)) s_targetGraph="" endif buildmenu "macros" buildmenu "GraphMarquee" buildmenu "TracePopup" end // set the data wave (raw spectrum from which baseline is to be subtracted) function InitBaselineFitting(w, [w_x]) wave w, w_x NewDataFolder /O root:Packages NewDataFolder /O root:Packages:Baselines String /G root:Packages:Baselines:s_targetGraph SVAR s_targetGraph=root:Packages:Baselines:s_targetGraph string s_win=WinName(0,1) if (SVAR_exists(s_targetGraph)) if (strlen(s_targetGraph) && !stringmatch(s_win, s_targetGraph)) // remove our stuff from old target graph RemoveBaselineWaves(s_targetGraph) print "Removed baseline traces from " + s_targetGraph endif endif s_targetGraph=s_win String /G root:Packages:Baselines:BaselineFitDataWaveName=GetWavesDataFolder(w, 2) variable /G root:Packages:Baselines:v_multifit=0 variable /G root:Packages:Baselines:isXY=waveexists(w_x) nvar isXY=root:Packages:Baselines:isXY if (isXY) String /G root:Packages:Baselines:BaselineFitXWaveName=GetWavesDataFolder(w_x, 2) else KillStrings /Z root:Packages:Baselines:BaselineFitXWaveName endif // clean waves from graph RemoveBaselineWaves(s_targetGraph) duplicate /O w root:Packages:Baselines:W_Display wave W_display=root:Packages:Baselines:W_display // don't reset the mask wave if new data wave has same length as previous one // in case we want to apply the same fit to many spectra wave W_mask=root:Packages:Baselines:W_mask if (waveexists(W_mask)) if (numpnts(W_mask)!=numpnts(W_display)) duplicate /O w root:Packages:Baselines:W_mask W_mask=0 W_display=nan endif else duplicate /O w root:Packages:Baselines:W_Mask wave W_mask=root:Packages:Baselines:W_mask W_mask=0 endif W_display = W_mask[p] ? w[p] : NaN if (isXY) appendtograph /W=$s_targetGraph W_display vs w_x else appendtograph /W=$s_targetGraph W_display endif ModifyGraph /W=$s_targetGraph mode(W_display)=7,hbFill(W_display)=4 ModifyGraph /W=$s_targetGraph rgb(W_display)=(24576,24576,65280) // preserve offsets variable DataOffsetX=0,DataOffsetY=0 string infostr=TraceInfo("", nameofwave(w), 0 ) infostr = GrepList(infostr, "offset", 0,";") infostr=StringFromList(0, infostr,";") sscanf infostr, "offset(x)={%g,%g}", DataOffsetX,DataOffsetY ModifyGraph /W=$s_targetGraph offset(W_display)={DataOffsetX,DataOffsetY} duplicate /O w root:Packages:Baselines:W_Base wave W_base=root:Packages:Baselines:W_base W_base=nan if (isXY) appendtograph /W=$s_targetGraph W_Base vs w_x else appendtograph /W=$s_targetGraph W_Base endif ModifyGraph /W=$s_targetGraph rgb(W_Base)=(0,15872,65280) ModifyGraph /W=$s_targetGraph offset(W_Base)={DataOffsetX,DataOffsetY} duplicate /O w root:Packages:Baselines:W_NoBase wave W_NoBase=root:Packages:Baselines:W_NoBase W_NoBase=nan if (isXY) appendtograph /W=$s_targetGraph W_NoBase vs w_x else appendtograph /W=$s_targetGraph W_NoBase endif ModifyGraph /W=$s_targetGraph rgb(W_NoBase)=(0,0,0) variable /G root:Packages:Baselines:V_smooth NVAR V_smooth=root:Packages:Baselines:V_smooth V_smooth+=0.5*(V_smooth==0) if (isXY) printf "InitBaselineFitting(%s, W_x=%s)\r", nameofwave(w), nameofwave(w_x) else printf "InitBaselineFitting(%s)\r", nameofwave(w) endif buildmenu "macros" buildmenu "GraphMarquee" buildmenu "TracePopup" end function RemoveBaselineWaves(s_targetGraph) string s_targetGraph do // remove all instances of w_display removefromgraph /W=$s_targetGraph/Z W_display checkdisplayed /W=$s_targetGraph W_display while (V_flag) do // remove all instances of w_base removefromgraph /W=$s_targetGraph/Z W_base checkdisplayed /W=$s_targetGraph W_base while (V_flag) do // remove all instances of W_NoBase removefromgraph /W=$s_targetGraph/Z W_NoBase checkdisplayed /W=$s_targetGraph W_NoBase while (V_flag) KillControl /W=$s_targetGraph SplineSmoothSetVar Cursor /K /W=$s_targetGraph I Cursor /K /W=$s_targetGraph J // remove hook in case we were fitting to cursors SetWindow $s_targetGraph hook=$"" end // wrapper function to subtract the current fit from the data wave function MenuSubtractBaseline() SVAR wname=root:Packages:Baselines:BaselineFitDataWaveName wave W_data=$wname SubtractBaseline(W_data) end // subtract current baseline from W_data function SubtractBaseline(W_data) wave W_data SVAR s_targetGraph=root:Packages:Baselines:s_targetGraph NVAR multifit=root:Packages:Baselines:v_multifit wave W_base=root:Packages:Baselines:W_base if(numpnts(W_base)!=numpnts(W_data)) if (multifit) print nameofwave(W_data) +" and baseline have different length" else doalert 0, nameofwave(W_data) +" and baseline have different length" ClearEverything() endif return 0 endif // save a copy of the baseline string strNewName=CleanupName( nameofwave(W_data)+"_BL",0) if (exists(strNewName)) doalert 1, strNewName+" exists. Overwrite?" if(V_flag==2) return 0 endif endif duplicate /o W_base $strNewName wave newbase= $strNewName newbase=W_base // subtract baseline strNewName=CleanupName( nameofwave(W_data)+"_Sub",0) if (exists(strNewName)) doalert 1, strNewName+" exists. Overwrite?" if(V_flag==2) return 0 endif endif duplicate /o W_data $strNewName wave subtracted= $strNewName subtracted=W_data-W_base print "SubtractBaseline("+nameofwave(W_data)+")" note subtracted, note(W_base) // append note from baseline wave to output wave note KillControl /W=$s_targetGraph SplineSmoothSetVar // uncomment if you don't wish to continue to allow fitting // SVAR s_Dataname=root:Packages:Baselines:BaselineFitDataWaveName // s_Dataname="" checkdisplayed /W=$s_targetGraph subtracted if (V_flag) return 1 else nvar isXY=root:Packages:Baselines:isXY if (isXY) svar s_Xname=root:Packages:Baselines:BaselineFitXWaveName wave w_x=$s_Xname appendtograph /W=$s_targetGraph subtracted vs w_x else appendtograph /W=$s_targetGraph subtracted endif ModifyGraph /W=$s_targetGraph rgb($nameofwave(subtracted))=(0,0,0) endif end // wrapper function to start baseline fit of type defined by menu item function MenuFitBaseline() SVAR wname=root:Packages:Baselines:BaselineFitDataWaveName wave w=$wname GetLastUserMenuInfo printf "FitBaseline(%s, \"%s\")\r", nameofwave(w), S_value FitBaseline(w, S_value) end // fit a baseline defined by type to the data wave W_data using predefined mask wave // this function allows batch fitting from the command line function FitBaseline(W_data, type) wave w_data string type SVAR s_targetGraph=root:Packages:Baselines:s_targetGraph if (SVAR_exists(s_targetGraph)==0) return 0 endif wave W_Base=root:Packages:Baselines:W_Base wave W_display=root:Packages:Baselines:W_display wave W_mask=root:Packages:Baselines:W_mask wave W_noBase=root:Packages:Baselines:W_noBase if (wavemin(w_mask)==0 && wavemax(w_mask)==0) doalert 0, "No fit region selected. Select fit region using graph marquee\rand add region to fit before fitting baseline." return 0 endif nvar isXY=root:Packages:Baselines:isXY if(isXY) svar s_Xname=root:Packages:Baselines:BaselineFitXWaveName wave w_x=$s_Xname endif string s_log=type if (stringmatch(type, "spline")) // remove hook in case we were fitting to cursors SetWindow $s_targetGraph hook=$"" W_display = W_mask[p] ? W_data[p] : NaN // reset W_display in case we're batch fitting NVAR V_smooth=root:Packages:Baselines:V_smooth if (isXY) duplicate /o w_x root:Packages:Baselines:w_splineX wave w_splineX=root:Packages:Baselines:w_splineX interpolate2/T=3/I=3/F=(V_smooth)/X=w_splineX/Y=W_Base w_x, W_display else interpolate2/T=3/I=3/F=(V_smooth)/Y=root:Packages:Baselines:W_Base root:Packages:Baselines:W_display endif SetVariable SplineSmoothSetVar title="Smoothing", pos={200,100}, size={100,16} SetVariable SplineSmoothSetVar labelBack=(65535,65535,65535) SetVariable SplineSmoothSetVar limits={0,1e6,0.1 }, value=root:Packages:Baselines:V_smooth SetVariable SplineSmoothSetVar proc=BL_SplineSetVarProc elseif(stringmatch(type, "line between cursors")) // remove the spline smoothing control in case previous fit was a spline KillControl SplineSmoothSetVar variable Yval if ( strlen(CsrWave(J))==0 ) getaxis /W=$s_targetGraph /Q bottom Yval=w_data(V_max) if (numtype(Yval)) getaxis /W=$s_targetGraph/Q left Yval=(V_max-V_min)/2 endif cursor /W=$s_targetGraph J $nameofwave(w_data) V_max //, w_data(V_max) else cursor /W=$s_targetGraph J $nameofwave(w_data) hcsr(J) endif if ( strlen(CsrWave(I))==0 ) getaxis /W=$s_targetGraph /Q bottom Yval=w_data(V_min) if (numtype(Yval)) getaxis /W=$s_targetGraph/Q left Yval=(V_max-V_min)/2 endif cursor /W=$s_targetGraph I $nameofwave(w_data) V_min //, Yval else cursor /W=$s_targetGraph I $nameofwave(w_data) hcsr(I) endif SetWindow $s_targetGraph hook=UpdateBaselineBetweenCursors, hookEvents=2^2 UpdateBaselineBetweenCursors("") return 1 // note was reset by UpdateBaselineBetweenCursors() else // remove the spline smoothing control in case previous fit was a spline KillControl /W=$s_targetGraph SplineSmoothSetVar // remove hook in case we were fitting to cursors SetWindow $s_targetGraph hook=$"" string s_hold="" if (stringmatch(type, "gauss3")) s_hold="/H=\"1000\"" type="gauss" execute /Q "K0 = 0" endif string cmd="" variable i wave w_mask=root:Packages:Baselines:W_mask variable mask1=0 for(i=0;i