3.11.1 Accessing X-Function

Calling X-Function

When programming in an X-Function or in a normal Origin C function, you may need to call another X-Function which has accomplished the desired purpose.

To call an X-Function in Origin C, class XFBase is needed (add #include <XFbase.h> for the header file).

A typical simple process will include:

XFBase	xf(LPCSTR lpcszName = NULL); //Which can declare the class and load the X-Function.

//set value for a specific variable for X-Function by variable name or variable index. 
//var variable below can be other data type like matrix&, int&, string&, double&, DataRange& and so on.
xf.SetArg(LPCSTR lpcszName, vector& var); 
xf.SetArg(int nVarIndex, vector& var);

//sequentially set values for the variables for X-Function. 
//Both the order of the variable in the X-Function variables list and the name can be used.
xf.SetArgs(...);

//Execute the X-Function ''without'' executing event handling functions.
xf.Evaluate(...);

Examples

Example to Call integ1 X-Function

#include	<XFbase.h> // XFbase.h is included for accessing the class XFBase.

// The example shows how to call an X-Function and get the result via Origin C
// A typical process of using XFBase will be the following. 

void	Call_XF_from_OC_Ex1_integ1()
{
	//////// Prepare the input data and put into worksheet ////////
	vector vX;
	vector vY;

	vX.Data(0., 20.0, 0.05);
	vY.SetSize(vX.GetSize());
	double dA = 100.0;
	double dXc = 8.0;
	double dW = 2.0;
	vY = dA * exp(-0.5*(vX-dXc)*(vX-dXc)/dW/dW);
	
	Worksheet wks;
	wks.Create("origin");
	while(wks.Columns.Count()<6) wks.AddCol();
	wks.SetColDesignations("XY");
	wks.Columns(1).SetLongName("Raw");
	wks.Columns(3).SetLongName("Integration");
	wks.Columns(5).SetLongName("Normalized");
	
	DataRange drIn;
	drIn.Add(wks,0,"X");
	drIn.Add(wks,1,"Y");
	if(!drIn.SetData(&vY, &vX)) 
	{
		out_str("Failed to set the data!");	
		return;
	}
		
	//////// Call X-Function integ1 to do the integration and plotting.////////

	//// Load the X-Function
	string		strXFNameToCall = "integ1";
	XFBase		xf(strXFNameToCall);
	if( !xf.IsValid() )
	{
		out_str("Failed to load xfunction.");
		return;
	}

	//// Set the arguments for the X-Function
	// Prototype for X-Function integ1.
	// void integ1(const XYRange& iy, const int& baseline, const int& type, 
// XYRange& oy, const int& plot, double& x1, double& x2, int& i1, int& i2, 
// double& area, double& y0, double& x0, double& dx, TreeNode& tr, const int& rescale)
	DataRange drInteg;
	drInteg.Add(wks, 2, "X");
	drInteg.Add(wks, 3, "Y");
	double dArea; 
	// DataRange can be directly passed as the arguments though the prototype for the argument is XYRange because class XYRange is derived from class DataRange.
	// We need get the result of integrated area, so set the 9th argument (area) separately.
	if ( !xf.SetArgs(drIn, 0, 0, drInteg, 1) || !xf.SetArg(9, dArea) )  
	{
		out_str("Failed to set the arguments!");
		return;
	}

	//// Execute the X-Function
	if ( !xf.Evaluate())
	{
		out_str("Failed to execute the X-Function!");
		return;
	}
	
	//////// Use the result of integ1 to do some calculation. ////////
	vector vXInteg;
	vector vYInteg;
	vector vYNorm;
	DataRange drNorm;
	drNorm.Add(wks, 4, "X");
	drNorm.Add(wks, 5, "Y");
	drInteg.GetData(vXInteg, 0);
	drInteg.GetData(vYInteg, 1);
	vYNorm = vYInteg/dArea;
	if( !drNorm.SetData(&vYNorm, &vXInteg) )
	{
		out_str("Failed to set the normalized data!");
		return;
	}

}

Example to Call corrcoef X-Function

#include	<XFbase.h>
#include 	<ReportTree.h>
void Call_XF_from_OC_Ex2_corrcoef()
{
	//Prepare data
	ASCIMP    ascimp;
	Worksheet wks;
	string strFile = GetAppPath(1) + "Samples\\Statistics\\automobile.dat";
	wks.Create();
	if(AscImpReadFileStruct(strFile,&ascimp)==0)
	{
		wks.ImportASCII(strFile, ascimp);
	}
	
	DataRange drIn;		
	for (int i = 2; i < 7; i++)
	{
	   drIn.Add(wks, i, "X");
	}
		
	string		strXFNameInner = "corrcoef";
	
	XFBase		xf(strXFNameInner);
	if ( !xf )
		XF_THROW(XFERR_FAIL_LOAD_XF);

	Tree trDummy1, trDummy2, trDummy3;
	ReportData rd(trDummy1);
	ReportTree rt(trDummy2);
	ReportTree rtPlot(trDummy3);
				
	if ( !xf.SetArgs(drIn, 1, 1, 1, 1, 1, 95, 0, rd, rtPlot, rt) )
		XF_THROW(XFERR_FAIL_SET_ARG);

 	//set plot data to destination worksheet for graph in report tree.
	WorksheetPage	wksPage = wks.GetPage();
	int nLayer = wksPage.AddLayer();
	Worksheet 	wksReportData = wksPage.Layers(nLayer);
	rd.SetWorksheet(wksReportData);

	if ( !xf.Evaluate() )
		XF_THROW(XFERR_FAIL_EVAL);
	
	// prepare worksheet for hierarchical report tree
	DWORD dwNewLayerBits = WP_SHEET_HIERARCHY | CREATE_NO_DEFAULT_TEMPLATE | WP_SHEET_THIN_COL_HEADERS | WP_SHEET_MAIN_NAN_AS_BLANK;	
	nLayer = wksPage.AddLayer((LPCSTR)NULL, dwNewLayerBits);
	Worksheet 	wksReportTree = wksPage.Layers(nLayer);
	rt.GenerateReport(wksReportTree, false, false);
	wksReportTree.AutoSize();	
	
	DWORD dwOptions = GETNBRANCH_HIDE_COL_LABELS | GETNBRANCH_FIT_COL_WIDTH | GETNBRANCH_FIT_ROW_HEIGHT;
	nLayer = wksPage.AddLayer((LPCSTR)NULL, dwNewLayerBits, NULL, dwOptions);
	Worksheet 	wksRTPlot = wksPage.Layers(nLayer);
	rtPlot.GenerateReport(wksRTPlot, false, false);
	wksReportTree.AutoSize();	

}

Example with Controlling X-Function Settings Tree

#include <XFbase.h>
void    Call_XF_from_OC_Ex3_expGraph()
{
    // Load the X-Function
    string      strXFNameToCall = "expGraph";
    XFBase      xf(strXFNameToCall);
    if( !xf.IsValid() )
    {
        out_str("Failed to load xfunction.");
        return;
    }    
    
    // Set the arguments for the X-Function
    int nType = 7;
    if( !xf.SetArg("type", nType) )         //7:jpg
        out_str("Failed to set argument image type");
 
    string strFilename = "abc";
    if( !xf.SetArg("filename", strFilename) )
    	out_str("Failed to set argument filename");
    
    string strPath = "d:\\";                    // the page export to
    if( !xf.SetArg("path", strPath) )
        out_str("Failed to set argument path");
    
    string strPages = "Graph1";         //assuming Graph1 is exist
    if( !xf.SetArg("pages", strPages) )
        out_str("Failed to set argument pages");
 
    // Set tree argument for the X-Function 
    Tree tr1;
    xf.GetXFCreatedTree("tr1", tr1);                    //get the tree
    tr1.Width.nVal = 5;                 //set tree value
    tr1.Height.nVal = 4;
    tr1.Unit.nVal = 0;
    if( !xf.SetArg("tr1", tr1))
        out_str("Failed to set argument tr");
    
    // Execute the X-Function, and before_execute is called without dialog.
    TreeNode trGetN; 
    if( !xf.Run(0, trGetN) )
    {
        out_str("Failed to execute the X-Function!");
        return;
    }
}

Example calling getnlr X-Function

#include <XFbase.h>
void call_XF_getnlr()
{
	// Load the getnlr X-Function
	XFBase xfGetNLR("getnlr");
	if( !xfGetNLR.IsValid() )
	{
		out_str("Failed to load getnlr X-Function.");
		return;
	}

	// Set the output tree argument
	Tree tnMyFit;
	if( !xfGetNLR.SetArg("tr", tnMyFit) )
	{
		out_str("Failed to set argument:  tr");
		return;
	}

	// Set the source worksheet argument
	Worksheet wks;
	char szWks[MAX_PATH];
	if( LT_get_str("__REPORT$", szWks, MAX_PATH) && lstrlen(szWks) )
	{
		wks.Attach(szWks);
		if( !xfGetNLR.SetArg("iw", wks) )
		{
			out_str("Failed to set argument:  iw");
			return;
		}
	}

	// Set the notation argument
	// Allowed values:
	// 0 = Parameter names
	// 1 = Abbreviations
	// 2 = Both
	int nPNotation = 2; // Parameter names and abbreviations
	if( !xfGetNLR.SetArg("pnotation", nPNotation) )
	{
		out_str("Failed to set argument:  pnotation");
		return;
	}

	// With arguments set we can now execute the X-Function
	if( !xfGetNLR.Evaluate() )
	{
		out_str("Failed to evaluate the getnlr X-Function.");
		return;
	}
	
	// Output the whole tree to the script window
	out_tree(tnMyFit);

	// Put the p1 value into a new workbook
	double p1;
	if( tnMyFit.p1.GetValue(p1) )
	{
		// Create a new workbook using the default Origin template
		WorksheetPage wksPgNew;
		wksPgNew.Create("origin.otw");

		// Get the active worksheet
		Worksheet wksNew = wksPgNew.Layers(-1);

		// Get the worksheet's first column
		Column col = wksNew.Columns(0);

		// Get the column's data values
		vector &colVals = col.GetDataObject();

		// Put the p1 value into the column's data
		if( colVals.GetSize() < 1 )
			colVals.Add(p1); // Add a new row with the p1 value
		else
			colVals[0] = p1; // Set first row to the p1 value
	}
	
}

Calling the stats X-Function

The following function can be called from Origin C to execute the stats X-Function.

In this example the stats X-Function is called to operate on one column of the specified worksheet, shows how to set vector data type input argument, and how to get double type result after X-Function execute.

#include <XFbase.h>
 
bool callStatsXF(Worksheet& wks, int nCol, 
    double& dMean, double& dSD, int& n,
    double& dMin, double& dMax,
    double& dSum, int& nMissing)
{
    //========== Load the stats X-Function
 
    XFBase xfStats("stats");
    if( !xfStats.IsValid() )
    {
        out_str("Failed to load stats X-Function.");
        return false;
    }
 
    //========== Set the ix argument
 
    // Get stats on the specified column     
    // Create a data range 
    DataRange dr;
    dr.Add(wks, nCol, "Range1");
 
    // Get the data represented by the data range into a local vector.
    vector<double> vData;    
    if( !dr.GetData(&vData, 0) )
    {
        out_str("Failed to get data.");
        return false;
    }
    if( 0 == vData.GetSize() )
    {
    	out_str("Dataset is empty.");
    	return false;
    }
 
    // Now with the local vector we can set the ix argument.
    if( !xfStats.SetArg("ix", vData) )
    {
        out_str("Failed to set argument:  ix");
        return false;
    }
 
    //========== Set the output arguments
 
    if( !xfStats.SetArg("mean", dMean) )
    {
        out_str("Failed to set argument:  mean");
        return false;
    }
 
    if( !xfStats.SetArg("sd", dSD) )
    {
        out_str("Failed to set argument:  sd");
        return false;
    }
 
    if( !xfStats.SetArg("n", n) )
    {
        out_str("Failed to set argument:  n");
        return false;
    }
 
    if( !xfStats.SetArg("min", dMin) )
    {
        out_str("Failed to set argument:  min");
        return false;
    }
 
    if( !xfStats.SetArg("max", dMax) )
    {
        out_str("Failed to set argument:  max");
        return false;
    }
 
    if( !xfStats.SetArg("sum", dSum) )
    {
        out_str("Failed to set argument:  sum");
        return false;
    }
 
    if( !xfStats.SetArg("missing", nMissing) )
    {
        out_str("Failed to set argument:  missing");
        return false;
    }
 
    //========== Execute the X-Function
 
    if( !xfStats.Evaluate() )
    {
        out_str("Failed to evaluate the stats X-Function.");
        return false;
    }
    return true;
}
 
// Test function for calling the above function.
void testCallStatsXF(int nCol = 0)
{
    Worksheet wks = Project.ActiveLayer();
    if( !wks )
    {
        out_str("Activate a worksheet and try again.");
        return;
    }
 
    double dMean, dSD, dMin, dMax, dSum;
    int n, nMissing; 
    
    if( callStatsXF(wks, nCol, dMean, dSD, n, dMin, dMax, dSum, nMissing) )
    {		
		printf("For Column %d:\
		\ndMean = %f\
		\ndSD = %f\
		\ndMin = %f\
		\ndMax = %f\
		\ndSum = %f\
		\nDataPoints = %d\
		\nnMissing = %d\n", nCol + 1, dMean, dSD, dMin, dMax, dSum, n, nMissing);
    }
}

Calling X-Function with XYRange arguments

This example shows how to construct XYRange variables and use them as X-Function arguments in Origin C.

To run the following function, a workhseet with 5 columns should be active. Fill the first two columns with XY data, the next two with XY data where the number of point is different but the range of X is similar to the first, and one empty column. The example illustrates the subtract_ref functions ability to interpolate. Note the comments for alternately using Y input as output.

#include <XFbase.h>

void run_subtract_ref()
{
    Worksheet wks = Project.ActiveLayer(); 
    if( 5 != wks.GetNumCols() )
    {
        out_str("Please make sure there are 5 columns in worksheet");
        return;
    }
    
    XYRange in;
    in.Add(wks, 0, "X"); // 1st column as X
    in.Add(wks, 1, "Y"); // 2nd column as Y
    
    XYRange ref;
    ref.Add(wks, 2, "X"); // 3rd column as X
    ref.Add(wks, 3, "Y"); // 4th column as Y
    
    XYRange out;
    out.Add(wks, 0, "X"); // Use the same X as Input and Output
    out.Add(wks, 4, "Y"); // Use the empty Y as Output
    // Comment line above and uncomment line below to overwrite Y data
    // out.Add(wks, 1, "Y"); // Use the input Y as output
    
    XFBase xf("subtract_ref"); // construct X-Function object with X-Function name  
    if( !xf.SetArg("iy1", in) )
    {
        out_str("Failed to set argument:  iy1");
        return;
    }
    
    if( !xf.SetArg("iy2", ref) )
    {
        out_str("Failed to set argument:  iy2");
        return;
    }   
 
    if( !xf.SetArg("oy", out) )
    {
        out_str("Failed to set argument:  oy");
        return;
    }   
 
    double xmean, ymean;
    if( !xf.SetArg("xmean", xmean) || !xf.SetArg("ymean", ymean) )
    {
        out_str("Failed to set argument:  xmean or ymean");
        return;
    } 
 
    if( !xf.Evaluate() )
    {
        out_str("Failed to evaluate the subtract_ref X-Function.");
        return;
    }  
    printf("xmean = %f, ymean = %f\n", xmean, ymean);
}

To check the argument data types of a function, open the X-Function Builder (F10), or type "xfname -h" or "help xfname" in the Command or Script Window.

Calling X-Function with theme

#include <XFBase.h>
bool test_xf_with_theme()
{
	Worksheet wks = Project.ActiveLayer();	
	if( !wks )
		return false;
	
	XFBase xf("averagexy");	
	
	// use theme name as input, can use STR_LAST_USED to apply last used settings to replace "abc" here.
	xf.ApplyTheme("abc");
	
	// set XFunctioin input varaible
	XYRange ry;
	ry.Add(wks, 0, "X");
	ry.Add(wks, 1, "Y");
	ry.Add("S", NULL);
	
	if (!xf.SetArg("iy", ry))
        return false;
	
	//// set XFunction output variables
	int iColx = wks.AddCol();
    wks.Columns(iColx).SetType(OKDATAOBJ_DESIGNATION_X);
    
	int iColy = wks.AddCol();	
	Dataset dsOutX(wks, iColx), dsOutY(wks, iColy);
	
	if (!xf.SetArg("x", dsOutX))
        return false;	
	if (!xf.SetArg("y", dsOutY))
        return false;
	
	return xf.Evaluate();	
}

Running X-Function with Auto Update

#include <../Originlab/xfunctionex.h>

bool running_xf_with_autoupdate()
{
	Worksheet wks = Project.ActiveLayer();	
	if( !wks )
		return false;
	
	// prepare input XY Range
	XYRange ry;
	ry.Add(wks, 0, "X");
	ry.Add(wks, 1, "Y");
	ry.Add("S", NULL);

	ry.Add(wks, 0, "X");
	ry.Add(wks, 2, "Y");
	ry.Add("S", NULL);

	ry.Add(wks, 0, "X");
	ry.Add(wks, 3, "Y");

    // prepre output X&Y columns
    int iColx = wks.AddCol();
    wks.Columns(iColx).SetType(OKDATAOBJ_DESIGNATION_X);
    
	int iColy = wks.AddCol();	
	Dataset dsOutX(wks, iColx), dsOutY(wks, iColy);
	
	// running XFunction "averagexy" with XFunction class
	XFunction xf;
	Tree trXF;
	if ( !xf.Load(&trXF, "averagexy", 0, true, false, true) ) // load a xfunction by name
        return false;
	
	// set XFunctioin input varaible
	if (!xf.SetArg("iy", ry))
        return false;
	
	// set XFunction output variables
	if (!xf.SetArg("x", dsOutX))
        return false;	
	if (!xf.SetArg("y", dsOutY))
        return false;
  	
	Tree tr;
	TreeNode trGetN;
	xf.GetGUI(tr, trGetN);
	
	// AU_AUTO means Auto Update is on.
    xf.Run(AU_AUTO, trGetN);
	return true;	
}