Wave reference confusion in code
Hi,
Kindly see the attached image for code.
I am sure that this has a straightforward solution but I am somehow stuck.
I have a 1D textwave called "analytename" that contains names. I also have a 2D wave called "dataJan2231". Each column of dataJan2231 is a timeseries for the names listed in the 1D wave analytename. The first thing I needed to do was to extract each column from the 2D wave as a 1D wave and name those individual 1D waves according to the names contained in "analytename". This I succeeded in doing as shown in the first 9 lines of code.
Now, the next step is where I am stuck. Within the same 'for loop' (on line 5 in attached code) that extracts a column from dataJan2231 into an individual 1D wave and gives it a name, I am also trying to run a code that takes the same newly made 1D wave and generates another 1D wave that is a time-averaged version of this wave (e.g. the original new 1D wave is per second timeseries and the time-averaged version will have hourly averages of it).
So in summary, within the same for loop, a column is extracted from the 2D wave as a 1D wave, the 1D wave gets named and then is hourly-averaged. The hourly-averaged data is put into a new 1D wave.
As marked in the code with yellow and green on lines 9 and 11, I somehow need the code to understand that- $name - is the name of the input wave at "wave2avg" and "waveAvg" needs to be the output wave with name- $name_avg. I just can't figure out how to do this. I would be very thankful for your advice!
Many Thanks and Regards,
Peeyush
Yes, wave referencing can be confusing at times, but here is a simple rule you can work with: In principle, you have to create a wave reference using the Wave declaration, but in some cases internal functions will do that for you (also always only for simple object names, i.e., not involving $ or something). It does not hurt however, if you add a proper wave declaration anyway, and only leave it out when you are sure what you are doing (for example, when having an obvious simple command like make wave0).
In your case, you have several options how to proceed. First, I assume your average wave does not exist, and you have to create it as well. The first and most recognizable option is always to give a wave declaration after the make command:
Make/D/O/N=(DimSize(dataJan2231,0)) $(name+"_avg")
Wave wave2avg = $name
Wave waveAvg = $(name+"_avg")
Now you can work with both later on. A second option lately is to use a special flag inline. This one is actually not documented for the individual commands, if I see correctly, but you can read more about it here:
DisplayHelpTopic "Inline WAVE Reference Statements"
Anyway, it goes like this:
Make/D/O/N=(DimSize(dataJan2231,0)) $(name+"_avg") /wave=waveAvg
Note that you should not use make/WAVE, which is instead the flag to create wave-reference waves.
A third option, which should rather be avoided and does not work with wave assignments is to just use the $ operator every time. It is OK for a short succession of operations, I guess. This is what you have used in your code as well:
Redimension/N ... $name
Hope that helps.
August 24, 2020 at 10:39 pm - Permalink
Hi Chozo,
Thanks a lot for such a detailed response and tips! So my issue got resolved and the program compiled, but when I tried to run it, it gave the following error:
"While executing WaveStats, the following error occurred: Expected wave name" .. couldn't figure out why this should happen..
wave/T analytename
wave dataJan2231
//wave startwav,endwav
//killwaves/Z stopWave,startWave
//duplicate endwav,stopWave
//duplicate startwav,startWave
variable i
for(i=0;i<dimsize(dataJan2231,1);i+=1)
string name = analytename[i]
killwaves/Z $name
make/n=(dimsize(dataJan2231,0))$name
Duplicate/O/RMD=[][i+1] dataJan2231,$name
Redimension/N=(dimsize(dataJan2231,0))$name
killwaves/Z $(name+"_avg1")
//duplicate timewave,timeWave
make/n=(dimsize(dataJan2231,0))$(name+"_avg1")
wave wave2avg=$name
wave waveAvg=$(name+"_avg1")
waveAvg=nan
Wave timeWave, wave2avg, waveAvg, startWave, stopWave
variable WASflag
variable start, stop, numpts_start=numpnts(startWave)
//Different author--------
for(i=0;i<numpts_start;i+=1)
start = FindFirstGE(timeWave, startWave[i], start)
if (WASflag)
stop = FindRightMostLE(timeWave, stopWave[i], stop)
else
stop = FindRightMostL(timeWave, stopWave[i], stop)
endif
if (stop < start) // catch index out of range error. (e.g. if there are WAS cans taken after end of flight.)
continue
endif
if (WASflag)
if ( (timeWave[start]>=startWave[i])&&(timeWave[stop]<=stopWave[i]) )
WaveStats/M=1/Q/R=[start,stop] wave2avg
waveAvg[i]=V_avg
endif
else
if ( (timeWave[start]>=startWave[i])&&(timeWave[stop]<stopWave[i]) )
WaveStats/M=1/Q/R=[start,stop] wave2avg
waveAvg[i]=V_avg
endif
endif
//-----------
endfor
endfor
end
August 25, 2020 at 10:48 am - Permalink
Never mind, I just got the code to run. I had to remove the wave reference for wave2Avg and waveAvg from the second place. However, the code is only running for the first name in the analytename textwave and generating just one 1D wave, when it is supposed to do the same processing for all names and generate multiple 1D waves. Wondering why this should be case..
August 25, 2020 at 10:54 am - Permalink
Yes, having the second Wave declaration overwrites your first one with the implicit
Wave wave2avg = currentfolder:wave2avg
Anyway, it seems like you are trying to fit different pieces of code together in the whack-a-mole error hunting style. In my experience it is often faster to build the code piece by piece and test that everything makes sense and works instead of copying large chunks over. For example, you are running two for loops with the same counter i. I guess this is your current problem, since the inner loop exhausts the counter and makes your outer loop stop after the first execution.
August 25, 2020 at 11:05 am - Permalink
In reply to Yes, having the second Wave… by chozo
Thanks! Finally got the entire code to work. The same counter was the issue.. but for next time, I will take your advice on building a code piece by piece. Thanks a ton for your advice and inputs!
August 25, 2020 at 11:27 am - Permalink
One quick question: Could you please advise on how to name individual columns of a 2D wave? Lets say I have a (10,5) 2D wave. Now, besides column index, I wish for each column to have a name from a 1D text wave that contains names. Much thanks!
August 25, 2020 at 11:29 am - Permalink
Hi
I have started using dimlabels quite a bit. For example instead of passing global variables, I have a single wave and then label each row with the name. When I create a function I only need to pass the single wave which makes code maintenance much easier. Also if I put the wave in a table I can see all my "variables" and their values. Very handy.
To set the column label is the similar to row label setting. Note there are some constraints on the text for the label.
From manual:
SetDimLabel dimNumber,dimIndex,label,wavelist
The SetDimLabel operation sets the dimension label or dimension element label to the specified label.
Parameters
dimNumber is one of the following:
0: Rows
1: Columns
2: Layers
3: Chunks
In this case label is the exact text that label will take, but you can use $textwave[0] and it will use the value from the first point of text wave as the label.
Andy
August 25, 2020 at 11:37 am - Permalink
For this SetDimLabel is your friend. You need to call this command once for each column in your wave, either in a loop or like:
SetDimLabel 1,1,'this is another Name', my2Dwave
SetDimLabel 1,2,$setFromString, my2Dwave
String nameFromWave = my1Dtextwave[2]
SetDimLabel 1,3,$nameFromWave, my2Dwave
SetDimLabel 1,4,'names are limited to 255 bytes', my2Dwave
August 25, 2020 at 11:42 am - Permalink
Hi Chozo and Andy,
This is great and I have made notes. Thanks a lot for these tips!
Sincerely,
Peeyush
August 25, 2020 at 12:48 pm - Permalink