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