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