2.3.1.6 Functions

Functions are the core of almost every programming language; the following introduces function syntax and use in LabTalk.

Built-In Functions

LabTalk supports many operations through built-in functions, a listing and description of each can be found in Function Reference. Functions are called with the following syntax:

outputVariable = FunctionName(Arg1, Arg2, ..., Arg N);

Below are a few examples of built-in functions in use.

The Count (Function) returns an integer count of the number of elements in a vector.

// Return the number of elements in Column A of the active worksheet:
int cc = count(col(A));

The Ave (Function) performs a group average on a dataset, returning the result as a range variable.

range ra = [Book1]Sheet1!Col(A);
range rb = [Book1]Sheet1!Col(B);
// Return the group-averaged values:
rb = ave(ra, 5);    // 5 = group size

The Sin (Function) returns the sine of the input angle as type double (the units of the input angle are determined by the value of system.math.angularunits):

system.math.angularunits=1;  // 1 = input in degrees
double dd = sin(45);         // ANS: DD = 0.7071

For functions that return type is a dataset or stringarray, you can use [index] to get the corresponding data in the array and use it in expression.

The Unique (Function) returns a list of unique number or strings in specified dataset.

Col(B)=unique(col(A), 2); //get unique numbers in column A, descending, 2nd arguement means descending

//2nd argument skipped so output will be ascending
//[index] - 1st value in output which is the smallest value
Col(C)[1]=unique(col(A))[1]; //column C row 1 will be filled the smallest unique number found in A

//[0] is the last index so unique(Col(A))[0] will refer to biggest unique number found in A
Col(D)=Col(A)-unique(col(A))[0];

User-Defined Functions

Multi-argument user-defined functions has been supported in LabTalk since Origin 8.1. The syntax for user-defined functions is:

function dataType funcName(Arg1, Arg2, ..., ArgN) {script;}

Minimum Origin Version Required: 8.6 SR0

Note:

  1. The function name should be less than 42 characters.
  2. Both arguments and return values support string, double, int, dataset, and tree data types. The default argument type is double. The default return type is int.
  3. By default, arguments of user-defined functions are passed by value, meaning that argument values inside the function are NOT available outside of the function. However, passing arguments by reference, in which changes in argument values inside the function WILL be available outside of the function, is possible with the keyword REF.

Here are some simple cases of numeric functions:

// This function calculates the cube root of a number
function double dCubeRoot(double dVal)
{
    double xVal;
    if(dVal<0) xVal = -exp(ln(-dVal)/3);
    else xVal = exp(ln(dVal)/3);
    return xVal;
}
// As shown here
dcuberoot(-8)=;

The function below calculates the geometric mean of a dataset:

function double dGeoMean(dataset ds)
{
    double dG = ds[1]; 
    for(int ii = 2 ; ii <= ds.GetSize() ; ii++)
        dG *= ds[ii]; // All values in dataset multiplied together
    return exp(ln(dG)/ds.GetSize());
}
// Argument is anything returning a datset
dGeoMean(col("Raw Data"))=;

This example defines a function that accepts a range argument and returns the mean of the data in that range:

// Calculate the mean of a range
function double dsmean(range ra)
{
   stats ra;
   return stats.mean;
}
// Pass a range that specifies all columns ...
// in the first sheet of the active book:
range rAll = 1!(1:end);
dsMean(rAll)=;

This example defines a function that counts the occurrences of a particular weekday in a Date dataset:

function int iCountDays(dataset ds, int iDay)
{
    int iCount = 0;
    for(int ii = 1 ; ii <= ds.GetSize() ; ii++)
    {
        if(weekday(ds[ii], 1) == iDay) iCount++;
    }
    return iCount;
}
// Here we count Fridays
iVal = iCountDays(col(1),6); // 6 is Friday in weekday(data, 1) sense
iVal=;

Functions can also return datasets ..

// Get only negative values from a dataset
function dataset dsSub(dataset ds1)
{
    dataset ds2;
    int iRow = 1;
    for(int ii = 1 ; ii <= ds1.GetSize() ; ii++)
    {
        if(ds1[ii] < 0)
        {
            ds2[iRow] = ds1[ii];
            iRow++;
        }
    }
    return ds2;
}
// Assign all negative values in column 1 to column 2
col(2) = dsSub(col(1));

