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;
}
|