How to make a pop-up menu list graph

Hello! I am a new user to Igor and I am currently trying to code a program that will create a pop-up menu that will graph a selected wave from a loaded Excel file. I need help graphing what is selected in the pop-up menu. I do not know how to make the pop-up menu control select the desired wave. Also, I need to reference the wave through order of being loaded in or by the number in the wave name (the number is at the end of the wave name). Some assistance would be appreciated!

function PopMenuProc(pa) : PopupMenuControl
        STRUCT WMPopupAction &pa

switch(pa.eventCode)
            case 2:
            Variable popNum = pa.popNum     // 1 - based item number
            String popStr = pa.popStr           // text of selected item
           
            if (!cmpstr(popStr,"1_txt")) // if wave names include 1, then the following will happen
                    wave /z Time__seconds_  // time_seconds wave is always referenced
                    wave /z AKAP_yfp_Orai11_mcherry_untagSTIM1_rest_1_txt      
                    Display AKAP_yfp_Orai11_mcherry_untagSTIM1_rest_1_txt vs Time__seconds_        
                    CurveFit/M=2/W=0 dblexp_XOffset, AKAP_yfp_Orai11_mcherry_untagSTIM1_rest_1_txt/X=Time__seconds_/D  
                endif
            break
        case -1:
        break       //control being killed
        endswitch

    return 0
end

 

First, it is important to know what will be the contents you select with your popup? Is it a wave from a list in the current folder (i.e., something you would get from WaveList())? Then the first part is very easy: Just use

Wave selection = $pa.popStr

This will convert the selected item (text) into a wave reference. If the selection is something else, then you need to explain first how your data is organized, what the popup selection should do and how one could possibly know about the wave from the selection (e.g., if your popup selects numbers which will be part of the wave name then one just needs to construct the name from the number).

Second part of your question:

  • If you want to go for time of being loaded => check  CreationDate(wave), and use ascending time value
  • If you want to go for a number in the wave name => you can parse the name of a wave for a number. If you tell us a bit more about what the format of your names are (e.g., myData_01) and what you want to do exactly, then we can suggest some code.

Thank you so much for your help! The suggested code worked great. However, I have another issue. 

 

If the user selects No, indicating they want to change the start/stop point, I want them to be able to use ShowInfo to manipulate the points. I also wanted to prompt the user to select their desired start/stop point (Start will always be 50 but stop can change). This desired stop point is B_value. My problem is that when the prompt shows up after the graph, the graph window can no longer be selected. I want the user to be able to interact with both the graph window and the prompt so that once they play around with different stop points, they can enter their desired stop point and it will be curve fitted. 

//  ask user if they like the graph; yes or no 
                DoAlert /T="Start/Stop Point", 1, "Are you satisfied with this start/stop point?"
                    if(V_Flag==1)
                        CurveFit/M=2/W=0 dblexp_XOffset, selection [50,389]/X=Time__seconds_[50,389]/D
                        DoUpdate
                        endif
                    if(V_Flag==2)
                        ShowInfo
                        PauseforUser/C Graph0
                        Prompt B_value, "Enter the desired stop point" 
                        DoPrompt "Enter_Stop_Point", B_value
                        CurveFit/M=2/W=0 dblexp_XOffset, selection [50,B_value]/X=Time__seconds_[50,B_value]/D
                        DoUpdate
                        endif

 

You need a panel as the "main" window for PauseForUser, such that when your user clicks the Done button in the panel, the panel commits suicide and that releases the PauseForUser. Having your graph as the second target of PauseForUser will leave the graph's UI still working. See the example in DisplayHelpTopic "PauseForUser Simple Cursor Example". It is almost exactly what you are trying to put together.

Here is an example for inspiration if you are looking for browsing through a series of waves instead of creating permanent graphs for each wave. Rolling your mouse wheel over the popup menu will scroll through the list of waves and display them in the graph.

Function MyFunction()
//  Creates a graph with a popup menu used to display the waves in the active datafolder

    //  Sets root: as the active datafolder
    SetDataFolder root:

    //  Creates three waves to chose from
    Make/O/N=100 root:Peter=sin(2*pi*p/100), root:Paul=cos(2*pi*p/100), root:Mary=2*sin(2*pi*p/20)
   
    //  Creates the wave to display in the graph. It is created in a different datafolder to avoid having it show up as a selection in the popup menu
    NewDataFolder/O root:MyFolder
    DFREF MyFolder=root:MyFolder
    Make/O/N=0 MyFolder:DisplayedWave/WAVE=DisplayedWave
   
    //  Creates the graph window
    DoWindow/K MyGraph
    Display/K=1/N=MyGraph DisplayedWave
   
    //  Creates a bit of white empty space at the top of the graph for the popup menu
    ModifyGraph /W=MyGraph margin(top)=30
   
    //  Creates the popup menu with the list of waves to display
    //  The WaveList call returns a semi-colon seperated list of all one-dimensional numeric waves in the active datafolder
    PopupMenu MyPopUp  bodyWidth=100, pos={80, 5}, mode=1, proc=MyPopUpProc, value=WaveList("*", ";", "DIMS:1,DF:0,CMPLX:0,TEXT:0,WAVE:0"), win=MyGraph
   
    //  Updates the graph with the selected wave
    MyUpdateFunction()
