FitMySpectrum
olelytken  December 3, 2017  23:56  

Right now you are overwriting your A1, A2 and fitdata waves every time FitMySpectrum is called, and FitMySpectrum is called once for every data point in your wave for every iteration of your fit. You need to create those waves outside the for loop and store the fit results after the FuncFit call, but inside the loop. You also seem to start the for loop twice... You also need to declare the wave you want to fit using [ last edited December 3, 2017  23:59 ]

HJDrescher  December 4, 2017  01:08  

Plus you call your fitfunction from its inside... (VERY rare) Try to get single tasks working one by one. Start with the fit function, add the displaying of the raw data, do manual fitting, store the coefficients, put this in loops, append the fits, and list the coefficients. 
December 4, 2017  09:58  

Just to be clear, the fitFunc function is only to compute a model value. It is called by Igor during iterations during the call to FuncFit. You are trying to add code to the fitting function that belongs in a separate function. You need a driver function that looks up the wave with the data in it and loops over the columns, calling FuncFit. The loop in your code needs to be put into a separate function, and then you would call that function. John Weeks 
Tika  December 4, 2017  10:18  

You are trying to add code to the fitting function that belongs in a separate function. You need a driver function that looks up the wave with the data in it and loops over the columns, calling FuncFit. The loop in your code needs to be put into a separate function, and then you would call that function. John Weeks Thanks Olelytken, HJ, and John for the suggestions. I slightly modified the code to separate fit function and raw spectrum. I can now display raw spectrums in a separate window and I want to call my fit function to fit each of these spectrums. While I am still working on how to call the fit func and append it to the raw spectrum, I would appreciate any insight/comments/help topic to get started. #pragma rtGlobals=3 // Use modern global access method and strict wave access. #include <WMBatchCurveFitIM> Function FitMySpectrum(ww, xx) : FitFunc WAVE ww Variable xx Variable w1=0,w2=0,w3=0,w4=0,w5=0,w6=0,w7=0,w8=0,w9=0,w10=0,w11=0,w12=0,w13,w14=0,qq=0 Variable T1=0.24, S1=0.047, T2=0.24, S2=0.047, x1=1.91, x2=1.918, S3=0.26, x3=2.20 //Variable k //Make/O/N=46 A1 //wave to store coefficients A1 //Make/O/N=46 A2 //wave to store coefficients A2 //Make/O/N=(41,46) fitdata //wavet to store results from fitting //CurveFitDialog/ These comments were created by the Curve Fitting dialog. Altering them will //CurveFitDialog/ make the function less convenient to work with in the Curve Fitting dialog. //CurveFitDialog/ Equation: //CurveFitDialog/ f(xx) = (A1*(1110*(exp(0.5*(S1/T1)^2(xxx1)/T1))*erfc(0.707*(S1/T1(xxx1)/S1)))+200*(exp(((xxx3)/S3)^2)))+(A2*(373*(exp(0.5*(S2/T2)^2(xxx2)/T2)*erfc(0.707*(S2/T2)(xxx2)/S2))+200*(exp(((xxx3)/S3)^2))) //CurveFitDialog/ End of Equation //CurveFitDialog/ Independent Variables 1 //CurveFitDialog/ xx //CurveFitDialog/ S1 > Set equal to 0.064 //CurveFitDialog/ T1 > Set equal to 0.23 //CurveFitDialog/ S2 > Set equal to 0.12 //CurveFitDialog/ T2 > Set equal to 0.09 //CurveFitDialog/ x1 > Set equal to 1.92 //CurveFitDialog/ x2 > Set equal to 2.17 //CurveFitDialog/ Coefficients 2 //CurveFitDialog/ ww[0] = A1 //CurveFitDialog/ ww[1] = A2 w1 = exp(0.5*(S1/T1)^2(xxx1)/T1) w2 = erfc(0.707*(S1/T1(xxx1)/S1)) w3 = 1110 w4 = exp(0.5*(S2/T2)^2(xxx2)/T2) w5 = erfc(0.707*(S2/T2(xxx2)/S2)) w6 = 373 w7 = 200 w8 = exp(((xxx3)/S3)^2) w9 = 200 w10 = 560 w11 = ww[0] w12 = ww[1] w13 = w3*(w1*w2)+w7*w8 w14 = w6*(w4*w5)+w10*w8 qq = w11*w13+w12*w14 return qq End Function RawSpectrumDisplay() variable i for(i=0;i<46;i+=1) String path = "root:ps_2" Display $path DFREF dfr = $path Display dfr:f35[][i] //These are the data I want to fit endfor End [ last edited December 4, 2017  10:29 ]

Tika  December 4, 2017  10:26  

