You can write your own software routines (or "procedures") using Igor Pro®'s built-in programming language. These routines are entered as text in "procedure windows":

procedure window containing examples of Igor's programming language

In addition to the main procedure window named "Procedure" (which is inseparable from the current Igor Pro® "experiment"), additional procedure windows may used to organize your work or to re-use routines previously written by the user or others. Igor ships with about 200 such procedure files written by WaveMetrics programmers.

You can use Igor's built-in programming language to call built-in functions and "operations", of which there are a considerable number (about 550). The Help menu´s Command Help item is a useful guide to these, and contextual help menus provide templates and quick access to documentation.

Procedure windows can also contain text that causes Igor to:

  • Load ("include") other procedure files
  • Define constants
  • Define new user-defined menus or menu items

User-defined Functions

User-defined functions are quite similar to functions written in C, Pascal, or modern Fortran and are compiled for speed.

Parameters and Return Values

Functions have parameters and return values. Parameters can be passed by value or by reference. They can be numbers, strings, structures, or references to arrays ("waves") of data. The parameters can be required or they can be optional.

Here's a simple function that counts the number of data values that exceed a given number:


Local and Global Variables

Like nearly every other procedural language, Igor´s language supports local (or "stack") variables (and strings and structures) that vanish when the routine containing them ceases execution.

In the example above the parameters w and value and the local variables exceed, i, and n exist only while the CountValuesThatExceed function is running. Afterwards only the returned value exists, either in the calling routine or in a global if assigned there. For example:

Variable/G gCount= CountValuesThatExceed(wave0,100)

creates a global variable gCount whose value is the returned exceed value. gCount will continue to exist after the end of command execution, and can be observed in Igor´s Data Browser.

Parameters passed by Reference

In Igor, arrays of data are always global objects: they are always passed into a routine by reference as a local "wave reference" parameter. In the example above, w is such a wave reference parameter.

Other kinds of parameters are passed by value unless specifically declared to be pass-by-reference using a convention borrowed from C++:

Function CountTwoThings(w, thing1, thing2)
    Wave 1
    Variable &thing1, &thing2
    thing1=0; thing2=0
    if( ... )
        thing1 += 1
    if( ... )
        thing2 += 1

When CountTwoThings is invoked:

Variable loc1, loc2 // two local variable in the calling routine
CountTwoThings(aWave, loc1, loc2)

the values of loc1 and loc2 in the calling routine are changed by CountTwoThings, in a manner familiar to most Fortran programmers.

Without the & character in CountTwoThings, loc1 and loc2 would be passed by value (copied into CountTwoThings), and remain unaffected by assignment and incrementing inside that routine.

Flow-control Commands

Igor´s language is a go-to-less "structured" procedural language with many of the standard modern flow-control constructs, and a few others. Here are some examples:

        thesum += wave[i];
        i += 1;
    while( i < n )
    for( j=0; j < n*2; j += 2 )
        thesum += wave[j];
    if ( i < j )
        val = j - i;
    elseif( i > j )
        val = i - j;
        val = 0
strswitch-case-endswitch ("string switch")
        case "revert"// literal string or string constant
            val= 2
            break   // without this execution "falls through" to val=1
        case "okay":
            val= 1
            val= 0
switch-case-endswitch ("numeric switch")
        case 0:         // literal number
        case kMyConstant:   // Constant kMyConstant =<some value>
            val= 1
            val= 2
        // test denominator
        if( denominator==0 )
            AbortOnRTE      // this is like C++´s "throw"
        // use denominator
        val= numerator / denominator
        // denominator must have been 0


You can define your own structures and pass them between functions. The syntax for using structure members is similar to C. Structures can contain numbers, strings, arrays of characters and substructures. In addition, Igor has some pre-defined structures such as the WMButtonAction in this simple coding example which also demonstrates that Igor´s structures can be converted into and from strings:

// A window proc that creates a user-defined panel
// with two buttons named b0 and b1.
Window DemoStructuresPanel() : Panel
    PauseUpdate; Silent 1       // building window...
    NewPanel /W=(343,91,561,138)
    Button b0,pos={26,12},size={50,20},proc=ButtonProc,title="Click"
    Button b1,pos={130,12},size={50,20},proc=ButtonProc,title="Click"

// Defines a custom structure
Structure mystruct
    Int32 nclicks
    double lastTime

// The function which runs when Button b0 or b1 are clicked.
Function ButtonProc(bStruct) : ButtonControl
    STRUCT WMButtonAction &bStruct  // Igor-defined structure, passed by reference.
    if( bStruct.eventCode != 1 )
        return 0        // we only handle mouse down (code=1)

    STRUCT mystruct s1          // local user-defined structure
    if( strlen(bStruct.userdata) == 0 ) // button hasn't had userdata initialized
        print "first click on " + bStruct.ctrlName
        // button has a structure packed into its userdata.
        StructGet/S s1,bStruct.userdata // unpack structure from userdata string.
        Variable lastTime= s1.lastTime  // get a value from the structure.
        String ctime= Secs2Date(lastTime, 1 )+" "+Secs2Time(lastTime,1)
        printf "button %s clicked %d time(s), last click = %s\r",bStruct.ctrlName,s1.nclicks,ctime
    s1.nclicks += 1         // update the structure members
    s1.lastTime= datetime       // seconds since Jan 1, 1904.
    StructPut/S s1,bStruct.userdata // pack structure s1 into string inside struct bStruct.
    return 0

And this is the resulting user interface:

panel with two buttons labeled "Click" and the print output displayed when they are clicked

Vector and Array Arithmetic

Igor´s programming language allows you to write assignment statements that work on an entire data set or on a subset just like you would assign the value to a single variable in a standard programming language:

Make/O/N=1000 data  // a vector ("wave") to hold 1000 values.
data = sin(2*pi*p/1000) // assigns to each element of data. p iterates from 0 to 999.
Display data

graph showing one cycle of sine wave

Here's an example of changing only a portion of the array:

data[0,499] = data[p]*data[p]   // replace first 500 values with sqrt(value).

graph showing one cycle of sine wave

For more examples, see Data Math.


Igor encourages code reuse through its "include" mechanism, which is similar to C.

For example, by simply entering this statement in any procedure window:

#include  <Multipeak Fitting>

Igor adds the Multipeak Fitting package to your Igor experiment:

peak fitting interface created by the Multipeak Fitting PackageThe package is comprised of multiple pre-written procedure files stored in the WaveMetrics Procedures folder that ships with Igor. The Multipeak Fitting.ipf procedure file itself includes other procedure files that support its functionality:

procedure file containing commands to #include code from additional procedure files.

You can reuse your own procedures this way, though with a slightly different syntax:

#include "MyProcedureFile"

which loads the procedure file named "MyProcedureFile.ipf" from your "User Procedures" folder (which is located inside your Documents\WaveMetrics\Igor Pro User Files folder).


Have you ever looked at program code and wondered why some "magic number" was used?

Sleep/T 7200    // an unexplained "magic" number
Sleep/T 60*60*2 // perhaps a little clearer

You can write code that is easier to maintain by using well-named constants:

Constant kTicksPerSecond=60
Constant kSecondsPerMinute=60
Constant kMinutesToWait=2

Sleep/T kTicksPerSecond*kSecondsPerMinute*kMinutesToWait

(Another advantage of using constants is when an identical value must be used in multiple places in the code. If you use a constant name everywhere the value is needed and later need to change the value, you can simply change the definition of the constant to change the value wherever it is used. This is better than combing through the code trying to determine which instances of say, 1, need to change to 2.)

Igor also has string constants, and you can make constant definitions "static" which makes them private to the procedure file they´re defined in:

Static StrConstant ksPrefsFileName="MyPrefs.txt"

User-defined Menus

You can add to Igor´s menus by writing menu definitions in procedure windows. For an example, see the "Analysis" menu definition in the Multipeak Fitting.ipf file shown above.

You can also enable or disable Igor´s standard menus using the SetIgorMenuMode command, or show and hide built-in menus with ShowIgorMenus and HideIgorMenus.

You can also programmatically add contextual menus to graph, table, panel, and layout windows using the PopupContextualMenu operation or add menu items to many of Igor's built-in contextual menus.

These features allow you to customize Igor for your applications, and to disable Igor features that users of your customized application do not want to worry about.




Igor Pro 9

Learn More

Igor XOP Toolkit

Learn More

Igor NIDAQ Tools MX

Learn More