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