You are trying to add code to the fitting function that belongs in a separate function. You need a driver function that looks up the wave with the data in it and loops over the columns, calling FuncFit. The loop in your code needs to be put into a separate function, and then you would call that function. John Weeks Thanks Olelytken, HJ, and John for the suggestions. I slightly modified the code to separate fit function and raw spectrum. I can now display raw spectrums in a separate window and want to call my fit function to fit each of these spectrums. While I am still working on how to call the fit func and append it to the raw spectrum, I would appreciate any insight/comments/help topic to get started. #pragma rtGlobals=3 // Use modern global access method and strict wave access. #include <WMBatchCurveFitIM> Function FitMySpectrum(ww, xx) : FitFunc WAVE ww Variable xx Variable w1=0,w2=0,w3=0,w4=0,w5=0,w6=0,w7=0,w8=0,w9=0,w10=0,w11=0,w12=0,w13,w14=0,qq=0 Variable T1=0.24, S1=0.047, T2=0.24, S2=0.047, x1=1.91, x2=1.918, S3=0.26, x3=2.20 //Variable k //Make/O/N=46 A1 //wave to store coefficients A1 //Make/O/N=46 A2 //wave to store coefficients A2 //Make/O/N=(41,46) fitdata //wavet to store results from fitting //CurveFitDialog/ These comments were created by the Curve Fitting dialog. Altering them will //CurveFitDialog/ make the function less convenient to work with in the Curve Fitting dialog. //CurveFitDialog/ Equation: //CurveFitDialog/ f(xx) = (A1*(1110*(exp(0.5*(S1/T1)^2(xxx1)/T1))*erfc(0.707*(S1/T1(xxx1)/S1)))+200*(exp(((xxx3)/S3)^2)))+(A2*(373*(exp(0.5*(S2/T2)^2(xxx2)/T2)*erfc(0.707*(S2/T2)(xxx2)/S2))+200*(exp(((xxx3)/S3)^2))) //CurveFitDialog/ End of Equation //CurveFitDialog/ Independent Variables 1 //CurveFitDialog/ xx //CurveFitDialog/ S1 > Set equal to 0.064 //CurveFitDialog/ T1 > Set equal to 0.23 //CurveFitDialog/ S2 > Set equal to 0.12 //CurveFitDialog/ T2 > Set equal to 0.09 //CurveFitDialog/ x1 > Set equal to 1.92 //CurveFitDialog/ x2 > Set equal to 2.17 //CurveFitDialog/ Coefficients 2 //CurveFitDialog/ ww[0] = A1 //CurveFitDialog/ ww[1] = A2 w1 = exp(0.5*(S1/T1)^2(xxx1)/T1) w2 = erfc(0.707*(S1/T1(xxx1)/S1)) w3 = 1110 w4 = exp(0.5*(S2/T2)^2(xxx2)/T2) w5 = erfc(0.707*(S2/T2(xxx2)/S2)) w6 = 373 w7 = 200 w8 = exp(((xxx3)/S3)^2) w9 = 200 w10 = 560 w11 = ww[0] w12 = ww[1] w13 = w3*(w1*w2)+w7*w8 w14 = w6*(w4*w5)+w10*w8 qq = w11*w13+w12*w14 return qq End Function RawSpectrumDisplay() variable i for(i=0;i<46;i+=1) String path = "root:ps_2" Display $path DFREF dfr = $path Display dfr:f35[][i] //These are the data I want to fit endfor End 
Tika  December 4, 2017  12:33  

You are trying to add code to the fitting function that belongs in a separate function. You need a driver function that looks up the wave with the data in it and loops over the columns, calling FuncFit. The loop in your code needs to be put into a separate function, and then you would call that function. John Weeks I tried to make the use of driver function within which I looped over the columns of my data. Calling the driver function from the command line just displays the raw data however; I can see the fitting coefficients for the last spectrum being displayed on the command panel. Also I copied the second last line of my code form the help menu and do not understand what ''/D /STRC=" is referring to. I would be thankful for any suggestion on how to get the fits appended over the raw spectrum. #pragma rtGlobals=3 // Use modern global access method and strict wave access. #include <WMBatchCurveFitIM> Function FitMySpectrum(ww, xx) : FitFunc WAVE ww Variable xx Variable w1=0,w2=0,w3=0,w4=0,w5=0,w6=0,w7=0,w8=0,w9=0,w10=0,w11=0,w12=0,w13,w14=0,qq=0 Variable T1=0.24, S1=0.047, T2=0.24, S2=0.047, x1=1.91, x2=1.918, S3=0.26, x3=2.20 //Variable i, k //Make/O/N=46 A1 //wave to store coefficients A1 //Make/O/N=46 A2 //wave to store coefficients A2 //Make/O/N=(41,46) fitdata //wavet to store results from fitting //CurveFitDialog/ These comments were created by the Curve Fitting dialog. Altering them will //CurveFitDialog/ make the function less convenient to work with in the Curve Fitting dialog. //CurveFitDialog/ Equation: //CurveFitDialog/ f(xx) = (A1*(1110*(exp(0.5*(S1/T1)^2(xxx1)/T1))*erfc(0.707*(S1/T1(xxx1)/S1)))+200*(exp(((xxx3)/S3)^2)))+(A2*(373*(exp(0.5*(S2/T2)^2(xxx2)/T2)*erfc(0.707*(S2/T2)(xxx2)/S2))+200*(exp(((xxx3)/S3)^2))) //CurveFitDialog/ End of Equation //CurveFitDialog/ Independent Variables 1 //CurveFitDialog/ xx //CurveFitDialog/ S1 > Set equal to 0.064 //CurveFitDialog/ T1 > Set equal to 0.23 //CurveFitDialog/ S2 > Set equal to 0.12 //CurveFitDialog/ T2 > Set equal to 0.09 //CurveFitDialog/ x1 > Set equal to 1.92 //CurveFitDialog/ x2 > Set equal to 2.17 //CurveFitDialog/ Coefficients 2 //CurveFitDialog/ ww[0] = A1 //CurveFitDialog/ ww[1] = A2 w1 = exp(0.5*(S1/T1)^2(xxx1)/T1) w2 = erfc(0.707*(S1/T1(xxx1)/S1)) w3 = 1110 w4 = exp(0.5*(S2/T2)^2(xxx2)/T2) w5 = erfc(0.707*(S2/T2(xxx2)/S2)) w6 = 373 w7 = 200 w8 = exp(((xxx3)/S3)^2) w9 = 200 w10 = 560 w11 = ww[0] w12 = ww[1] w13 = w3*(w1*w2)+w7*w8 w14 = w6*(w4*w5)+w10*w8 qq = w11*w13+w12*w14 return qq End Function RawSpectrumDisplay() variable i for(i=0;i<46;i+=1) String path = "root:ps_2" Display $path DFREF dfr = $path Display dfr:f35[][i] //These are the data I want to fit endfor End // The structure definition Structure EMGFitStruct Wave cw // required coefficient wave that should be guessed initially wave yw // y value which should come from f35[][i] wave xw // x values already scaled in f35[][i] variable j EndStructure // The driver function that calls Func Fit: Function EMGFitDriver(cw,yw,xw) //FUNCREF RawSpectrumDisplay Wave cw // coefficient waves Wave yw Wave xw variable i for(i=0;i<46;i+=1) String path = "root:ps_2" Display $path DFREF dfr = $path Display dfr:f35[][i] //These are the data I want to fit endfor STRUCT EMGFitStruct f35 FuncFit FitMySpectrum, cw, yw /X=xw /D /STRC=f35 END 
Tika  December 5, 2017  08:08  

