Microplate Reader Data Sorting

Hi all,

I've used IGOR to analyze voltage-clamp data, but I'm new to programming. I'm working through the Payam's Place "Introduction to IGOR Programming," and I've made it to the Intermediate Algorithms section, but I think I'm having a more basic issue.

So each data file I get is an excel file with 385 columns (the first is time) of 600 points each - each corresponding to a well on a 364-well plate. I read these all in as waves, and thanks to jjweimer's responses to a few other topics in the forum, I've managed to write functions to rename and duplicate all of the files:


function TempRenameEpic(matchstring, newsuffix)
	string matchstring, newsuffix
	
	string wavenames=wavelist("*", ";", "")
	
	string theOne
	
	string theName
	
	variable i 
	
	for (i = 0; i < itemsinlist(wavenames); i += 1)
		theOne = stringfromlist(i,wavenames)
		theName = ReplaceString(matchstring,theOne,newsuffix)

        		rename $theOne $theName
        		
        endfor
    End
    
    function duplicateEpic(matchstring, newsuffix)
	string matchstring, newsuffix
	
	string wavenames=wavelist("*", ";", "")
	
	string theOne
	
	variable i 
	
	for (i = 0; i < itemsinlist(wavenames); i += 1)
		theOne = stringfromlist(i,wavenames)
		string theName = ReplaceString(matchstring,theOne,newsuffix)		      
    		
                duplicate/O $theOne $theName
        		
        endfor
    End



Since all of the original titles for each wave are cumbersome, this allows me to rename them the simple A1_ A2_ A3_ etc (I include the underscore because of the system variables K0-K19). Here's the issue: I have baseline wells - in the O and P rows of the plate - that are buffer controls. Each one corresponds to one well in a group of four - such that O1 is the control well for A1, O2 for A2, P1 for B1, and P2 for B2. This continues down the column of the 384-well plate, so O1 is the control for not only A1, but C1, E1, G1, I1, K1, and M1.

I want to quickly subtract the appropriate control wave from each of its well waves. I can easily do it for one wave:

duplicate A1_, A1_mb
A1_mb = A1_ - O1_

So now I just need to set up a series of If, elseif parameters inside a function to do it for each column and then the whole plate. Here is what I have so far:


    function SubtractBaselineOnce(input,baseline) //This works if I supply the target wave and its appropriate control wave
	wave input
	wave baseline
	
	string outputname = nameofwave(input) + "mb"
	
	duplicate/O input, $outputname
	
	wave output = $outputname
			
	output = input - baseline
	
    End
    
    Function SubBase(matchstring)
    
    string matchstring
    
    
	string wavenames=wavelist("*", ";", "")
	
	string theOne
	
	string theName
	
	variable i 
	
	for (i = 0; i < itemsinlist(wavenames); i += 1)
		theOne = stringfromlist(i,wavenames)
	
        	if 							//How do I sort this?
        	endif	
        endfor
    
    End




Thanks for any tips you might have.

-EM
Hello EM:

for the subtraction you could try:

function subBase(inW,baseW)
	Wave inW,baseW
	
	String name=nameofwave(inW)+"mb"
	MatrixOP/O $name=inW-baseW
End


This saves the duplication.

If you are going to repeat this for the whole plate I recommend that you reconsider the way you arrange your data. Specifically you might benefit from storing all the data in a single 2D wave where each one of your current waves is a single column. It would then be easier to perform uniform baseline subtraction and all your waves are nicely organized in a single object.

A.G.
WaveMetrics, Inc.
You need to use $ to create a wave reference from a string variable containing the name of the wave. Basically it is:

Wave w1 = $theName		// Create wave reference
...
Wave w2 = $theOne		// Create wave reference
w2 -= w1				// Subtract


To learn about this, execute:

DisplayHelpTopic "Accessing Global Variables And Waves"


But you really should read all of the Programming help file or the equivalent - chapters IV-1, IV-2 and IV-3 of the PDF manual.

On the topic of loading waves, if you are loading waves using XLLoadWave and you know the desired wave names in advance, you can use the XLLoadWave /NAME flag to set the wave names.

