Tables

<< Click to Display Table of Contents >>

Navigation:  Details >

Tables

Previous pageReturn to chapter overviewNext page

Table construction in Gekko is mentioned briefly under Table.cs here.

Gekko has its own table syntax (.gtb file, xml-based) for tabelling timeseries, where table rows and columns can be defined. From a .gtb file, Gekko can output a table in either text or html format, and has its own "engine" to do so. It also has its own table syntax, to create tables cell by cell. The latter is normally not used by Gekko users. The Table.cs code is a bit complicated and quite lengthy. Gekko tables are mostly used to print timeseries in tables where the periods are in columns and the series are in rows.

Future modernization

 

If the table generator was made today, the approach would probably be different. An approach could be to convert the mathematical expressions like x/y into C# Func<> delegates, just like it is done regarding printing. Then, a normal Gekko list (IVariable) could be filled with the cells (in the form of a nested list or rows and columns), since Gekko lists accept cells with any variable type (so both value, date and string are supported). Formatting and other information could be stored in the list cells too. At the end, the nested list could be converted to either text (string) or html format. This would be flexible, and it would allow the user to design tables manually by just defining the nested Gekko list directly (and asking for it to be transformed into text or html). This would make the whole code a lot more simple and maintainable.

 

The table code is located in Table.cs and basically runs from TableStuff.XmlTable(). This method inputs the xml .gtb table definition file and produces a temporary tablecode.gcm file that contains Gekko code that is able to produce the table. This convoluted way of handling tables has to do with mathematical expressions: table code should be able to handle experssions like x/y etc., and when the table system was built, generating Gekko code seemed like the easiest way to do it. However, this makes the table generator very convoluted. First, it loops through a xml .gtb table file, then transforms til into Gekko code, and then transforms the Gekko code into C# code.

In the existing code, TableStuff.XmlTable() takes the xml file, converts it into a nested tree of XmlNodes (XmlNode is C#, from the System.Xml namespace). This tree is walked recursively, using TableStuff.VisitChildren(), where some info is gathered regarding the xml tree. But the real work is done in TableStuff.HandleXmlRow(), which goes through each line of the xml file. While doing this, it also keeps track of the attributes, because a given xml attribute can often be given on different xml levels: in <table> it applies to the whole table, in <col> it applies to the specific column, in <rowformat> it applies to all following rows, until next <rowformat> overrides it, in <row> it applies to the specific row, in the element itself (for instance in the <txt> or <var> tags). HandleXmlRow() outputs a Gekko command file like the following:

// ----------------------------------------------------------------------
// This file is auto-generated, made from a XML table file
// XML table filename: c:\Thomas\Desktop\gekko\testing\table.gtb
// ----------------------------------------------------------------------
//
DATE %__t1 = %__tabletimestart;
DATE %__t2 = %__tabletimeend;
TABLE tab = new Table();
VAL %__periods = %__t2 - %__t1 + 1 - filteredperiods(%__t1, %__t2);
VAL %__c1 = 1;
VAL %__c2 = %__c1 + 1;
VAL %__c3 = %__c2 + %__periods;
TABLE tab.CurRow.SetTopBorder(1, %__c3 - 1);
TABLE tab.CurRow.SetText(%__c1, 'Test table}');
TABLE tab.CurRow.MergeCols(%__c1, %__c3 - 1);
TABLE tab.CurRow.Next();
TABLE tab.CurRow.SetTopBorder(1, %__c3 - 1);
TABLE tab.CurRow.SetDates(%__c2, %__t1, %__t2);
TABLE tab.CurRow.Next();
TABLE tab.CurRow.SetTopBorder(1, %__c3 - 1);
TABLE tab.CurRow.SetText(%__c1, 'xx1');
TABLE tab.CurRow.MergeCols(%__c1, %__c2 - 1);
TABLE tab.CurRow.SetValues(%__c2, %__t1, %__t2, xx1, 'n', 1.0, 'f15.2');
TABLE tab.CurRow.Next();
TABLE tab.CurRow.SetText(%__c1, 'xx2');
TABLE tab.CurRow.MergeCols(%__c1, %__c2 - 1);
TABLE tab.CurRow.SetValues(%__c2, %__t1, %__t2, xx2, 'm', 1.0, 'f15.2');
TABLE tab.CurRow.SetBottomBorder(1, %__c3 - 1);
TABLE tab.CurRow.SetLeftBorder(%__c1);
TABLE tab.CurRow.SetLeftBorder(%__c2);
TABLE tab.CurRow.SetRightBorder(%__c3 - 1);
TABLE tab.Print('html');

 

The idea is basically that the table is produced line by line, where CurRow.Next() shifts to the next table row. Borders can be set with .SetTopBorder() and similar, and text, dates and values can be set with SetText(), SetDates(), and SetValues(). There is a special method, MergeCols(), which merges a number of columns in a given (current) row. This is like merging cells horizontally in a spreadsheet like for instance Excel.

The C# Table class has the method PrintText() for printing a text character table, whereas PrintHtml() prints it out in html format. Regarding PrintText(), it uses a special trick, namely cloning the Table object, and then afterwards (in the cloned table) multiplying all cell coordinates with two. So if there was a 3 x 3 table with the cells (1, 1), (1, 2), (1, 3), (2, 1), (2, 2), (2, 3), (3, 1), (3, 2), (3, 3), these cells are transformed into coordinates (2, 2), (2, 4), (2, 6), (4, 2), (4, 4), (4, 6), (6, 2), (6, 4), (6, 6). This way, there will be the empty rows 1, 3, 5, and empty columns 1, 3, 5. These can be filled with cells that represent possible borders. The neat thing about this is that if the original cell (1, 2) had a bottom border, and the cell (2, 2) had a top border, these two borders will both just activate a horizontal border "between" (1, 2) and (2, 2). So the cloned cells will be (2, 4) and (4, 4), and in that cloned table, the cell (3, 4) will contain the horizontal border that both cells activate. In a sense, the trick creates the necessary text space to handle the borders. But the trick also introduces some tedious bookkeeping.

Regarding PrintHtml(), this method works a bit differently, among other things because the handling of borders is much more simple to state in html. In html, a top border is simply set directly with a html tag, and the html browser engine handles how it is actually printed on the screen.