So far, I made a little progress but still far from what I need. The fitting appears only for the last raw spectrum displayed. I tried to run for loop for the fitting function and also tried some changes in the last function but no luck. I would appreciate very much for the help on how to include the fit for every displayed raw spectrum. Here is the revised code. #pragma rtGlobals=3 // Use modern global access method and strict wave access. #include <WMBatchCurveFitIM> // The structure definition Structure EMGFitStruct Wave cw // required coefficient wave that should be guessed initially wave yw // y value which should come from f35[][i] wave xw // x values already scaled in f35[][i] //variable xx, qq //wave ww wave inputw EndStructure Function FitMySpectrum(ww,xx) : FitFunc //STRUCT EMGFitStruct &s //variable xx //variable qq WAVE ww //wave qq Variable xx Variable w1=0,w2=0,w3=0,w4=0,w5=0,w6=0,w7=0,w8=0,w9=0,w10=0,w11=0,w12=0,w13,w14=0,qq=0 Variable T1=0.24, S1=0.047, T2=0.24, S2=0.047, x1=1.91, x2=1.918, S3=0.26, x3=2.20 //Variable i, k //Make/O/N=46 A1 //wave to store coefficients A1 //Make/O/N=46 A2 //wave to store coefficients A2 //Make/O/N=(41,46) qq //wavet to store results from fitting //CurveFitDialog/ These comments were created by the Curve Fitting dialog. Altering them will //CurveFitDialog/ make the function less convenient to work with in the Curve Fitting dialog. //CurveFitDialog/ Equation: //CurveFitDialog/ f(xx) = (A1*(1110*(exp(0.5*(S1/T1)^2(xxx1)/T1))*erfc(0.707*(S1/T1(xxx1)/S1)))+200*(exp(((xxx3)/S3)^2)))+(A2*(373*(exp(0.5*(S2/T2)^2(xxx2)/T2)*erfc(0.707*(S2/T2)(xxx2)/S2))+200*(exp(((xxx3)/S3)^2))) //CurveFitDialog/ End of Equation //CurveFitDialog/ Independent Variables 1 //CurveFitDialog/ xx //CurveFitDialog/ S1 > Set equal to 0.064 //CurveFitDialog/ T1 > Set equal to 0.23 //CurveFitDialog/ S2 > Set equal to 0.12 //CurveFitDialog/ T2 > Set equal to 0.09 //CurveFitDialog/ x1 > Set equal to 1.92 //CurveFitDialog/ x2 > Set equal to 2.17 //CurveFitDialog/ Coefficients 2 //CurveFitDialog/ ww[0] = A1 //CurveFitDialog/ ww[1] = A2 w1 = exp(0.5*(S1/T1)^2(xxx1)/T1) w2 = erfc(0.707*(S1/T1(xxx1)/S1)) w3 = 1110 w4 = exp(0.5*(S2/T2)^2(xxx2)/T2) w5 = erfc(0.707*(S2/T2(xxx2)/S2)) w6 = 373 w7 = 200 w8 = exp(((xxx3)/S3)^2) w9 = 200 w10 = 560 w11 = ww[0] w12 = ww[1] w13 = w3*(w1*w2)+w7*w8 w14 = w6*(w4*w5)+w10*w8 qq = w11*w13+w12*w14 return qq //variable i //for(i=0;i<2;i+=1) //qq=qq[i] //endfor //return qq End Function RawSpectrumDisplay (coef, f35) wave coef wave f35 variable xx STRUCT EMGFitStruct fs variable i for(i=0;i<2;i+=1) String path = "root:ps_2" Display $path DFREF dfr = $path Display dfr:f35[][i] //These are the data I want to fit wave fs.inputw=dfr:f35 endfor End // The driver function that calls Func Fit: Function EMGFitDriver(W_coef,f35,xx) //FUNCREF RawSpectrumDisplay Wave W_coef // coefficient waves Wave f35 Wave xx variable i for(i=0;i<3;i+=1) String path = "root:ps_2:f35[][i]" Display $path DFREF dfr = $path Display dfr:f35[][i] //These are the data I want to fit endfor STRUCT EMGFitStruct fs FuncFit FitMySpectrum, W_coef, f35[][i]/D /STRC=fs //FitMySpectrum is the fitting function END 
HJDrescher  December 5, 2017  08:55  

Once again, just break it down into easy pieces. Write a function that only displays the raw data. From now on have a close look to the history window: Use the information from the history to modify the displaying function mentioned above. In short words: add these commands within the display loop. Display the coefficient wave and you should be almost happy. 
Tika  December 5, 2017  09:16  

Write a function that only displays the raw data. From now on have a close look to the history window: Use the information from the history to modify the displaying function mentioned above. In short words: add these commands within the display loop. Display the coefficient wave and you should be almost happy. TRK Thank HJ ! 'Analysis>Curve Fitting' works beautifully and I extract the coefficients from the history/textbox in the graph window. Here I am looking for some automate fitting as I have hundreds of columns in my data (though I am running my loops only for 3 cols in above code for check) and will encounter similar sets of data in future. Initially I tried using simple function but it did not work for me and based on the comments and forum posts, I decided to use structure function. I would be happy and appreciate very much for the help on displaying the fit to every raw spectrums than just the last raw spectum in the loop. Thanks, Tika [ last edited December 5, 2017  09:26 ]

HJDrescher  December 5, 2017  09:49  


Tika  December 5, 2017  16:05  

Once this works, add that command right after the funcfit command in your procedure. Once again I need help to extract data for each iteration in FuncFit. I checked FuncFit section in help file and it does not explain how to extract results from FuncFit. I just keep on getting the fit only for the last iteration of my loop; it looks like overwriting the fit. Here is what I did; After FuncFit command line I duplicated the wave to get fit data for each iteration (but this does not seem to duplicate the fit data). Then I created a 2D wave to store the fit data. Here is the segment of the code. Thanks Function EMGFitDriver(W_coef,f35,xx) Wave W_coef // coefficient waves in my folder Wave f35 Wave xx Wave fit_f35 //Wave outputw variable i,n for(i=0;i<10;i+=1) String path = "root:ps_2:f35[][i]" Display $path DFREF dfr = $path Display dfr:f35[][i] //These are the data I want to fit endfor STRUCT EMGFitStruct fs FuncFit FitMySpectrum, W_coef, f35[][i]/D/STRC=fs //FitMySpectrum is the fitting function duplicate/o fit_f35, $("fit"+num2istr(n)+"_"+"f35") //I am assuming FucnFit returns the fit data as fit_f35 wave by default because this is what I see in my folder Make/O/N=(41,46) fitdata fitdata = fit_f35 SetAxis bottom 1.64, 3.2 //Display outputw[][i] AppendToGraph f35[][i],fit_f35[][i] 
Tika  December 5, 2017  20:41  

