How to access and save individual wave from TraceNameToWaveRef("", traceName)

I have two trace ( trace 1 and trace 2) in a graph that I want to subtract (y value ). Incidentally my x waves are different (actually x value are same but the name of the x wave is different so the traces are = trace1 = {yw1 vs xw1 } and trace 2= {yw2, xw2 } where actually xw1 = xw2 point by point.

Usually I drag one of the trace (trace 2 ) to the other and use the code of by "Rgerkin" and then I have two trace in a single graph.
Now when I use "tracename" and use TraceNameToWaveRef("", traceName) and generate y wave and x wave (yw and xw).

Since it is in a loop it access the traces trace1 and trace 2 sequentially and thereby the last yw and xw is always from trace 2.
How I can save the trace 1 in an another variable or use a array function to save the trace1 : xw and yw (say yw1 and xw1) and then can save the trace from the 2nd trace : xw2 and yw2 and then I can do the required subtraction yw=yw2-yw1.

Although in my case the x a values are same (although x waves names are different)..but in case I have a situation whether the x values are different ( point by point ) .., just curious to know ..is it possible to plot yw or I have to interpolate or have to choose either xw1 or xw2 to plot yw ?

String list = TraceNameList("", ";", 1)
String traceName
Variable index = 0

do
traceName = StringFromList(index, list)
if (strlen(traceName) == 0)
break // No more traces.
endif

wave yw = TraceNameToWaveRef("", traceName)
wave xw = XWaveRefFromTrace("", traceName)
------------------
?? need to save in a array yw1 and yw2
---------------

index += 1
while(1)
end


// Want to do the subtraction  
yw=yw2-yw1

The obvious straightforward method:
Function test()

    String list = TraceNameList("", ";", 1)
    String traceName
    Variable index = 0
 
    traceName = StringFromList(0, list)
    if (strlen(traceName) == 0)
        DoAlert 0, "No YW1"
        return -1
    endif
    wave yw1 = TraceNameToWaveRef("", traceName)
    wave xw1 = XWaveRefFromTrace("", traceName)

    traceName = StringFromList(1, list)
    if (strlen(traceName) == 0)
        DoAlert 0, "No YW2"
        return -1
    endif
    wave yw2 = TraceNameToWaveRef("", traceName)
    wave xw2 = XWaveRefFromTrace("", traceName)
 
    index += 1
 
    // probably need to make this more general...
    Duplicate/O yw1, MyNewWave
    // Want to do the subtraction  
    MyNewWave=yw2-yw1
end

If you *really* want a loop, you will need to make a wave wave (look up the Make command and read about Make/WAVE). In the loop, fill in the wave wave with references to the waves you want.

By the way, the second igor tag needed to be slash-igor to close the code segment.

John Weeks
WaveMetrics, Inc.
support@wavemetrics.com
Thank you so much JohnWeeks...that exactly what I was looking for....thanks a lot.
Yes I corrected the tag..thanks
For the case of when the x-waves are different, you need to take the maximum and minimum values into consideration. For instance if xw1 goes from 1-40 and xw2 goes from 10-50, you cant subtract the y values which correspond to x values 1-9, or 41-50 (you can only subtract two numbers if they exist). This can be accomplished by only subtracting from max(xw1[0],xw2[0]) to min(xw1[inf],xw2[inf]). That is, largest of the small values to the smallest of the large values (excluding the outside ranges which do not match).

Next, choose one wave as the basis for your for loop (assuming they have different intervals). For example, I am going to choose xw1. For each value of xw1 in this range (10-40 for the above example numbers), you will need to use interp on yw2. If you always have the case where the intervals of xw1 and xw2 are scalar multiples of eachother, you can avoid using interp but always having the result wave have the same interval spacing as the wave with the fewest datapoints (lowest resolution) and just ignoring the extra data points in the other wave.

yw[i] = yw1[i] - interp(xw1[i], xw2, yw2)

where i is the current iteration in your for loop covering the range from 10-40 (again for my example numbers).

I'm vaguely aware of a notation involving the ? symbol that applies a math operation to only a section of a wave, but I'm not sure if that can be used in here place of a for loop (considering interp is required).

Sorry for writing you late. Thanks Proland for your clear explanation. Incidentally this time my "x" axis are equal ...but soon I will have situation whether the "x"s are different and I would need your method.
Hi
I wanted to show on a panel the name of the wave subtracted : i,e
WaveSubtracated = StringFromList(1, list)- StringFromList(0, list)

with what control I can show it, ValueDispaly is only for numeric value not for string, I tried listbox ...also didnt work.
If you want it for display purposes (read-only) you can use a titlebox. Just change the title of the titlebox to be the new wave name. Fundamentally, this isn't very different than using a SetVariable control, where you change the string that is linked to the control.

string NewTitleStr
titlebox box1 title=NewTitleStr
Before you get too deep into this, you might want to check out the Wave Arithmetic package. To load it, select Analysis->Packages->Wave Arithmetic. You may wish to look at a demo first: File->Example Experiments->Analysis->Wave Arithmetic Panel Demo. It handles the cases of overlapping but not identical X ranges, as well as X values that are not coincident (it interpolates Y values to handle this). If you look at the code, you will see that it is fairly complex keeping track of all the cases that must be handled.

John Weeks
WaveMetrics, Inc.
support@wavemetrics.com
Thanks to Proland...titlebox works great...Thanks to Johnweeks ..you are right....indeed I will not dive so deep...as I am aware of my limited knowledge in Igor..so I stayed with same xw ..and plotted with same xw....indeed Arithmetic Panel is great ...but as I had to work with many sets of graph, I thought wrote something tailor made would be easy to use for me…I checked codes for it…it seems extremely complex … I thought to so something simple....I need little help.

The code beneath (part of my bigger program) does the subtraction and works on Graph with two trace...Mainly what I want to do is to have option in subtraction (arithmetic) so that using setvar0 and setvar1 control I can define MyNewWave…for example say MyNewWave=
 2(wave0)- wave1 where  setvar1=wave0 and  setvar1=wave1 which I say typed in the servar box. Now in present condition it is always hardcoded as  wave2-wave1 or  wave1-wave2 (if checkbox 1 is checked) .

If tried to declare setvar as string ...and tried to access setvar value as MyNewWave ( say MyNewWave=2(setvar0)-setvar1..where I say handtyped
setvar1=2(wave0)
setvar2=wave1
...but it always gives error..
How can I have this...Pl find atta..the ipf file and one Graph containing two trace

#pragma rtGlobals=1     // Use modern global access method.

Menu "Test Subtrac"
      "Test SubtractA/1", Panel10()
End

Variable/G

Window Panel10() : Panel
PauseUpdate; Silent 1
NewPanel /W=(80,40,358,280)

titlebox box1, pos={52,70},size={130,20}, title= "wave1-wave2"
Button button1, pos={52,100},size={130,20}, proc=iSubtractTraceButton,  title="Subtract Traces"
CheckBox Check1,pos={52,130},size={39,14},title="Reverse",value= 0
SetVariable setvar0  pos={52,150},size={130,20}, value= _STR:"wave0"
SetVariable setvar1  pos={52,170},size={130,20}, value= _STR:"wave1"

EndMacro

Function iSubtractTraceButton(cntl) : ButtonControl
String cntl
Button $cntl
itestsubtract()
End

Function itestsubtract()
 
    String list = TraceNameList("", ";", 1)
    String traceName
    Variable index = 0
       NVAR setvar1
       NVAR setvar1
       Variable Conf1
       
       ControlInfo /W=Panel10 Check1
                 Conf1= V_value
 
    traceName = StringFromList(0, list)
    if (strlen(traceName) == 0)
        DoAlert 0, "No YW1"
        return -1
    endif
    wave yw1 = TraceNameToWaveRef("", traceName)
    wave xw1 = XWaveRefFromTrace("", traceName)
 
    traceName = StringFromList(1, list)
    if (strlen(traceName) == 0)
        DoAlert 0, "No YW2"
        return -1
    endif
    wave yw2 = TraceNameToWaveRef("", traceName)
    wave xw2 = XWaveRefFromTrace("", traceName)
 
    index += 1

       Duplicate/O yw1, MyNewWave

    string NewTitleStr
   
     if (Conf1)
     MyNewWave=yw2-yw1
    // MyNewWave=setvar0 - setvar1
     NewTitleStr =StringFromList(1, list) + " - " + StringFromList(0, list)
  //   setvar0  = NewTitleStr
  // setvar1 = StringFromList(1, list)
     
                   else
    MyNewWave=yw1-yw2
    NewTitleStr =StringFromList(0, list) + " - " + StringFromList(1, list)
         endif
         
 titlebox box1, pos={52,70},size={130,20}, title= NewTitleStr
   
    AppendtoGraph MyNewWave vs xw1
    display MyNewWave vs xw1
end
I downloaded the experiment that you attached. When I click the Subtract Traces button, I get an error message "Can't find the control's action procedure named 'SubtractTracesButton'". This makes sense because there is no SubtractTracesButton procedure in the experiment.

I then copied the procedures that you posted thinking perhaps they contained the SubtractTracesButton procedure, but no, they don't.

It would be much easier if you would provide a self-contained experiment including all necessary procedures. You can do this by either pasting the procedures in the built-in procedure window or adopting (File->Adopt Procedure) a standalone procedure file. To learn about adopting, execute:
DisplayHelpFile "Adopting a Procedure File"


I now see that the panel in the SumRay.pxp file is obsolete as it has only one SetVariable. If I run, Panel10 I get a new panel with two SetVariables. But still no SubtractTracesButton procedure.

I also note that your Panel10 macro is missing the End statement.

Finally, here is an implementation of the SubtractTracesButton function:
Function SubtractTraces(panelName) 
    String panelName
   
    ControlInfo /W=$panelName setVar0
    String firstWaveName = S_Value          // e.g., "wave0"
    Wave firstWave = $firstWaveName     // Create wave reference
   
    ControlInfo /W=$panelName setVar1
    String secondWaveName = S_Value         // e.g., "wave1"
    Wave secondWave = $secondWaveName   // Create wave reference
   
    Duplicate /O firstWave, MyNewWave
    MyNewWave -= secondWave
End

Function SubtractTracesButton(ba) : ButtonControl
    STRUCT WMButtonAction &ba

    switch( ba.eventCode )
        case 2: // mouse up
            SubtractTraces(ba.win)
            break
        case -1: // control being killed
            break
    endswitch

    return 0
End


This would be better named as SubtractWaves because it does not have anything to do with graphs or traces in graphs. But perhaps that is something you intend to implement later.


I am really sorry hrodstein..indeed it was my mistake as the same ipf file I had inside the igor procedure folder ..and when saving I did some mistake.......now I corrected (subtractTrace button) and I upload the proper ipf with data file....I still didnt include your addition..I have to include that...thank you so much...now I understand how to use the setvar.
Thanks hrodstein....thank you so much...I still have some problem ..can you give me clue..

1) How can I "parse" the string typed in a setvar input box ...such that if I type 2*wave0 in setvar0 field...then after parsing it should set S_Value = wave0 i,e the true wavename ..not 2*wave0..while "2" will be set as coeff so that in next stage of subtraction it can do
coeff* wave0-wave1..... is there any builtin parsar in Igor.

2) I want to populate the setvar0 and setvar1 field by the "wave name" that exist in a current trace ( as then I dont have to type...) ..I tried to use
traceName = StringFromList(0, list)
ControlInfo /W=panel10 setVar0
S_Value= traceName


but it does work..
I would recommend a separate setvar for the scalar multiplier. This eliminates the need to parse the string. While splitting the string is possible, you would require the user to be consistent. Splitting "2*wave0" or "wave0*2" are two completely different things.

In regards to setting the value of the setvariable, you do not use ControlInfo.

Instead, use

tracename = stringfromlist(0, list)
Setvariable setVar0 value = _STR:tracename


To update a control, use the same commands you used to make it. Note that you only need to include those which you wish to change (I didn't change the position or size above).
Thanks Proland...extremely sorry for writing so late...just took me some time to come back and again started coding in Igor...
indeed your solution

tracename = stringfromlist(0, list)
Setvariable setVar0 value = _STR:tracename


works for me very well..now I can list the waves ..

Thank you so much.