or strings ..

// Get all values in a dataset where a substring occurs
function string strFind(dataset ds, string strVal)
{
    string strTest, strResult;
    for( int ii = 1 ; ii <= ds.GetSize() ; ii++ )
    {
        strTest$ = ds[ii]$;
        if( strTest.Find(strVal$) > 0 )
        {
            strResult$ = %(strResult$)%(CRLF)%(strTest$);
        }
    }
    return strResult$;
}
// Gather all instances in column 3 where "hadron" occurs
string MyResults$ = strFind(col(3),"hadron")$; // Note ending '$'
MyResults$=;

Passing Arguments by Reference

This example demonstrates a function that returns a tree node value as an int (one element of a tree variable). In addition, passing by reference is illustrated using the REF keyword.

// Function definition:
Function int GetMinMax(range rr, ref double min, ref double max) {
  stats rr;
  //after running the stats XF, a LabTalk tree variable with the
  //same name is created/updated
  min = stats.min;
  max = stats.max;
  return stats.N;
}

// Call function GetMinMax to find min max for an entire worksheet:
double y1,y2;
int nn = getminmax(1:end,y1, y2);
type "Worksheet has $(nn) points, min=$(y1), max=$(y2)";

See this detailed example on using tree variables in LabTalk functions and passing variables by reference.

Another example of passing string argument by reference is given below that shows that the $ termination should not be used in the function call:

//return range string of the 1st sheet
//actual new book shortname will be returned by Name$
Function string GetNewBook(int nSheets, ref string Name$)
{
	newbook sheet:= nSheets result:=Name$;	
	string strRange$ = "[%(Name$)]1!";	
	return strRange$;
}

When calling the above function, it is very important that the Name$ argument should not have the $, as shown below:

string strName$;
string strR$ = GetNewBook(1, strName)$;
strName$=;
strR$=;

Dataset Functions

Origin also supports defining mathematical functions that accept arguments of type double and return type double. The general syntax for such functions is:

funcName(X) = expressionInvolvingX.

We call these dataset functions because when they are defined, a dataset by that name is created. This dataset, associated with the function, is then saved as part of the Origin project. Once defined, a dataset function can be referred to by name and used as you would a built-in LabTalk function.

For example, enter the following script in the Script window to define a function named Salary:

Salary(x) = 52 * x

Once defined, the function may be called anytime as in,

Salary(100)=

which yields the result Salary(100)=5200. In this case, the resulting dataset has only one element. But if a vector (or dataset) were passed as an input argument, the output would be a dataset containing the same number of elements as the input.

As with other datasets, user-defined dataset functions are listed in dialogs such as Plot Setup (and can be plotted like any other dataset), and in the Available Data list in dialogs such as Layer n.

If a 2D graph layer is the active layer when a function is defined, then a dataset of 100 points is created using the X axis scale as the X range and the function dataset is automatically added to the plot layer.

The Function Graph Template (FUNCTION.OTP, accessible from the Standard Toolbar or the File: New menu) also creates and plots dataset functions.

Origin's Function Plots feature allows new dataset functions to be easily created from any combination of built-in and user-defined functions. In addition, the newly created function is immediately plotted for your reference.

Access this feature in either of two ways:

  1. Click on the New Function button in the Standard toolbar, Button New Function.png
  2. From the Origin drop-down menus, select File: New and select Function from the list of choices, and click OK.

From there, in the Function tab of the Plot Details dialog that opens, enter the function definition, such as, F1(x) = 5*sin(x)+1 and press OK. The function will be plotted in the graph.

You may define another function by clicking on the New Function button in the graph and adding another function in Plot Details. Press OK, and the new function plot will be added to the graph. Repeat if more functions are desired.

Fitting Functions

In addition to supporting many common functions, Origin also allows you to create your own fitting functions to be used in non-linear curve fitting. User-defined fitting functions can also be used to generate new datasets, but calling them requires a special syntax:

nlf_FitFuncName(ds, p1, p2, ..., pn)

where the fitting function is named FitFuncName, ds is a dataset to be used as the independent variable, and p1--pn are the parameters of the fitting function.