I understand that I am making too many posts for a simple problem which might be annoying to other igor programmers/forum readers, I apologize. As a newbie in programming skills, I just wanted to make sure that I am following the right direction and get some insight on the coding from the experts/experienced igor users. In the previous post, I realized my silly mistake of ending the for loop before its execution and now I fixed that, and am able to append the raw spectrum to fit data and display graph for each iteration. In the next step, I am trying to save fit coefficients and fit data of each iteration in a 2D wave form. I would appreciate any help on this part. Here is the segment of the code. Function EMGFitDriver(W_coef,f35,xx) Wave W_coef // coefficient waves Wave f35 Wave xx Make/O/N = (46)fit_f35 //Wave outputw variable i,n for(i=0;i<2;i+=1) String path = "root:ps_2:f35[][i]" Display $path DFREF dfr = $path Display dfr:f35[][i] //These are the data I want to fit STRUCT EMGFitStruct fs FuncFit FitMySpectrum, W_coef, f35[][i]/D/STRC=fs //FitMySpectrum is the fitting function duplicate/o fit_f35, $("fit"+num2istr(n)+"_"+"f35[][i]") display fit_f35[][i], $("fit"+num2istr(i)+"_"+"f35[][i]") //wave fitdata=$("fit"+num2istr(n)+"_"+"f35") Make/O/N=(41,46) fitdata wave fitdata=$("fit"+num2istr(0)+"_"+"f35[][i]") SetAxis bottom 1.64, 3.2 endfor End 
HJDrescher  December 6, 2017  01:16  

Once again: do it manually first. For three data sets is enough. Run your code in the command window and see what happens. Ill guide you though the development. I assume there are things in the code (e.g., "/TN=") that you don't understand. This is absolutely fine. Consult the manual and if you have additional questions, please feel free to ask. Let's start. We do not want to mess with the current data folder (DF): Hence, we save the current one, switch to our data, and at the end of the function we switch back. Function ProcessData(DataFolderName, DataName) String DataFolderName, DataName // This is the full path to your data in two pieces as text. It could also be passed as a wave reference, but this makes the code a little more complicated Variable i DFRef OldDF=GetDataFolderDFR() //Store the current DF SetDataFolder $DataFolderName // Set it to our data Wave Data=$DataName For (i=0;i<Dimsize(Data,1);i+=1) Display /K=1 /W=(10*i,10*i+40, 10*i+440, 10*i+40+210) Data[][i]/TN=$(DataName+"_"+Num2str(i)) ModifyGraph mode(test_2)=2, lsize(test_2)=2 EndFor SetDataFolder OldDF // Switch DF back End Have a look at the manual what the K and W flags are doing. you should be able to call it like this: ProcessData("root:ps_2:input:", "f35")
The next step would be to include the fitting function. There is no need for storing in the fit function. All it does is getting one x value and calculating one y value. For each point in your data. In each iteration. You see, it gets called many times. You want the data after all of this is finished. In the meantime, avoid any overhead: Remove all 'Make' command from the fitfunction. Variables i & k are also not used  remove this line as well. Now you want to prepare for storing something. Your fits will share the same data structure as your raw data. Why not use this property? Function ProcessData(DataFolderName, DataName) String DataFolderName, DataName Variable i DFRef OldDF=GetDataFolderDFR() SetDataFolder $DataFolderName Wave Data=$DataName Duplicate /O Data $("fit_"+DataName) // Replicate the data structure incl. wavc scaling units etc. Wave Fits=$("fit_"+DataName) Make /O /N=(DimSize(Data,1)) A1, A2 // Prepare the coefficient storage For (i=0;i<Dimsize(Data,1);i+=1) Display /K=1 /W=(10*i,10*i+40, 10*i+440, 10*i+40+210) Data[][i]/TN=$(DataName+"_"+Num2str(i)) ModifyGraph mode(test_2)=2, lsize(test_2)=2 Endfor SetDataFolder OldDF End Now we can add the fitting. You don't need the data structure. A temporary (/FREE) coefficient wave with initial guesses is sufficient. Also prepare a temporary wave for the fit outside the loop. Make /FREE /D /N=2 w_coef={1,2} Make /FREE /N=(Dimsize(Data,0)) Fit And add the fitting in the loop: FuncFit /Q FitMySpectrum W_coef Data[][i] /D=Fit Function ProcessData(DataFolderName, DataName) String DataFolderName, DataName Variable i DFRef OldDF=GetDataFolderDFR() SetDataFolder $DataFolderName Wave Data=$DataName Duplicate /O Data $("fit_"+DataName) Wave Fits=$("fit_"+DataName) Make /O /N=(DimSize(Data,1)) A1, A2 Make /FREE /D /N=2 w_coef={1,2} Make /FREE /N=(Dimsize(Data,0)) Fit For (i=0;i<Dimsize(Data,1);i+=1) Display /K=1 /W=(10*i,10*i+40, 10*i+440, 10*i+40+210) Data[][i]/TN=$(DataName+"_"+Num2str(i)) ModifyGraph mode($(DataName+"_"+Num2str(i)))=2, lsize($(DataName+"_"+Num2str(i)))=2 FuncFit /Q FitMySpectrum W_coef Data[][i] /D=Fit Endfor SetDataFolder OldDF End If you test this function, you will realize that there is no fit displayed in the windows. This is ok for now. Let's store our results first. Fits[][i]=Fit[p] A1[i]=w_coef[0] A2[i]=w_coef[1] Certainly this needs to be done right after the fitting. Next, we nicely display the resulting fit within the loop AppendToGraph Fits[][i]/TN=$(DataName+"_Fit_"+Num2str(i)) ModifyGraph rgb($(DataName+"_Fit_"+Num2str(i)))=(0,0,0) Finally we add some output of the coefficeints Edit /K=1 /W=(400,40,800,240) A1 A2 Display /K=1 /W=(400,310,800,510) A1 Display /K=1 /W=(400,550,800,750) A2 Altogether it should look like this: Function ProcessData(DataFolderName, DataName) String DataFolderName, DataName Variable i DFRef OldDF=GetDataFolderDFR() SetDataFolder $DataFolderName Wave Data=$DataName Duplicate /O Data $("fit_"+DataName) Wave Fits=$("fit_"+DataName) Make /O /N=(DimSize(Data,1)) A1, A2 Make /FREE /D /N=2 w_coef={1,2} Make /FREE /N=(Dimsize(Data,0)) Fit For (i=0;i<Dimsize(Data,1);i+=1) Display /K=1 /W=(10*i,10*i+40, 10*i+440, 10*i+40+210) Data[][i]/TN=$(DataName+"_"+Num2str(i)) ModifyGraph mode($(DataName+"_"+Num2str(i)))=2, lsize($(DataName+"_"+Num2str(i)))=2 FuncFit /Q FitMySpectrum W_coef Data[][i] /D=Fit Fits[][i]=Fit[p] A1[i]=w_coef[0] A2[i]=w_coef[1] AppendToGraph Fits[][i]/TN=$(DataName+"_Fit_"+Num2str(i)) ModifyGraph rgb($(DataName+"_Fit_"+Num2str(i)))=(0,0,0) Endfor Edit /K=1 /W=(400,40,800,240) A1 A2 Display /K=1 /W=(400,310,800,510) A1 Display /K=1 /W=(400,550,800,750) A2 SetDataFolder OldDF End A final remark: FitMySpectrum is a name that suits for this forum. In Igor, it should get a more meaningful name, e.g. NeuronResponse or DoniachSunjic. Hope this helps, 
Tika  December 6, 2017  17:51  

