TABLE

From Wiki
Revision as of 13:23, 13 February 2006 by Duncan (talk | contribs) (Added section on character alignment, explaining mode=2)
Jump to navigation Jump to search

< Tables Overview | XML >

This mighty table mode is called “natural tables” or “automatic tables.” I'd call it “HTML tables,” because it's very similar to them. They're especially suited for XML conversions.

Beware: every element must use \b ... \e!

You find a lot of samples in enattab.pdf

Willi Egger wrote a My Way how he set a typesetter's lead type case: Use of natural tables

\setupTABLE[row][odd][background=color,backgroundcolor=red, width=.2\textwidth]
\bTABLE[split=yes]
\bTR \bTD[nr=3] 1 \eTD \bTD[nc=2] 2/3 \eTD \bTD[nr=3] 4 \eTD \eTR
\bTR \bTD 2 \eTD \bTD 3 \eTD \eTR
\bTR \bTD 2 \eTD \bTD 3 \eTD \eTR
\bTR \bTD[nc=3] 1/2/3 \eTD \bTD 4 \eTD \eTR
\bTR \bTD 1 \eTD \bTD 2 \eTD \bTD 3 \eTD \bTD 4 \eTD \eTR
\eTABLE

You get automatic page breaking with the option [split=yes].

The sample looks like this:

Multipage TABLEs

Try to divide your table into...

and \setupTABLE[split=yes] or [split=repeat]

see also core-ntb.tex

Creating tables from CSV data (Comma Separated Values)

An interesting example of creating a table using comma separated values was posted to the mailing list by Christopher Creutzig

The following macros take care of processing CSV data:

% Iterate over all the lines of text captured with \obeylines active
% command to call is first argument, is not called for empty lines
\bgroup
\obeylines
\gdef\ProcessLines#1#2{\doProcessLines{#1}#2^^M\doProcessLines}%
\gdef\doProcessLines#1#2^^M#3\doProcessLines{%
 \doifnotempty{#2}{#1{#2}}%
 \doifnotempty{#3}{\doProcessLines{#1}#3\doProcessLines}%
}%
\egroup

\def\startCSV{\bgroup\obeylines\dostartCSV}

The next lines are an example of transforming the data into a natural table, but can be easily adapted to any type of the table or perhaps (mis)used in even more strange ways:

\def\TBLentry#1{\bTD#1\eTD}
\def\TBLline#1{\bTR\processcommalist[#1]\TBLentry}

\def\dostartCSV#1\stopCSV{%
  \bTABLE
  \ProcessLines\TBLline{#1}%
  \eTABLE
  \egroup
}

The following lines will then finally result in a desired table:

% some additional settings for the table may be made as well
\setupTABLE[c][2][style=\tt]
\setupTABLE[c][3][align=middle]
\setupTABLE[r][1][style=bold] % how to override the \tt in the second column?

\startCSV
Name,Email,Accepted
\CONTEXT,worth@trying.to,Yes
Hans,main@developer.of,Yes
Bug,get@rid.of,No
\stopCSV

Some remarks: the (tentative) code ignores the fact that

  • csv data may optionally be enclosed in "" quotes that have to be removed (to be done in \TBLentry)
  • quoted strings may contain commas themselves (which means writing a custom version of \processcommalist instead).

The author of this entry is looking for a solution for the described problem. (See: How to?)

What about separating the values using tabs?


Designing complex TABLEs

Everything is easy when a simple grid is enough. Unfortunately, this is not the case most of the time, tables tend to have information which should flow accross cell boundaries either vertically or horizontally. One of the reasons to use TABLE instead of the table environment is that TABLE provides an easy (relatively speaking, at least) way to make merged cells to both directions.

There are probably as many ways to design TABLEs as there are users, but a simple one to begin with is to start with a grid:

The desired table layout is then drawn onto this grid, and the top left corner cell of each cell in the final layout identified:

The cells are listed from left to right and up to down. Each larger cell is then given it size by using nc=... and nr=... parameters with \bTD. The code producing the table above is:

\setupTABLE[r][each][height=1cm]
\setupTABLE[c][each][width=1cm]
\setupTABLE[r][1][height=0cm,frame=off]
\bTABLE
\bTR \bTD \eTD \bTD \eTD \bTD \eTD \bTD \eTD \bTD \eTD \bTD \eTD \eTR
\bTR \bTD[nc=2,nr=2] r1c1 \eTD \bTD r1c3 \eTD \bTD[nr=2] r1c4 \eTD \bTD[nr=2,nc=2] r1c5 \eTD \eTR
\bTR \bTD[nr=2] r2c3 \eTD \eTR
\bTR \bTD[nc=2] r3c1 \eTD \bTD[nc=2] r3c4 \eTD \bTD r3c6 \eTD \eTR
\bTR \bTD r4c1 \eTD \bTD[nc=2] r4c2 \eTD \bTD[nr=2] r4c4 \eTD \bTD[nc=2] r4c5 \eTD \eTR
\bTR \bTD[nr=2,nc=2] r5c1 \eTD \bTD[nr=2] r5c3 \eTD \bTD[nr=2,nc=2] r5c5 \eTD \eTR
\bTR \bTD r6c4 \eTD \eTR
\eTABLE

N.B. There is an ugly hack in the code. An empty first row with zero height and no borders is added. If the row is omitted, then something odd happens to the number of columns. The table should have all cells, so this may be a bug. (Or then I have blundered something with this example, possibly.)

Everything rectangular can be done with TABLE, as long as it can be fit in the grid. The grid does not have to be equidistant, and if its dimensions are omitted, the program will fit the data in. L-shaped or other complex cell shapes are not possible. Using them would be a bit odd, in any case, as alignment and text flow problems would be quite interesting.


Cell Addressing and Frames

The setup commands for TABLE do not seem to be very verbosedly commented. There are, however, a few shorthands, which are useful to understand. First of all, there are several ways to address cells. This is a brief summary of some of them:

\setupTABLE[r][(list of rows)][...]
\setupTABLE[c][(list of columns)][...]
\setupTABLE[(list of columns)][(list of rows)][...]

A list contains one or more numbers separated by commas. Word "last" is equivalent to the number of the last row or column. The complete list can be replaced by the word "each" to address all cells on the row/column.

Let us consider the following table:

\setupTABLE[c][each][align={middle,lohi},frame=off]
\setupTABLE[r][2,3,4,5,6][height=1.0cm]
\setupTABLE[r][2,4][topframe=on]
\setupTABLE[c][1,2,3][rightframe=on]
...

In plain language the rows are interpreted as follows:

  • Align each cell in each column (i.e. all cells) horizontally in the middle

and vertically in the middle (lohi), and remove all frames (borders)

  • The height of rows 2 -- 6 is 1.0 cm
  • Draw a line on top of rows 2 and 4
  • Draw a line to the right side of columns 1 -- 3

In this case the table is slightly complicated, there are some split cells, as shown below:

\bTABLE
\bTR
  \bTD \bf r1c1 \eTD
  \bTD \bf r1c2 \eTD
  \bTD \bf r1c3 \eTD
  \bTD \bf r1c4 \eTD
\eTR
\bTR
  \bTD r2c1 \eTD
  \bTD r2c2 \eTD
  \bTD[nr=2] r2c3 \eTD
  \bTD r2c4 \eTD
\eTR
\bTR
  \bTD r3c1 \eTD
  \bTD r3c2 \eTD
  \bTD r3c4 \eTD
\eTR
\bTR
  \bTD r4c1 \eTD
  \bTD r4c2 \eTD
  \bTD[nr=3] r4c3 \eTD
  \bTD[nr=3] r4c4 \eTD
\eTR
\bTR
  \bTD r5c1 \eTD
  \bTD r5c2 \eTD
\eTR
\bTR
  \bTD r6c1 \eTD
  \bTD r6c2 \eTD
\eTR
\eTABLE

The cell numbering is well worth noting. It is very logical (upper leftmost part of a combined cell), but sometimes the results are surprising in the beginning.

The important point about cell numbering is that there is really a difference between "bottom border of row 3" and "top border of row 4". To illustrate this, let us change the frame setups:

\setupTABLE[r][2,4][topframe=on]

is changed to

\setupTABLE[r][1,3][bottomframe=on]

At first sight this is exactly the same thing. But...

Where did the horizontal line in column 3 disappear? Nowhere. There is no row 3 in column 3, so there cannot be a frame under it. This problem can be overcome by using topframe and leftframe instead of bottom and right, as the cells below and to the right of a border have to exist.

However, this solution leaves the problem of bottom and rightmost borders. How to draw a line in the bottom of the table? Using \setupTABLE[r][6][bottomframe=on] will leave the gap in columns 3 and 4, and \setupTABLE[r][7][topframe=on] is not possible, as there is no row 7. The clever idea of using "last" instead of the row number (6) will fail, as "last" seems to behave exactly the same way as number 6.

One useful method is to switch on the borders cell by cell by adding \setupTABLE[3,4][4][bottomframe=on], i.e. draw a border under cells r4c3 and r4c4.

Column Offset/Gap

From the mailing list at 2005-11-09 by Vit Zyka, modified by Hans Hagen:

\starttext

% distance mechanism, per column (H)

\start
   \setupTABLE[c][1][distance=2em]
   \setupTABLE[c][2][distance=3em]

   \bTABLE
   \bTR \bTD test \eTD  \bTD test \eTD  \bTD test \eTD \eTR
   \bTR \bTD[nx=2] test \eTD  \bTD test \eTD \eTR
   \bTR \bTD test \eTD  \bTD[nx=2] test \eTD \eTR
   \eTABLE

   \bTABLE[option=stretch]
   \bTR \bTD test \eTD  \bTD test \eTD  \bTD test \eTD \eTR
   \bTR \bTD[nx=2] test \eTD  \bTD test \eTD \eTR
   \bTR \bTD test \eTD  \bTD[nx=2] test \eTD \eTR
   \eTABLE
\stop

% distance mechanism, per table (V)

\framed[offset=none]{%
\setupTABLE[column][2][align=left]
\setupTABLE[column][3][align=right]
\bTABLE[columndistance=2cm,leftmargindistance=.3cm,rightmargindistance=.5cm]
 \bTR
   \bTH[nc=3] Table head\eTH
 \eTR
 \bTR\bTD[nc=2] AB\eTD\bTD C\eTD\eTR
 \bTR\bTD[nc=2,align=left] AB\eTD\bTD C\eTD\eTR
 \bTR\bTD[nc=2,align=middle] AB\eTD\bTD C\eTD\eTR
 \bTR\bTD A\eTD\bTD B\eTD\bTD C\eTD\eTR
 \bTR\bTD Aa\eTD\bTD Bb\eTD\bTD Cccc\eTD\eTR
 \bTR\bTD[nc=3,align=middle] ABC\eTD\eTR
\eTABLE
}

\stoptext

Beware, this distance parameter is only available from the next release on (in core-ntb-new.tex).

Make a cell bold

\bTABLE
\bTR \bTD 1 \eTD \bTD 1 \eTD \bTD 2/3 \eTD \eTR
\bTR \bTD 2 \eTD \bTD 2 \eTD \bTD 3 \eTD \eTR
\bTR \bTD 2 \eTD \bTD[rulethickness=2pt] 2 \eTD \bTD 3 \eTD \eTR
\bTR \bTD 1 \eTD \bTD 1 \eTD \bTD 4 \eTD \eTR
\bTR \bTD 1 \eTD \bTD 1 \eTD \bTD 2 \eTD \eTR
\eTABLE

Using character alignment

ConTeXt can align columns of numbers on a character (often a decimal point to align accounting data) automatically, removing the need to add fixed spaces into your document. For any such column you need to specify the character on which to align. You use the aligncharacter=yes parameter to set up character alignment, alignmentcharacter={.} to say what the character should be (in this case a full stop) and align=middle to set the overall alignment of the column.

\bTABLE
\setupTABLE[column][1][align=right]
\setupTABLE[column][2][alignmentcharacter={.},
aligncharacter=yes,align=middle]
\bTR \bTH Category \eTH \bTH Data entry \eTH \eTR
\bTR \bTD First \eTD \bTD 71.3 \eTD \eTR
\bTR \bTD Second \eTD \bTD 43.7 \eTD \eTR
\bTR \bTD Total \eTD \bTD 115 \eTD \eTR
\eTABLE

You'll note that the final line, because it has no . in the number, gets aligned under the right-hand side of the numbers. In most circumstances you would want such a number aligned with the left-hand set of digits. To so do, issue the following command in your preamble:

\chardef\characteralignmentmode=2

and now the table above will turn out like this: