How to work with multiple waves in a loop
ananya.sen
I am a new user of Igor. I am trying to do a calculation in a loop which involves loading a text file which is a 2D matrix, storing it in a wave which has the dimension of my desired matrix and then doing a bunch of calculations with it and finally displaying a graph. I do this in a loop as I need to open multiple files at once. My problem is I am not being able to change the wave names at every iteration of the loop. So, to summarize my procedure starts by opening multiple files and loading them with separate wave names but as soon as I try to do calculations on them I can do that only once as it encounters the same wave in the second iteration and stops. Please can any one help me how to solve this problem. My procedure looks like this.
Function/S OpenMultiFileDialog()
Variable refNum
String message = "Select one or more files"
String outputPaths
String fileFilters = "Binary Files (*.bin):.bin;"
fileFilters += "All Files:.*;"
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")
GBLoadWave/B/T={80,80} path //Here I am loading my files in respective waves.
Duplicate/O wave0,rwave //Here I would like to change wave0 to wave1, wave2... at every iteration.
Redimension/N=(512,480) rwave
Make/N=(512,480)/W CDR
CDR=0.5*((rwave)+abs(rwave)) //I would like to change the wave CDR to CDR1.CDR2...at every iteration.
Display;AppendImage CDR;DelayUpdate
ModifyImage CDR ctab= {*,80,Rainbow,1}
ModifyGraph width=566.929,height=566.929
SetAxis left -0.5,512
endfor
endif
return outputPaths
end
Variable refNum
String message = "Select one or more files"
String outputPaths
String fileFilters = "Binary Files (*.bin):.bin;"
fileFilters += "All Files:.*;"
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")
GBLoadWave/B/T={80,80} path //Here I am loading my files in respective waves.
Duplicate/O wave0,rwave //Here I would like to change wave0 to wave1, wave2... at every iteration.
Redimension/N=(512,480) rwave
Make/N=(512,480)/W CDR
CDR=0.5*((rwave)+abs(rwave)) //I would like to change the wave CDR to CDR1.CDR2...at every iteration.
Display;AppendImage CDR;DelayUpdate
ModifyImage CDR ctab= {*,80,Rainbow,1}
ModifyGraph width=566.929,height=566.929
SetAxis left -0.5,512
endfor
endif
return outputPaths
end
Thank you very much.
displayhelptopic "Converting a String into a Reference Using $"
and the chapter IV-1 of the manual. It's worth to have a look.
Also have a look at
num2str
.HJ
March 1, 2016 at 01:59 am - Permalink
For the GBLoadWave operation, Igor will set the string S_waveNames with a semicolon list of the names of waves that were loaded. You can use this info to refer to the loaded waves.
Changes that I propose have comments beginning //***
Variable refNum
String message = "Select one or more files"
String outputPaths
String fileFilters = "Binary Files (*.bin):.bin;"
String sWaveName = "" //***
String sCDRname = "" //***
String sMsg = ""
fileFilters += "All Files:.*;"
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")
GBLoadWave/B/T={80,80} path //Here I am loading my files in respective waves.
sWaveName = stringfromlist(0, S_waveNames) //***Get name Igor assigned to loaded wave
if( strlen( sWaveName ) == 0 ) //***Make sure a wave was loaded; exit loop if not.
sMsg = "No Wave was loaded for iteration: " + num2str(i) //***error message
DoAlert /T="OpenMultiFileDialog", 0, sMsg //***post alert
break //***error, exit loop
endif
Duplicate/O $sWaveName,rwave //***Operate on the newly loaded wave.
Redimension/N=(512,480) rwave
sCDRname = "CDR" + num2str(i) //***name for new output wave
Make/N=(512,480)/W $sCDRname
Wave CDR = $sCDRname //***create reference to new CDRx wave
CDR=0.5*((rwave)+abs(rwave)) //I would like to change the wave CDR to CDR1.CDR2...at every iteration.
Display;AppendImage CDR;DelayUpdate
ModifyImage CDR ctab= {*,80,Rainbow,1}
ModifyGraph width=566.929,height=566.929
SetAxis left -0.5,512
endfor
endif
return outputPaths
End
March 1, 2016 at 05:55 am - Permalink
Thank you so much for your replies. I have been going through the display help topics you have mentioned, but it s an uphill struggle to get the theory to work in a short time. :) Thank you so much for the help jtigor. The procedure worked fine. I have now added few lines to subtract a background matrix from the loaded image file. This background matrix is loaded only once , so it needn't change with every iteration. However, in order to subtract it I needed to store it in different wave names at every iteration of the loop. I am not very comfortable with the procedure as I create copies of a wave which I don't really need. Is there a way out from this? Here is the total procedure .
I have indicated my additions with an arrow like this "<----" . Hope this is not too complicated.
macro background()
GBLoadWave/B/T={80,80}/W=1 "Usr1:b126lab:Desktop:20151130155509_Centroid512A.bin"
Rename wave0,b00
Redimension/N=(512,480) b00
Make/N=(512,480)/W/U b0
b0=2*b00
end
macro plot_background()
Display;AppendImage b0;DelayUpdate
ModifyImage b0 ctab= {*,80,Rainbow,1}
ModifyGraph width=566.929,height=566.929
SetAxis left -0.5,512
end
Function/S OpenMultiFileDialog()
Variable refNum
String message = "Select one or more files"
String outputPaths
String fileFilters = "Binary Files (*.bin):.bin;"
String sWaveName = "" //***
String sCDRname = "" //***
String sm0="" // <-----
String sMsg = ""
fileFilters += "All Files:.*;"
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")
GBLoadWave/B/T={80,80} path //Here I am loading my files in respective waves.
sWaveName = stringfromlist(0, S_waveNames) //***Get name Igor assigned to loaded wave
if( strlen( sWaveName ) == 0 ) //***Make sure a wave was loaded; exit loop if not.
sMsg = "No Wave was loaded for iteration: " + num2str(i) //***error message
DoAlert /T="OpenMultiFileDialog", 0, sMsg //***post alert
break //***error, exit loop
endif
Duplicate/O $sWaveName,rwave //***Operate on the newly loaded wave.
Redimension/N=(512,480) rwave
sCDRname = "CDR" + num2str(i) //***name for new output wave
Make/N=(512,480)/W $sCDRname
sm0="bb"+num2str(i) // <---- New output wave for background
Duplicate/O b0,$sm0 // <------ Duplicating the original background wave
Wave CDR = $sCDRname //***create reference to new CDRx wave
Wave m0=$sm0 // <------- Creating refernce for nrew background wave
CDR=0.5*((rwave-m0)+abs(rwave-m0)) //<------ I have subtracted the background wave here
Display;AppendImage $sCDRname;DelayUpdate
ModifyImage $sCDRname ctab= {*,80,Rainbow,1}
ModifyGraph width=566.929,height=566.929
SetAxis left -0.5,512
endfor
endif
end
Thank you once more. It is very encouraging to see the procedure working fine.
Ananya
March 1, 2016 at 09:58 am - Permalink
Here is a simple example:
Make/O wave0, wave1, wave2
String list = "wave0;wave1;wave1;"
Variable numItems = ItemsInList(list)
Variable i
for(i=0; i<numItems; i+=1)
String item = StringFromList(i, list)
Wave w = $item
Print NameOfWave(w)
endfor
End
March 1, 2016 at 11:18 am - Permalink
If I correctly understand what you want to do, you don't need to duplicate the background wave each iteration. Create a reference to it once, outside of the loop and use that same reference for each iteration of the loop.
If the background wave is in the current directory (same one image waves are loaded into) you can create the reference using
Wave b0
or
Wave b0 = b0
If the wave is in a different directory you need to give the path to it:
Wave b0 = root:subdir1:subdir2:b0
Variable refNum
String message = "Select one or more files"
String outputPaths
String fileFilters = "Binary Files (*.bin):.bin;"
String sWaveName = "" //***
String sCDRname = "" //***
String sm0="" // <-----
String sMsg = ""
fileFilters += "All Files:.*;"
Open /D /R /MULT=1 /F=fileFilters /M=message refNum
outputPaths = S_fileName
Wave b0 = b0 //*****reference to background wave
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")
GBLoadWave/B/T={80,80} path //Here I am loading my files in respective waves.
sWaveName = stringfromlist(0, S_waveNames) //***Get name Igor assigned to loaded wave
if( strlen( sWaveName ) == 0 ) //***Make sure a wave was loaded; exit loop if not.
sMsg = "No Wave was loaded for iteration: " + num2str(i) //***error message
DoAlert /T="OpenMultiFileDialog", 0, sMsg //***post alert
break //***error, exit loop
endif
Duplicate/O $sWaveName,rwave //***Operate on the newly loaded wave.
Redimension/N=(512,480) rwave
sCDRname = "CDR" + num2str(i) //***name for new output wave
Make/N=(512,480)/W $sCDRname
Wave CDR = $sCDRname //***create reference to new CDRx wave
CDR=0.5*((rwave-b0)+abs(rwave-b0)) //*****b0 is the background wave
Display;AppendImage $sCDRname;DelayUpdate
ModifyImage $sCDRname ctab= {*,80,Rainbow,1}
ModifyGraph width=566.929,height=566.929
SetAxis left -0.5,512
endfor
endif
end
March 1, 2016 at 01:00 pm - Permalink
Thank You!! Yes it works fine now without generating excess files. The only thing about the procedure which I find strange is if I want to load multiple files for the second time it tells me that there are waves of similar names present. So I added the following code to kill those waves before doing the calculation.
Redimension/N=(512,480) rwave
sImagename = "Image" + num2str(i)
If (WaveExists($sImagename)) //<-----
KillWaves $sImagename //<-----
endif //<------
Make/N=(512,480)/W $sImagename
Wave Image = $sImagename //Creating reference to new CDRx wave
Image=0.5*((rwave-b0)+abs(rwave-b0)) // Subtraction of the background wave.
Display;AppendImage $sImagename;DelayUpdate
The arrows indicate the added lines. When I write this, I get an error message saying " Waves which are part of a function, graph or XOP can't be killed". This is strange to me as I can very well go to the menu and delete those waves manually. I don't understand why the same function doesn't compile in a procedure.
Basically I want to do either of two things:
1. Kill waves which have similar names
2. Start the loop from the last value of i (of previous loop). This way I don't need to kill any waves. (I am struggling to write the procedure for this).
If this has been discussed before, can anyone send me the link to the thread please.
Thanks,
Ananya
March 2, 2016 at 01:03 pm - Permalink
You could
- simply overwrite the existing waves
Make /O /N....
- run your index and only create the wave if it does not exist
If (!WaveExists($sImagename))
(with or without recalculation of the existing ones)
- store the last used index and initialize the loop with that value (not recommended, error prone)
A way to find the first unused index would be a for-loop which only checks whether the corresponding wave exists and a second loop afterwards *without index initialization* doing the calculation. Copy the sample code to your procedure, adjust the "42" in the second loop to a number larger than your highest image number (but not much), and see what is does.
variable i
for (i=0;exists("Image"+num2str(i))==1;i+=1) // quite compact
endfor
for (;i<42;i+=1) // <-- nothing in front of ";"
print i // here could be your code for new data
endfor
end
Have a look at the online help for details of commands :-)
HJ
March 3, 2016 at 03:05 am - Permalink