Run your code in the command window and see what happens. Ill guide you though the development. I assume there are things in the code (e.g., "/TN=") that you don't understand. This is absolutely fine. Consult the manual and if you have additional questions, please feel free to ask. Let's start. We do not want to mess with the current data folder (DF): Hence, we save the current one, switch to our data, and at the end of the function we switch back. Function ProcessData(DataFolderName, DataName) String DataFolderName, DataName // This is the full path to your data in two pieces as text. It could also be passed as a wave reference, but this makes the code a little more complicated Variable i DFRef OldDF=GetDataFolderDFR() //Store the current DF SetDataFolder $DataFolderName // Set it to our data Wave Data=$DataName For (i=0;i<Dimsize(Data,1);i+=1) Display /K=1 /W=(10*i,10*i+40, 10*i+440, 10*i+40+210) Data[][i]/TN=$(DataName+"_"+Num2str(i)) ModifyGraph mode(test_2)=2, lsize(test_2)=2 EndFor SetDataFolder OldDF // Switch DF back End Have a look at the manual what the K and W flags are doing. you should be able to call it like this: ProcessData("root:ps_2:input:", "f35")
The next step would be to include the fitting function. There is no need for storing in the fit function. All it does is getting one x value and calculating one y value. For each point in your data. In each iteration. You see, it gets called many times. You want the data after all of this is finished. In the meantime, avoid any overhead: Remove all 'Make' command from the fitfunction. Variables i & k are also not used  remove this line as well. Now you want to prepare for storing something. Your fits will share the same data structure as your raw data. Why not use this property? Function ProcessData(DataFolderName, DataName) String DataFolderName, DataName Variable i DFRef OldDF=GetDataFolderDFR() SetDataFolder $DataFolderName Wave Data=$DataName Duplicate /O Data $("fit_"+DataName) // Replicate the data structure incl. wavc scaling units etc. Wave Fits=$("fit_"+DataName) Make /O /N=(DimSize(Data,1)) A1, A2 // Prepare the coefficient storage For (i=0;i<Dimsize(Data,1);i+=1) Display /K=1 /W=(10*i,10*i+40, 10*i+440, 10*i+40+210) Data[][i]/TN=$(DataName+"_"+Num2str(i)) ModifyGraph mode(test_2)=2, lsize(test_2)=2 Endfor SetDataFolder OldDF End Now we can add the fitting. You don't need the data structure. A temporary (/FREE) coefficient wave with initial guesses is sufficient. Also prepare a temporary wave for the fit outside the loop. Make /FREE /D /N=2 w_coef={1,2} Make /FREE /N=(Dimsize(Data,0)) Fit And add the fitting in the loop: FuncFit /Q FitMySpectrum W_coef Data[][i] /D=Fit Function ProcessData(DataFolderName, DataName) String DataFolderName, DataName Variable i DFRef OldDF=GetDataFolderDFR() SetDataFolder $DataFolderName Wave Data=$DataName Duplicate /O Data $("fit_"+DataName) Wave Fits=$("fit_"+DataName) Make /O /N=(DimSize(Data,1)) A1, A2 Make /FREE /D /N=2 w_coef={1,2} Make /FREE /N=(Dimsize(Data,0)) Fit For (i=0;i<Dimsize(Data,1);i+=1) Display /K=1 /W=(10*i,10*i+40, 10*i+440, 10*i+40+210) Data[][i]/TN=$(DataName+"_"+Num2str(i)) ModifyGraph mode($(DataName+"_"+Num2str(i)))=2, lsize($(DataName+"_"+Num2str(i)))=2 FuncFit /Q FitMySpectrum W_coef Data[][i] /D=Fit Endfor SetDataFolder OldDF End If you test this function, you will realize that there is no fit displayed in the windows. This is ok for now. Let's store our results first. Fits[][i]=Fit[p] A1[i]=w_coef[0] A2[i]=w_coef[1] Certainly this needs to be done right after the fitting. Next, we nicely display the resulting fit within the loop AppendToGraph Fits[][i]/TN=$(DataName+"_Fit_"+Num2str(i)) ModifyGraph rgb($(DataName+"_Fit_"+Num2str(i)))=(0,0,0) Finally we add some output of the coefficeints Edit /K=1 /W=(400,40,800,240) A1 A2 Display /K=1 /W=(400,310,800,510) A1 Display /K=1 /W=(400,550,800,750) A2 Altogether it should look like this: Function ProcessData(DataFolderName, DataName) String DataFolderName, DataName Variable i DFRef OldDF=GetDataFolderDFR() SetDataFolder $DataFolderName Wave Data=$DataName Duplicate /O Data $("fit_"+DataName) Wave Fits=$("fit_"+DataName) Make /O /N=(DimSize(Data,1)) A1, A2 Make /FREE /D /N=2 w_coef={1,2} Make /FREE /N=(Dimsize(Data,0)) Fit For (i=0;i<Dimsize(Data,1);i+=1) Display /K=1 /W=(10*i,10*i+40, 10*i+440, 10*i+40+210) Data[][i]/TN=$(DataName+"_"+Num2str(i)) ModifyGraph mode($(DataName+"_"+Num2str(i)))=2, lsize($(DataName+"_"+Num2str(i)))=2 FuncFit /Q FitMySpectrum W_coef Data[][i] /D=Fit Fits[][i]=Fit[p] A1[i]=w_coef[0] A2[i]=w_coef[1] AppendToGraph Fits[][i]/TN=$(DataName+"_Fit_"+Num2str(i)) ModifyGraph rgb($(DataName+"_Fit_"+Num2str(i)))=(0,0,0) Endfor Edit /K=1 /W=(400,40,800,240) A1 A2 Display /K=1 /W=(400,310,800,510) A1 Display /K=1 /W=(400,550,800,750) A2 SetDataFolder OldDF End A final remark: FitMySpectrum is a name that suits for this forum. In Igor, it should get a more meaningful name, e.g. NeuronResponse or DoniachSunjic. Hope this helps, Thank you HJ for step by step development towards the goal. This is what I was looking for exactly. I appreciate your time and effort. It is so good to see how flags after the display command can kill the window (/K=1) with no dialog, determine the location and size of the graph (/w) and provide tracename based on the parent wave(/TN). At the end, I included a residual wave to visualize how good the fit is. Finally, have a couple of quick questions. I checked that the script "Residuals=DataFits" works as it calculates after all the waves are collected. At the same time why "Residuals[][i]=Data[i]Fits[i] or Residuals[][p]=Data[p]Fits[p]" does not work inside the loop because I was assuming that the subtraction from the raw data takes place for each iteration and is stored in Residuals. Next, I know that I can chose not to display the graph window by disabling the display command. I noticed there is /k=3 to hide the window. Other than these is there any quick way to kill the graph window rather than doing it manually? Once again, thank you very much ! Here is how I tried to calculate Residuals, Function ProcessData(DataFolderName, DataName) String DataFolderName, DataName Variable i DFRef OldDF=GetDataFolderDFR() SetDataFolder $DataFolderName //identifies the path for the current data folder Wave Data=$DataName // wavename to be executed Duplicate /O Data $("fit_"+DataName) Wave Fits=$("fit_"+DataName) Make /O /N=(DimSize(Data,1)) A1, A2 Make /FREE/D /N=2 w_coef={1,2} Make /FREE/N=(Dimsize(Data,0)) Fit Duplicate /O Data $("Residual_"+DataName) ////////////// Wave Residuals=$("Residual_"+DataName) ////////////// variable k k=Dimsize(Data,1) For (i=0;i<Dimsize(Data,1);i+=1) Display /K=1 /W=(10*i,10*i+40, 10*i+440, 10*i+40+210) Data[][i]/TN=$(DataName+"_"+Num2str(i)) ModifyGraph mode($(DataName+"_"+Num2str(i)))=2, lsize($(DataName+"_"+Num2str(i)))=2 FuncFit /Q FitMySpectrum W_coef Data[][i] /D=Fit Fits[][i]=Fit[p] Residuals=DataFits ////////////////residuals are calculated //Residuals[][i]=Data[i]Fits[i] //Residuals[p][q]=Data[p][q]Fits[p][q] //this does not work A1[i]=w_coef[0] A2[i]=w_coef[1] AppendToGraph Fits[][i]/TN=$(DataName+"_Fit_"+Num2str(i)) ModifyGraph rgb($(DataName+"_Fit_"+Num2str(i)))=(0,0,0) Endfor //Residuals=DataFits //////////////////////// Edit /K=1 /W=(400,100,800,240) A1 A2 Display /K=1 /W=(400,310,800,510) A1 Display /K=1 /W=(400,550,800,750) A2 SetDataFolder OldDF End <igor> 
HJDrescher  December 7, 2017  05:05  

Small remark: Please don't quote every last response, the thread gets longish. "Post reply" is fine. Calculating the residuals at the end of the procedure should work that way you wrote it. The right syntax would be Residuals[][i]=Data[p][i]Fit[p] You want to calculate for all rows (which correspond to index p) in column i in Residuals (this is the [][i] part) the difference between row p in column p of data and the pth row in Fit. Please read the manual about wave assignment: displayhelptopic "Waveform Arithmetic and Assignment" displayhelptopic "Multidimensional Wave Assignment" (Copy these commands to the command window and execute them) Essentially, function Killwins(WindowList) string WindowList variable i for (i=0;i<itemsinlist(WindowList);i+=1) Killwindow $stringfromlist(i,WindowList) endfor end To kill all graphs run Killwins(winlist("*",";","WIN:1")) and to kill all tables Killwins(winlist("*",";","WIN:2"))
However, it might not be necessary to kill the windows, e.g, if you only want to rerun the fitting. In this case, it might be advisable to separate the processing function into smaller fragments that share the same task. Examples would be creation of data structure, displaying, fitting, summarizing, and cleanup. The same holds, if you want to recreate the graphs later without new fitting. I can give you a step by step example later. I added a little extra to the processing function: Function ProcessData(DataFolderName, DataName) String DataFolderName, DataName Variable i DFRef OldDF=GetDataFolderDFR() SetDataFolder $DataFolderName Wave Data=$DataName Duplicate /O Data $("fit_"+DataName), $("res_"+DataName) // You can duplicate to several destination waves; Keep the names short for automatic extension Wave Residuals=$("res_"+DataName) Wave Fits=$("fit_"+DataName) Make /O /N=(DimSize(Data,1)) A1, A2 Make /FREE /D /N=2 w_coef={1,2} Make /FREE /N=(Dimsize(Data,0)) Fit For (i=0;i<Dimsize(Data,1);i+=1) Display /K=1 /W=(10*i,10*i+40, 10*i+440, 10*i+40+210) Data[][i]/TN=$(DataName+"_"+Num2str(i)) as DataName+"_"+num2str(i) FuncFit /Q FitMySpectrum W_coef Data[][i] /D=Fit Fits[][i]=Fit[p] Residuals[][i]=Data[p][i]Fit[p] A1[i]=w_coef[0] A2[i]=w_coef[1] AppendToGraph Fits[][i]/TN=$(DataName+"_Fit_"+Num2str(i)) AppendToGraph /L=laxRes Residuals[][i]/TN=$(DataName+"_Res_"+Num2str(i)) ModifyGraph mode($(DataName+"_"+Num2str(i)))=2, lsize($(DataName+"_"+Num2str(i)))=2 ModifyGraph mode($(DataName+"_Res_"+Num2str(i)))=2, lsize($(DataName+"_Res_"+Num2str(i)))=2 ModifyGraph freePos(laxRes)={0,bottom} ModifyGraph axisEnab(left)={0,0.75} ModifyGraph axisEnab(laxRes)={0.8,1} ModifyGraph rgb($(DataName+"_Fit_"+Num2str(i)))=(0,0,0) Endfor // Residuals=DataFits Edit /K=1 /W=(400,40,800,240) A1 A2 Display /K=1 /W=(400,310,800,510) A1 Display /K=1 /W=(400,550,800,750) A2 SetDataFolder OldDF End HJ 
Tika  December 7, 2017  23:23  

Thank you HJ for guiding step by step through example. Now I can see how indexing in wave assignment works and the technique how multiple tracenames can be replaced by a single name. I noticed that /TN flags for the residuals and fits could be disabled as it has no affect unless we want to change color of the trace. Also thanks for introducing free axes and how traces can be beautifully positioned for the better display. In fact I started enjoying programming in igor much than before and I understand there is a lot more to know. I am keen to know how above function can be processed into fragments if your time permits. [ last edited December 7, 2017  23:48 ]

December 8, 2017  09:17  

I think you may be ready to read the Programming help file: DisplayHelpTopic "Programming Overview", in Programming.ihf. There is another help file: Programming Techniques.ihf that has a lot of good advice. It is hard going. The first time through it won't make a lot of sense. But some will stick and the next time through more of it will make sense. And it helps to have a project like yours to apply your learning to as you read. John Weeks 
Tika  December 9, 2017  09:43  

Thank you Johnweeks for the suggestion. I will go through the programming techniques while it may take time to be familiar with. For now, I have a quick question related to scaling of waves. Function ConcatenateWaves(data2, data1) Wave data2, data1 Wave destWave variable k, dy //dy =destWave[0]  destWave[1] Duplicate /O/R=[][1,*] data1, sub1 Duplicate /O/R=[][0,26] data2, sub2 k=Dimsize(destWave,1) Concatenate/O/NP=1 {sub2,sub1}, destWave //for (k=0;k<26;k+=1) do (k<27) //col 0 to col 26; starty 300, deltay= 10, endy 40; dy = 30010*k //col 27 to col72, starty39, deltay= 1, endy= 5 while (k>26) dy = 391*k SetScale/P y, destWave[0], dy, destWave //SetAxis/A/R left //endfor End <igor> 
December 11, 2017  09:33  

No, a wave can have only one scaling for a given dimension. You need to use a 1D auxiliary wave giving the time values for each column. How you make that wave will depend on how you want to use the data. Most likely you just need to use a wave with one time value for each column of the wave. That would appropriate for curve fits, for instance. John Weeks 
Tika  December 11, 2017  21:59  


December 12, 2017  09:16  

No, I mean that you need a second wave containing the values of time that go with each column in your 2D wave. Once you do that, then you need to keep track of the 1D wave whenever you need those time values. John Weeks 
HJDrescher  December 13, 2017  00:52  


HJDrescher  December 13, 2017  01:46  

