Is it possible to Setscale by Wavelist

Hi

I'm trying to make my program more flexibility, I've got some data with many layer.

I wrote my code like following code in the first time, but if the height of layer change, I have to change all numbers in code by hand, is it possible to Setscale by Wavelist or some other function?

setscale/I x,Dates[0],Dates[(numpnts(Dates)-1)],"dat", Spd196,Spd176,Spd156,Spd136,Spd116,Spd96,Spd76,Spd56,Spd36,Spd16
setscale/I x,Dates[0],Dates[(numpnts(Dates)-1)],"dat",Dir196,Dir176,Dir156,Dir136,Dir116,Dir96,Dir76,Dir56,Dir36,Dir16

 

Are you writing your own procedures? It is very easy to loop trough waves or pick from a list of waves with WaveList.

Here is a start:

string AllWavesInFolder = WaveList("", ";", "")
variable i
for (i=0;i<ItemsinList(AllWavesInFolder); i+=1)
    wave workwave = StringFromList(i, AllWavesInFolder)
    setscale/I x,Dates[0],Dates[(numpnts(Dates)-1)],"dat", workwave
endfor

or

variable i
for (i=startvalue;i<=endvalue; i+=1)
    string baseName = "Spd" + i // may use sprintf for more controlled output, e.g. to get Spd001
    wave workwave = $baseName
    setscale/I x,Dates[0],Dates[(numpnts(Dates)-1)],"dat", workwave
endfor

 

In reply to by chozo

I agree that it would be nice if this and a few other functions could take in a string list. A route I sometimes take, when I don't want to go write a whole function for a few special cases, is to use the function at the bottom of this post. The upside is that you don't have to write code, though you would have to copy that function into a Procedure file and have it compiled in the instance of Igor. Then you could run a command like the following:

//something like this would be run at command line:
String wavesToSet="Spd196,Spd176,Spd156,Spd136,Spd116,Spd96,Spd76,Spd56,Spd36,Spd16"
list_operation_g("setscale/I x,Dates[0],Dates[(numpnts(Dates)-1)],\"dat\",%s",wavesToSet,delim=",") //note: delim would be unnecessary if using semi-colons to delimit the list

 

//iterates through strList, substituting any %s in macroStr with the current list item
//and substituting any %i with the current list index, then executing macroStr
function list_operation_g(macroStr,strList,[start,num,delim,iterateWaveColInstead])
    String macroStr     //macro to execute e.g, display/k=1 %s to plot waves in list
    String strList      //list to iterate over (e.g., names of waves)
    Variable start,num      //for specifying a subrange of strList
    variable iterateWaveColInstead  //optionally pass to iterate down a wave column, column number is passed and wave name is in strList.. pass -1 to use row labels
    String delim        //expects semi-colon delimited strList, pass to use another delimiter
   
    String delimUsed
    if (ParamIsDefault(delim))
        delimUsed=";"
    else
        delimUsed=delim
    endif
   
    Variable i,ind; String executeStr, listStr
    if (!ParamIsDefault(iterateWaveColInstead) && !numtype(iterateWaveColInstead) && (iterateWaveColInstead>-2))
        String ref=strList
        WAVE/T wv=$strList
        strList=""
        Variable rows=dimsize(wv,0)
        if (iterateWaveColInstead < 0)  //==-1 so row labels
            for (i=0;i<rows;i+=1)
                strList+=getdimlabel(wv,0,i)+delimUsed
            endfor     
        else
            for (i=0;i<rows;i+=1)
                strList+=wv[i][iterateWaveColInstead]+delimUsed
            endfor
        endif
    endif
   
    Variable startInd = ParamIsDefault(start) ? 0 : start
    Variable numItems=ItemsInList(strList)
    Variable maxItems=numItems-startInd
    Variable numInds = ParamISDefault(num) ? maxItems : min(startInd+num,maxItems)
    for (i=0;i<numInds;i+=1)
        ind=i+startInd
        listStr=stringfromlist(ind,strList,delimUsed)
        executeStr = replacestring("%s",macroStr,listStr)
        executeStr = replacestring("%i",executeStr,num2str(i))
        Execute/q executeStr
    endfor
