reference a wave loaded by the LoadWave operation

Dear Igor Users,

I am completely new to Igor and to programming in general, so my question might seem quite simple. I am dealing with large data files from FRET spectra. To start with, I would like to open all files and load waves containing specific parts of the columns. By combining some code I found in different forums this was no problem. I want to set a baseline for all the waves loaded, by running a separate function on them. this is what I have so far:

Function/S OpenMultiFileDialog()
    Variable refNum
    String outputPaths
    String fileFilters = "All Files:.*;"
    string message
   
    Open /D /R /MULT=1 /F=fileFilters /M=message refNum
    outputPaths = S_fileName
 
    if (strlen(outputPaths) == 0)
        Print "Cancelled"
    else
 
        Variable numFilesSelected = ItemsInList(outputPaths, "\r")
        Variable i
 
       
        for(i=0; i<numFilesSelected; i+=1)
            String path = StringFromList(i, outputPaths, "\r")
            LoadWave/D/J/A=wave/O/L={0,160256,511,5,1}path
               
                if (V_flag >1) // loaded more than 1 wave
           
                    do
                        if (strlen (stringfromlist(i, S_waveNames)) == 0) // No more waves?
                            break
                        endif
                       
                        wave testWave = $(stringFromList(i, S_waveNames))
                       
                        SetBaseline (testwave)
                       
                        i+=1
                    while(1)
                endif
        endfor
    endif

End



function SetBaseline(wave2treat) //Function
    wave wave2treat //wave reference

    //store the name of the wave + the string "_base" into newWaveName
    string newWaveName=NameofWave(wave2treat)+"_base"


    //Duplicate the wave x as a wave named x_normalised
    Duplicate/O wave2treat $newWaveName

    //Reference x_normalised so that you can use it
    wave newWave=$NewWaveName

    newWave= wave2treat-WaveMin(wave2treat)
end


This compiles but gives me an error "Attempt to use a null string variable". Any help/suggestions/explanations will be greatly appreciated!

I have removed the duplicate posting.

Quick perusal doesn't show a problem, but my eyes are often blind to obvious mistakes. When the error occurs, you should get information about which line caused the error. That would be useful information for the experts looking at your posting.

Use the symbolic debugger: DisplayHelpTopic "The Debugger"

Right-click in any procedure window and select Enable Debugger. Then right-click again and select NVAR, SVAR, Wave Checking. Right-click once more and select Debug on Error.

Now run your procedure; when the error occurs the debugger should pop up stopped at the line causing the error (or the line after, because, after all, the line has already executed). The debugger will allow you to examine the values of the variables, and will show NULL for a string variable that is NULL.

Note that a NULL string variable is one that has never been assigned a value. It is different from a string variable of zero length.

John Weeks
WaveMetrics, Inc.
support@wavemetrics.com
You should follow John's instructions for using the debugger. It is invaluable.

You will find that the string message is uninitialized.
Thanks a lot for the help,

I followed the instructions and assigned the value to message. The function runs without errors, but it still doesn't produce the new waves through the the SetBaseline function. The waves of loadwaves operation are there though. Did I not reference them correctly, or is there a problem in the loop? should I introduce a new variable index, instead of i for the new list of waves created by LoadWaves? Or am I missing something?
You are using the i loop variable for two nested loops. You need two loop variables. Here is my rewrite of the part in question:

    Variable numFilesSelected = ItemsInList(outputPaths, "\r")
    Variable i
    for(i=0; i<numFilesSelected; i+=1)
        String path = StringFromList(i, outputPaths, "\r")
        LoadWave/D/J/A=wave/O/L={0,160256,511,5,1} path
        Variable numWavesLoaded = V_flag    // V_flag is set by LoadWave
        String list = S_waveNames           // S_waveNames is set by LoadWave
        Variable j
        for(j=0; j<numWavesLoaded; j+=1)
            String name = StringFromList(j, list)
            if (strlen(name) == 0)          // No more waves?
                break
            endif
            Wave testWave = $name
            SetBaseline(testwave)
        endfor
    endfor