Back to our stepbystep example (sorry for replying late, I had some quite busy time): First, we need to identify each command with a logical set of actions. Function ProcessData(DataFolderName, DataName) String DataFolderName, DataName Variable i DFRef OldDF=GetDataFolderDFR() // Preparation SetDataFolder $DataFolderName // Preparation Wave Data=$DataName // Preparation Duplicate /O Data $("fit_"+DataName), $("res_"+DataName) // Data management Wave Residuals=$("res_"+DataName) // Preparation Wave Fits=$("fit_"+DataName) // Preparation Make /O /N=(DimSize(Data,1)) A1, A2 // Data management Make /FREE /D /N=2 w_coef={1,2} // Preparation Make /FREE /N=(Dimsize(Data,0)) Fit // Preparation For (i=0;i<Dimsize(Data,1);i+=1) // Loop Display /K=1 /W=(10*i,10*i+40, 10*i+440, 10*i+40+210) Data[][i]/TN=$(DataName+"_"+Num2str(i)) as DataName+"_"+num2str(i) // Display FuncFit /Q FitMySpectrum W_coef Data[][i] /D=Fit // Fitting Fits[][i]=Fit[p] // Fitting Residuals[][i]=Data[p][i]Fit[p] // Fitting A1[i]=w_coef[0] // Fitting A2[i]=w_coef[1] // Fitting AppendToGraph Fits[][i]/TN=$(DataName+"_Fit_"+Num2str(i)) // Display AppendToGraph /L=laxRes Residuals[][i]/TN=$(DataName+"_Res_"+Num2str(i)) // Display ModifyGraph mode($(DataName+"_"+Num2str(i)))=2, lsize($(DataName+"_"+Num2str(i)))=2 // Display ModifyGraph mode($(DataName+"_Res_"+Num2str(i)))=2, lsize($(DataName+"_Res_"+Num2str(i)))=2 // Display ModifyGraph freePos(laxRes)={0,bottom} // Display ModifyGraph axisEnab(left)={0,0.75} // Display ModifyGraph axisEnab(laxRes)={0.8,1} // Display ModifyGraph rgb($(DataName+"_Fit_"+Num2str(i)))=(0,0,0) // Display Endfor // Loop Edit /K=1 /W=(400,40,800,240) A1 A2 // Summary Display /K=1 /W=(400,310,800,510) A1 // Summary Display /K=1 /W=(400,550,800,750) A2 // Summary SetDataFolder OldDF // Clean up End The next steps are to create a copy of the function for each set, rename them appropriately, and delete parts that don't match. Be careful with loops and preparations! They might appear in several places. Function PrepareData(DataFolderName, DataName) String DataFolderName, DataName Variable i DFRef OldDF=GetDataFolderDFR() // Preparation SetDataFolder $DataFolderName // Preparation Wave Data=$DataName // Preparation Duplicate /O Data $("fit_"+DataName), $("res_"+DataName) // Data management Make /O /N=(DimSize(Data,1)) $(DataName+"_A1"), $(DataName+"_A2") // Data management SetDataFolder OldDF // Clean up End Function FitData(DataFolderName, DataName) String DataFolderName, DataName Variable i DFRef OldDF=GetDataFolderDFR() // Preparation SetDataFolder $DataFolderName // Preparation Wave Data=$DataName // Preparation Wave Residuals=$("res_"+DataName) // Preparation Wave Fits=$("fit_"+DataName) // Preparation Wave A1= $(DataName+"_A1"), A2= $(DataName+"_A2") // Preparation < This has changed ! Make /FREE /D /N=2 w_coef={1,2} // Preparation Make /FREE /N=(Dimsize(Data,0)) Fit // Preparation For (i=0;i<Dimsize(Data,1);i+=1) // Loop FuncFit /Q FitMySpectrum W_coef Data[][i] /D=Fit // Fitting Fits[][i]=Fit[p] // Fitting Residuals[][i]=Data[p][i]Fit[p] // Fitting A1[i]=w_coef[0] // Fitting A2[i]=w_coef[1] // Fitting Endfor // Loop SetDataFolder OldDF // Clean up End Function DisplayData(DataFolderName, DataName) String DataFolderName, DataName Variable i DFRef OldDF=GetDataFolderDFR() // Preparation SetDataFolder $DataFolderName // Preparation Wave Data=$DataName // Preparation Wave Residuals=$("res_"+DataName) // Preparation Wave Fits=$("fit_"+DataName) // Preparation For (i=0;i<Dimsize(Data,1);i+=1) // Loop Display /K=1 /W=(10*i,10*i+40, 10*i+440, 10*i+40+210) Data[][i]/TN=$(DataName+"_"+Num2str(i)) as DataName+"_"+num2str(i) // Display AppendToGraph Fits[][i]/TN=$(DataName+"_Fit_"+Num2str(i)) // Display AppendToGraph /L=laxRes Residuals[][i]/TN=$(DataName+"_Res_"+Num2str(i)) // Display ModifyGraph mode($(DataName+"_"+Num2str(i)))=2, lsize($(DataName+"_"+Num2str(i)))=2 // Display ModifyGraph mode($(DataName+"_Res_"+Num2str(i)))=2, lsize($(DataName+"_Res_"+Num2str(i)))=2 // Display ModifyGraph freePos(laxRes)={0,bottom} // Display ModifyGraph axisEnab(left)={0,0.75} // Display ModifyGraph axisEnab(laxRes)={0.8,1} // Display ModifyGraph rgb($(DataName+"_Fit_"+Num2str(i)))=(0,0,0) // Display Endfor // Loop SetDataFolder OldDF // Clean up End Function SummaryData(DataFolderName, DataName) String DataFolderName, DataName Variable i DFRef OldDF=GetDataFolderDFR() // Preparation SetDataFolder $DataFolderName // Preparation Wave Data=$DataName // Preparation Duplicate /O Data $("fit_"+DataName), $("res_"+DataName) // Data management Wave Residuals=$("res_"+DataName) // Preparation Wave Fits=$("fit_"+DataName) // Preparation Wave A1= $(DataName+"_A1"), A2= $(DataName+"_A2") // Preparation < This has changed from creation to reference Edit /K=1 /W=(400,40,800,240) A1 A2 // Summary Display /K=1 /W=(400,310,800,510) A1 // Summary Display /K=1 /W=(400,550,800,750) A2 // Summary SetDataFolder OldDF // Clean up End Now you have to run the functions one by one PrepareData("root:sdf:", "test") FitData("root:sdf:", "test") DisplayData("root:sdf:", "test") SummaryData("root:sdf:", "test") Note: If you run one of the latter functions on a new set of data, it will fail. It expects the prepared waves to exist, which is not the case for a new data set. Here, some data structure checking would be required to protect the data from the user. Have a look in the manual and read about You might have realized that the original function is gone at this point. It was so nice, that it did all of the work with one command. Let's bring it back: Function ProcessData(DataFolderName, DataName) String DataFolderName, DataName PrepareData(DataFolderName, DataName) FitData(DataFolderName, DataName) DisplayData(DataFolderName, DataName) SummaryData(DataFolderName, DataName) End It simply takes your input and calls the other functions. What is it good for? We had the same result using one more complex function. On the one hand, it gives the programmer a better view on his code. Once the simple functions reach a couple of hundred lines you are happy that it's not in the thousands. On the other hand, we can rerun single steps! Assume you did a full run on the data, modified the graphs, added some manual annotation, ..... and you figured out that there was a small typo in the fit function. You don't want to kill all the nice figures. Actually, all you need is to rerun the fit and check your remarks in the graph. This is possible now. The data structure is prepared from the last run. You can call the fitting by itself. Igor updates the graphs as the corresponding waves are altered. As a next logical step, we want to kill (or hide but this takes some more checking) the fit result windows. In order to do this, we should give the windows names: Display /N=$(DataName+"_"+Num2str(i))) /K=1 /W=(10*i,10*i+40, 10*i+440, 10*i+40+210) Data[][i]/TN=$(DataName+"_"+Num2str(i)) as DataName+"_"+num2str(i) // in DisplayData and prepare a function that kills the windows related to a data set (based on that name): Function KillFitWindows(DataFolderName, DataName) String DataFolderName, DataName Variable i Wave Data=$(DataFolderName+DataName) // Preparation For (i=0;i<Dimsize(Data,1);i+=1) // Loop Killwindow $(DataName+"_"+Num2str(i)) EndFor End Be advised not to display the fit windows twice. Killing only works on the first instance. To fix this, you would need some checkup during the displaying routine that skips already displayed fits. Happy fitting, [ last edited December 13, 2017  01:47 ]

Tika  December 16, 2017  17:45  

Thank you HJ for step by step illustrations on how the code is developed towards the final step. My fitting is complete now. Igor Exchange forum has always been a great site to learn and develop skills for users like me. 
HJDrescher  December 17, 2017  00:40  


Joined: 20151112
Location: Nepal
I have a equation with two fit coefficients to fit data from a 2D wave. I want to display all fitting curves along with the raw data and store coefficient values in wave form; somewhat similar to batch curve fitting. There are few related forum posts that discusses about automatic curve fitting and how coefficients are stored in data folder however; due to my limited knowledge I am having trouble to follow the coding and hence I am trying to work with my code. Right now, my code does not accept the input wave to which I want to fit my data. Can anyone suggest/help me to make my code work?
TRK