end

 

Thank you for your advices, function is still new to me, I usually use macro to write procedures, I'll take my time to study how to write function, thanks again.

In reply to by chozo

I try to write a loop in function, but program return "expected assignment operator" error to me, which point at StringFromList(num,strList), did I wrote something wrong ?

list_operation(Wavelist("Spd*",";",""),Dates)

/=======

Function list_operation(strList,timewave)

string strList
Wave timewave
variable num=0
for (num=0;num<ItemsinList(strList); num+=1)
    wave workwave = StringFromList(num,strList)
    setscale/I x,timewave[0],timewave[(numpnts(timewave)-1)],"dat", workwave
endfor

Here is another way to do it, which creates a wave-reference wave and runs an operation on all waves in the wave-reference wave.

Function Test()
//  Runs SetScale on all waves in root:

    //  Looks for waves in root:
    DFREF Folder=root:

    //  Counts the number of waves in the folder
    Variable n=CountObjectsDFR(Folder, 1)

    //  Creates a list of all waves in the folder
        //      WaveList would give you the same information,
        //      but as a string list instead of a wave-reference wave
    Make/FREE/O/WAVE/N=(n) AllWaves=WaveRefIndexedDFR(Folder, p)

    //  Runs SetScale on all waves in AllWaves. You could replace Start,
        //      Delta and UnitStr with waves to use different values for the different waves
    Variable Start=10
    Variable Delta=2
    String UnitStr="Apples"
    AllWaves[]=MySetScale(Start, Delta, UnitStr, AllWaves[p])
        //     This could also be done with a for loop
end



Function/WAVE MySetScale(Start, Delta, UnitStr, MyWave)
Variable Start, Delta
String UnitStr
Wave MyWave

    //  Runs SetScale on MyWave
    SetScale/P x, Start, Delta, UnitStr, MyWave

    //  Allows the function to work without a for loop 
    Return MyWave
end

 

olelytken's approach of using WAVE reference waves is, in my opinion, the "right" way to do this. If the list of waves ever gets very large, you will get much better performance if you only need to look up the wave from a name once and then use those wave references for the rest of the work.

In Igor 7 and later, you can use the ListToWaveRefWave function if you have a string list of wave names, such as what you might get from WaveList, or in gsb's example above.

As a bonus, olelytken's code above could be improved slightly by declaring MySetScale as ThreadSafe and then using the MultiThread keyword in the wave assignment statement in Test(). Here's the modified code:

Function Test()
    //  Runs SetScale on all waves in root:

    //  Looks for waves in root:
    DFREF Folder=root:

    //  Counts the number of waves in the folder
    Variable n=CountObjectsDFR(Folder, 1)

    //  Creates a list of all waves in the folder
    //      WaveList would give you the same information,
    //      but as a string list instead of a wave-reference wave
    Make/FREE/O/WAVE/N=(n) AllWaves=WaveRefIndexedDFR(Folder, p)

    //  Runs SetScale on all waves in AllWaves. You could replace Start,
    //      Delta and UnitStr with waves to use different values for the different waves
    Variable Start=10
    Variable Delta=2
    String UnitStr="Apples"
    Multithread  AllWaves[]=MySetScale(Start, Delta, UnitStr, AllWaves[p])
    //     This could also be done with a for loop
end



ThreadSafe Function/WAVE MySetScale(Start, Delta, UnitStr, MyWave)
    Variable Start, Delta
    String UnitStr
    Wave MyWave

    //  Runs SetScale on MyWave
    SetScale/P x, Start, Delta, UnitStr, MyWave

    //  Allows the function to work without a for loop  
    Return MyWave
end

 

Ooops, forgot the $ in my original post. So much for not testing my suggestions. It's probably a bit too late but anyway, if you want to read more about this execute in the command line:

DisplayHelpTopic "Converting a String into a Reference Using $"