Note that I store the wave name in the local string variable name. This makes is much easier to debug than this:
if (strlen (stringfromlist(i, S_waveNames)) == 0) // No more waves?
    break
 endif
 wave testWave = $(stringFromList(i, S_waveNames))


There is another problem here:

newWave= wave2treat-WaveMin(wave2treat)


This evaluates the righthand side once for each point in newWave. Thus you are calling WaveMin once for each point in newWave. Replace it with this:

Variable wMin = WaveMin(wave2treat)
newWave= wave2treat-wMin


Or, since newWave is a clone of wave2treat, you can do this which may be slightly faster:
Variable wMin = WaveMin(wave2treat)
newWave -= wMin


Thanks again for your help! it seems to be working fine now. I have another question though.. How do I now reference the waves that have been through the SetBaseline function? I want to normalize all the waves to the first wave processed by the function.

And another question while I'm at it. I want the waves to keep the name of the file when they are loaded. I've looked at some code, and I think I can manage to write it in, but the names of the files are more than 32 char. "2013 January 22 17_06_04-Frame-1.Csv" I was wondering if it was possible to delete characters from the beginning of the filename, instead of the end, since " 17_06_04-Frame-1" is the information I need?

Thanks again!
Quote:
How do I now reference the waves that have been through the SetBaseline function?


One way to do it is this:
String newWaveName=NameofWave(wave2treat)+"_base"   // Replicate what is done in SetBaseline
Wave newWave = $newWaveName


A better way is to have SetBaseline return a wave reference:
Function/WAVE SetBaseline(wave2treat) //Function
    wave wave2treat //wave reference
 
    . . . code that creates a new wave and a wave reference named newWave . . .

    return newWave
End

Then change the SetBaseline call to:
    Wave newWave = SetBaseline (testwave)
    <Do something with newWave>

Quote:
And another question while I'm at it. I want the waves to keep the name of the file when they are loaded. I've looked at some code, and I think I can manage to write it in, but the names of the files are more than 32 char. "2013 January 22 17_06_04-Frame-1.Csv" I was wondering if it was possible to delete characters from the beginning of the filename, instead of the end, since " 17_06_04-Frame-1" is the information I need?


With the caveat that I know only enough about regular expressions to be dangerous . . .

Function/S ExtractDatasetName(fileName)
    String fileName // e.g., "2013 January 22 17_06_04-Frame-1.Csv"
   
    String leadingJunkMatcher = "([[:digit:]]+ [[:alpha:]]+ [[:digit:]]+ )"
    String datasetNameMatcher = "([[:digit:]]{2}_[[:digit:]]{2}_[[:digit:]]{2}-[[:alpha:]]+-[[:digit:]]+)"
    String trailingJunkMatcher = "(\\.[[:alpha:]]+)"
   
    String regExp = leadingJunkMatcher + datasetNameMatcher + trailingJunkMatcher
    String dataSetName, leadingJunk, trailingJunk
    SplitString /E=regExp fileName, leadingJunk, dataSetName, trailingJunk

    return dataSetName          // e.g., "17_06_04-Frame-1"
End


You can test this like this:
Print ExtractDatasetName("2013 January 22 17_06_04-Frame-1.Csv")
L.K.Chris wrote:
And another question while I'm at it. I want the waves to keep the name of the file when they are loaded. I've looked at some code, and I think I can manage to write it in, but the names of the files are more than 32 char. "2013 January 22 17_06_04-Frame-1.Csv" I was wondering if it was possible to delete characters from the beginning of the filename, instead of the end, since " 17_06_04-Frame-1" is the information I need?


I try to avoid regular expressions as they can be "temper-mental" for lack of a better word. I would accomplish this by treating the file name like a string list with the space character as the list separator.

string filename
string subname

subname = stringfromlist(3, filename, " ")


After this you can do further manipulation to remove the ".csv" and you'll also want to replace the hyphens with underscores. Some operations in Igor will not accept hyphens are part of the name (such as window titles) so I've gotten into the habit of always removing them.