2.12.3 Looping Over Objects

There may be instances where it is desirable to perform a certain task or set of tasks on every object of a particular type that exists in the Origin project. For example, you might want to rescale all of your project graph layers or add a new column to every worksheet in the project. The LabTalk document command (or doc) facilitates this type of operation. Several examples are shown here to illustrate the doc command.

Looping over Objects in a Project

The document command with the -e or -ef switch (or doc -e command), is the primary means for looping over various collections of objects in an Origin Project. This command allows user to execute multiple lines of LabTalk script on each instance of the Origin Object found in the collection.

Looping over Workbooks and Worksheets

You can loop through all worksheets in a project with the doc -e LB command. The script below loops through all worksheets, skipping the matrix layers:

//loop over all worksheets in project to print their names
//and the number of columns on each sheet
doc -e LB {
	if(exist(%H,2)==0) //not a workbook, must be a matrix
		continue;
	int nn = wks.nCols;
	string str=wks.Name$;
	type "[%H]%(str$) has $(nn) columns";
}

The following example shows how to loop and operate on data columns that reside in different workbooks of a project.

Open the sample project file available since Origin 8.1 SR2:
\\Samples\LabTalk Script Examples\Loop_wks.opj

In the project there are two folders for two different samples and a folder named Bgsignal for the background signals alone. Each sample folder contains two folders named Freq1 and Freq2, which correspond to data at a set frequency for the specific sample.

The workbook in each Freq folder contains three columns including DataX, DataY and the frequency, which is a constant. The workbook's name in the Bgsignal folder is Bgsig. In the Bgsig workbook, there are three columns including DataX and two Y columns whose long names correspond to set frequencies in the workbook in each Freq folder.

The aim is to add a column in each workbook and subtract the background signal for a particular frequency from the sample data for the same frequency. The following Labtalk script performs this operation.

doc -e LB
{ //Loop over each worksheet.
   if(%H != "Bgsig") //Skip the background signal workbook. 
   {
      Freq=col(3)[1]; //Get the frequency.
      wks.ncols=wks.ncols+1; //Add a column in the sample sheet.
      //bg signal column for Freq using long name.
      range aa=[Bgsig]1!col("$(Freq)");
      wcol(wks.ncols)=col(2)-aa; //Subtract the bg signal.
      wcol(wks.ncols)[L]$="Remove bg signal"; //Set the long name.
   }
}

For increased control, you may also loop through the books and then loop through the sheets in your code, albeit a bit more slowly than the code above.

The following example shows how to loop over all workbooks in the current/active Project Explorer Folder, and then loop over each sheet inside each book that is found:

int nbooks = 0;
// Get the name of this folder
string strPath;
pe_path path:=strPath;
// Loop over all Workbooks ...
// Restricted to the current Project Explorer Folder View
doc -ef W {
   int nsheets = 0;
   // Loop over all worksheets in each workbook
   doc -e LW {
      type Sheet name: %(layer.name$);
      nsheets++;
   }
   type Found $(nsheets) sheet(s) in %H;
   type %(CRLF);
   nbooks++;   
}
type Found $(nbooks) book(s) in folder %(strPath$) of project %G;

Additionally, we can replace the internal loop using Workbook properties:

int nbooks = 0;
// Get the name of this folder
string strPath;
pe_path path:=strPath;
// Loop over all Workbooks ...
// Restricted to the current Project Explorer Folder View
doc -ef W {
   // Loop over all worksheets in each workbook
   loop(ii,1,page.nlayers) {
      range rW = [Book1]$(ii)!;
      type Sheet name: %(rw.name$);
   }
   type Found $(page.nlayers) sheet(s) in %H;
   type %(CRLF);
   nbooks++;   
}
// Final report - %G contains the project name
type Found $(nbooks) book(s) in folder %(strPath$) of project %G;

Looping Over Graph Windows

Here we loop over all plot windows (which include all Graph, Function Plots, Layout pages and embedded Graphs).

doc -e LP
{
    // Skip over any embedded graphs or Layout windows
    if(page.IsEmbedded==0&&exist(%H)!=11)
    {
        string name$ = %(page.label$);
        if(name.Getlength()==0 ) name$ = %H;
        type [%(name$)]%(layer.name$);
    }
}

The following script prints the contents of all graph windows in the project to the default printer driver.

doc -e P print; // Abbreviation of ''document -each Plot Print''

Looping Over Workbook Windows

The document -e command can be nested as in this example that loops over all Y datasets within all Worksheets:

doc -e W
{
    int iCount = 0;
    doc -e DY
    {
        iCount++;
    }
    if( iCount < 2 )
      { type Worksheet %H has $(wks.ncols) columns,; 
        type $(iCount) of which are Y columns; }
    else
      { type Worksheet %H has $(wks.ncols) columns,; 
        type $(iCount) of which are Y columns; }
}

Looping over Columns and Rows

This example shows how to loop over all columns and delete every nth column

int ndel = 3; // change this number as needed;
int ncols = wks.ncols;
int nlast = ncols - mod(ncols, ndel);
// Need to delete from the right to the left
for(int ii = nlast; ii > 0; ii -= ndel)
{
   delete wcol($(ii));
}

This example shows how to delete every nth rows in a worksheet.

int ndel = 3;           // change this number as needed
range rr = col(1);      // Get a range for column 1
nrows = rr.GetSize();   // Get the number of rows
int nlast = nrows - mod(nrows, ndel);
// Need to delete from the bottom to the top
for(int ii = nlast; ii > 0; ii -= ndel)
{
   range rr = wcol(1)[$(ii):$(ii)];
   mark -d rr;
}

This script calculates the logarithm of four columns on Sheet1, placing the result in the corresponding column of Sheet2:

for(ii=1; ii<=4; ii++)
{
	range ss = [book1]sheet1!col($(ii));
	range dd = [book1]sheet2!col($(ii));
	dd = log(ss);
}

Looping Over Graphic Objects

You can loop over all Graphic Objects in the active layer. By wrapping this with two other options we can cover an entire project.

// For each Plot
doc -e P
{
    // For each Layer in each Plot
    doc -e LW
    {
        // For each Graphic Object in each Layer in each Plot
        doc -e G
        {   // Set Legend background to Shadow
            if("%B"=="Legend") %B.background = 2;
            // Set timestamp color to Blue
            if("%B"=="timestamp") %B.color = color(blue);
            // Delete all rectangle objects 
            if("%B"=="rect*") label -r %B; 
        }
    }
}

Perform Peak Analysis on All Layers in Graph

This example shows how to loop over all layers in a graph and perform peak analysis on datasets in each layer using a pre-saved Peak Analyzer theme file. It assumes the active window is a multi-layer graph, and each layer has one data curve. It further assumes a pre-saved Peak Analyzer theme exists.

// Block reminder messages before entering loop.
// This is to avoid either reminder message from popping up
// about Origin switching to the report sheet
type -mb 0;
// Loop over all layers in graph window
doc -e LW
{
   // Perform peak analysis with preset theme
   sec; 
   pa theme:="My Peak Fit"; 
   watch;
   /* sec and watch are optional, 
      they print out time taken for fitting data in each layer */
}
// Un-block reminder message
type -me;