As a simple example, if you defined a simple straight-line fitting function called MyLine that expected a y-intercept and slope as input parameters (in that order), and you wanted column C in the active worksheet to be the independent variable (X), and column D to be used for the function output, enter:

// Intercept = 0, Slope = 4
Col(D) = nlf_MyLine(Col(C), 0, 4)

Scope of Functions

As with user-defined variables, user-defined functions have a scope that can be controlled. User-defined functions can be accessed from anywhere in the Origin project where LabTalk script is supported, provided the scope of definition is applicable to such usage. Thus for example, a function defined with preceding assignment @glob=1 that returns type double or dataset, can be used in the Set Values dialog Column Formula panel. For more on scope, see Data Types and Variables.

  • You can associate functions with a project by defining them in the project's ProjectEvents.OGS file. Using @glob=1, your function becomes available any time the project is opened (see this example, below).
  • The scope of a function can be expanded for general use any time that Origin runs by defining the function using @glob=1, saving the function to an .ogs file in the User Files Folder (UFF), and calling the .ogs file from the [Startup] section of Origin.ini (also in the UFF), as discussed here.

Examples: Scope of Functions

Using @glob=1 to call the function anywhere.

[Main]
	@glob=1;  // promote the following function to session level
	function double dGeoMean(dataset ds)
	{
	    double dG = ds[1]; 
	    for(int ii = 2 ; ii <= ds.GetSize() ; ii++)
	        dG *= ds[ii]; // All values in dataset multiplied together
	    return exp(ln(dG)/ds.GetSize());
	}
	// can call the function in [main] section
	dGeoMean(col(1))=;
[section1]
	// the function can be called in this section too
	dGeoMean(col(1))=;

If the function is defined in a section of a *.ogs file without @glob=1, then it can only be called in its own section.

[Main]
	function double dGeoMean(dataset ds)
	{
	    double dG = ds[1]; 
	    for(int ii = 2 ; ii <= ds.GetSize() ; ii++)
	        dG *= ds[ii]; // All values in dataset multiplied together
	    return exp(ln(dG)/ds.GetSize());
	}
	// can call the function in [main] section
	dGeoMean(col(1))=;
[section1]
	// the function can NOT be called in this section
	dGeoMean(col(1))=;  // an error: Unknown function

If the function is defined in a block without @glob=1, it can not be called outside this block.

[Main]
{  // define the function between braces
	function double dGeoMean(dataset ds)
	{
	    double dG = ds[1]; 
	    for(int ii = 2 ; ii <= ds.GetSize() ; ii++)
	        dG *= ds[ii]; // All values in dataset multiplied together
	    return exp(ln(dG)/ds.GetSize());
	}
}
	// can Not call the function outside the braces
	dGeoMean(col(1))=;  // an error: Unknown function

Tutorial: Using Multiple Function Features

The following mini tutorial shows how to add a user-defined function at the Origin project level and then use that function to create function plots.

  1. Start a new Project and use View: Code Builder menu item to open Code Builder.
  2. Expand the Project branch on the left panel tree and double-click to open the ProjectEvents.OGS file. This file exists by default in any new Project.
  3. Under the [AfterOpenDoc] section, add the following lines of code:
    @glob=1;
    Function double myPeak(double x, double x0)
    {
    double y = 10*exp(-(x-x0)^2/4);
    return y;
    }
  4. Save the file and close Code Builder.
  5. In Origin, save the Project to a desired folder location. The OGS file is saved with the Project, so the user-defined function is available for use in the Project.
  6. Open the just saved project again. This will trigger the [AfterOpenDoc] section to be executed and thus our myPeak function to be defined.
  7. Click on the New 2D Plot toolbar button in the Standard toolbar or choose File: New: Function Plot: 2D Function Plot... menu.
  8. In the edit box after Y(x) =, enter myPeak(x, 3) and press Add. The function will be plotted in a graph.
  9. With the dialog still open, modify the function to be myPeak(x,4). Make sure the bottom dropdown list shows Add to Active Graph. Click Add button. The modified function plot is added to the graph.
  10. Save the project and share with others. Since the myPeak function is defined upon loading the project, it is always accessible in the project.