# 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

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
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
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)
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.

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"
//     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 \$"`