Thank You for the tips! I'm working through the IGOR manual chapters, but I found the information I needed in Volume IV-1 and the Volume V reference. Below is the solution I came up with (to subtract the buffer control - O and P - wells from their corresponding condition wells in A-N rows).

I'm sure it can be cleaned up and simplified, but I'm just happy I got it to work, and hopefully someone can use this info in the future. The functions that were the most helpful for me were sscanf, StringByKey, and SelectString.


    Function SubtractBuffer(matchstring)
    
    string matchstring
    
	string wavenames=wavelist("*", ";", "")
	
	string theOne
	
	variable i 
	
	for (i = 0; i < itemsinlist(wavenames); i += 1)
		
		theOne = stringfromlist(i,wavenames)

			variable v1
			string s1
			string whichone //will be 0 or 1 -- 0 for O, 1 for P (to work with SelectString)
			
			sscanf theOne, "%1s%f", s1, v1  //separates plate column number from row letter
			
			//make all waves containing A, C, E ect return 0 and the rest return 1
			whichone = StringByKey(s1, "A:0;B:1;C:0;D:1;E:0;F:1;G:0;H:1;I:0;J:1;K:0;L:1;M:0;N:1")
			
			//SelectString will output O or P based on whichone value
			string intermediatename = SelectString(str2num(whichone), "O", "P")
			string baselinename = intermediatename + num2str(v1) +"_"	
			
			string outputname = nameofwave($theOne) + "mb"
	
	//this last part is to prevent generating the buffer-subtracted wave from buffer-well waves or time waves
	if (str2num(whichone) == 0)
			duplicate/O $theOne, $outputname
	
			wave original = $theOne
			wave output = $outputname
			wave baseline = $baselinename
			
			output = original - baseline
			
	elseif (str2num(whichone) == 1)
			duplicate/O $theOne, $outputname
	
			wave original = $theOne
			wave output = $outputname
			wave baseline = $baselinename
			
			output = original - baseline
			
	else 
			duplicate/O $theOne, $outputname
	
			killwaves $outputname	
        endif
        endfor
    
    End


Thanks again for the help!

-EM
Don't you do the exact same thing in the
if (str2num(whichone) == 0)
and
elseif (str2num(whichone) == 1)
blocks?
And also the last
else
block seems redundant, as you first duplicate the wave and two lines later kill it.

Recent igor versions also allow to create a wave reference on duplication i.e.

Function doStuff()

	Make data
	string temp = "abcd"
	Duplicate/O data, $temp/Wave=output
End

which make the code more compact to read.
I could not see where your function uses the input matchstring. I also could not see that you need a complicated if ... elseif ... else section, since you do the same thing for whichone = 0 or 1 and these are your only two options. I _think_ this might do the same thing. One caveat is, after it is run one time, the wavenames string will have the new output wave names in it, and you will have to filter those out. I think this could be a problem in your original code as well.


#pragma rtGlobals=3		// Use modern global access method and strict wave access.

Function SubtractBuffer()
 
	string wavenames, theOne, s1, iname, blname, outname
	variable ic, v1, nw, ns
	
	wavenames = wavelist("*", ";", "")
	nw = ItemsInList(wavenames)
 
	for (ic = 0; ic <nw; ic += 1)
 
		theOne = stringfromlist(ic,wavenames)
		wave source = $theOne
		
		sscanf theOne, "%1s%f", s1, v1
 		
		nw = mod((char2num(s1)-65),2)
		
		iname = nw == 0 ? "O" : "P"
		
		blname = iname + num2str(v1) + "_"
		wave baseline = $blname
		
		outname = theOne + "mb"
		duplicate/O $theOne $outname
		wave output = $outname
		
		output = source - baseline
		
	endfor
	
	return 0
 
end


You might consider whether your data waves can be collapsed so that MatrixOp can be used (as AG suggested) to streamline and speed up the code

--
J. J. Weimer
Chemistry / Chemical & Materials Engineering, UAHuntsville