end



 Function MyPopUpProc(PU_Struct) : PopupMenuControl
//  Updates the graph with the selected wave
STRUCT WMPopupAction &PU_Struct

    //  If the selection was changed
    if  (PU_Struct.eventCode==2)
   
        //  Updates the graph with the selected wave
        MyUpdateFunction()
    endif
end



 Function MyUpdateFunction()
//  Updates the graph with the wave selected in the popup menu

    //  The location of the displayed wave
    DFREF MyFolder=root:MyFolder
   
    //  Finds the selected text in the popup menu
    ControlInfo /W=MyGraph MyPopUp
    String SelectedStr=S_Value
   
    //  Finds the name of the wave to display
    Wave/Z SelectedWave=$SelectedStr
       
    //  Checks if the selection is valid
    if (WaveExists(SelectedWave))
       
        //  Overwrites the displayed wave with the selected wave
        Duplicate/O SelectedWave MyFolder:DisplayedWave
    else
       
        //  Clear the display if the selected wave does not exist
        Make/O/N=0 MyFolder:DisplayedWave
    endif
end

 

In reply to by johnweeks

Thanks for your suggestion! The example was exactly what I needed. The very last part of my code involves using FindRoots and I have been having some issues with it. Using the dlbexp equation from CurveFit, I was trying to solve for x. In order to do that I tried using FindRoots. Before using the actual command, I followed the "Function Format for Systems of Multivariate Functions" example under "FindRoots" in Igor Reference and keep running into the same error that says "While executing a wave read, the following error occurred: Index out of range for wave "coefs". The code compiles but it does not run correctly. 

I'd really appreciate some assistance with this because FindRoots is a very confusing command for me.

//  y-half calculation  //
   
    wave /z w_coef
   
        variable y0             // define variables from w_coef wave
        y0 = W_coef[0]
        variable A1
        A1 = W_coef[1]
        variable tau1
        tau1 = W_coef[2]
        variable A2
        A2 = W_coef[3]
        variable tau2
        tau2 = W_coef[4]
       
        variable x0
        x0 = 13.215
   
    function Y_half_calc(w_coef,x)
        wave /z w_coef
        variable x
        return W_coef[0] + W_coef[1]*exp(-(x-13.215)/W_coef[2]) + W_coef[3]*exp(-(x-13.215)/W_coef[4])
       
        Make/D/O Y_half_coefs={0, 1, 2, .5}                     // an offset by 0.5
        Make/D/O Y_half_wave                                        // a wave with 128 points   // give it an X range of (-10, 10)??
        SetScale/I x -100,100,Y_half_wave
        Y_half_wave = Y_half_calc(Y_half_coefs, x)              // fill it with function values                            
        Display Y_half_wave                                         // and make a graph of it
        ModifyGraph zero(left)=1                                    // add a zero line to show the roots
        ModifyGraph minor(bottom)=1                             // add minor ticks to the graph
       
        end

 

That piece of code is very strange. You have a function Y_half_calc that's calling itself over and over again for every point in Y_half_wave, and for every call a new graph is created. I have no idea what you are trying to accomplish with the code to be honest.

In reply to by olelytken

I was trying to find solve for x in the double exponential offset equation. When I searched for a way to do this, I was directed to FindRoots. Under Command Help, FindRoots has an example called "Function Format for Systems of Multivariate Functions". I loosely followed that example and what is shown above is from that example, including using x as a variable. 

What I am trying to use the code for is finding the halfway point between the end of my curve-fitted graph and the end of it. I found that solving the double exp offset equation would give me this value. 

Update:

I am no longer trying to use FindRoots for this equation. I am nearing the last part of my code but need assistance. I used CTRL+I to ShowInfo on my graph. There are number points, and an x and y value for each point. I want to be able to reference these points and have the graph find the number point that is closest to a specific Y value I want. I also want it to print the shown x value for the number point. I just don't know how to reference them. 

To your last Update question, to find values for cursors on a trace, look to functions such as xcsr and pcsr.  The CsrWave function, which returns the name of the wave the cursor is on, may be of use as well. 

I looked into using these commands so I'm glad to know my thoughts were in the right place. I have another question. Is it possible to accurately use BinarySearch to search for a wave that has a value with $ in it?

What do you mean? BinarySearch() looks for numerical expressions in numerical waves. It is not possible for such a wave to contain the '$' character.

In reply to by chozo

I just figured it out a few minutes ago but I was referring to a wave that has a value that has the $ character. For example " wave selection = $pa.popStr ". I wanted to know if the wave "selection" could be used with BinarySearch() to search for the wave for a numerical expression. I was able to get it to work.

Now that I have done this, I need to reference a _calculated_ wave. Is this possible?

In reply to by ilavsky

I tried using the x scaling for my original wave but the values are off. The x scaling for the curve is Time__seconds_[50, b_value] and the x for the original wave is Time__seconds_. The variable b_value is the end-point of the x-scaling. Is there a way to put the x-scaling in the wave reference to Time__seconds?

Update:

I ended up just using pnt2x since I had my desired point number for the curve fit graph. Much thanks to everyone that's helped me with me code. I really appreciate the assistance and patience while I've been learning Igor.