12

My last answer about vertically aligned table inspired me to write my first question at this site. How to create the following table in various TeX approaches: plainTeX, LaTeX, Context, eplain, OPmac etc.? The comparison would be welcome.

The table has given column widths, each data item is vertically centered, some data items can be vertically spanned and vertically centered in its space. Data items are one of the two types: single centered line in the column or the paragraph. There are single lines between columns and between lines. The table looks like:

valign2

It would be fine to separate the code to two parts: first part will be signed as % macro code created by the macro programmer and/or typo designer. The second part is signed as % document and the author of the text is supposed to write it.

I'll give the answer for plainTeX (this is my domain). I am looking forward to another approaches.

As a bonus you can try to create the table from my book TeXbook inside out (full text is available here) from the page 142. The vertical aligning is here too: the last but one line is vertically centered and the the last line is aligned to the top.

Edit I am still waiting for LaTeX solution. One user mentioned in comments that this is worse aspect from typographical point of view. But I am not evaluating the typographical quality of many examples presented at tex.stackexchange. Why do it with this special case? For example, my customer asked me for creating the following excel-like table:

table-v

This is not used for printing in book but only as a tool printed on paper sheets to do data more transparent. This is typical example for \valign usage.

Is there a LaTeX approach to do this? LaTeX is mentioned here in 98 % of threads. Can we found somebody to explain this from LaTeX point of view? Or LaTeX isn't able to do it (without absorbing the plain TeX solution)?

Note: the vertical-alignment tag includes 1030 threads. What can be more natural than \valign primitive for such request...

Today, there is very similar question Different vertical alignment with multirow.

6
  • 3
    This is simply a badly laid out table, why bother? ;-)
    – egreg
    Jun 5, 2014 at 6:50
  • @egreg This evasion is very ferquent if something is more complicated:). Moreover this was the primary question where I was referred (by @Olumide) and there are 4 answers here with misconception the original question. You can omit the vertical lines if you feel them as bad.
    – wipet
    Jun 5, 2014 at 7:09
  • 4
    It's mid vertical alignment the worse aspect in the table, closely followed by the vertical rules.
    – egreg
    Jun 5, 2014 at 7:23
  • 4
    @egreg Why didn't you mention about worse aspect in the previous thread "centering multirow text in a table..."? Read the question from it carefully: The multirow text "spring" is NOT centered over the three rows that it spans. My interest is: is there a LaTeX and/or Context solution for this intelligent \multirow? I don't know. You can simply say: LaTeX is not able to do it. Please do detach the typographical aspect of this, this was not mine proposal. I did use \valign in many more cases in my practice and I am interesting how this is solved in another TeX macro packages.
    – wipet
    Jun 5, 2014 at 8:36
  • @wipet: AFAIK, with the \halign/\valign-primitives, you can only do either \multispan for columns in \halign, or for rows in \valign, but not both in the same table.
    – morbusg
    Jun 5, 2014 at 10:58

6 Answers 6

10

With ConTeXt:

\def\blah{blah blah blah blah }
\switchtobodyfont[10pt]
\starttext
\bTABLE
  \setupTABLE[offset=1em]
  \setupTABLE[column][each][align={middle, lohi}]
  \setupTABLE[column][3][align=right, width=.3\textwidth]
  \bTABLEhead
    \bTR\bTH Type\eTH         \bTH Specs\eTH   \bTH[align=middle] Uses\eTH\eTR
  \eTABLEhead
  \bTABLEbody
    \bTR\bTD\eTD              \bTD Model 1\eTD \bTD \blah\blah \eTD\eTR
    \bTR\bTD[nr=3] Spring\eTD \bTD Model 2\eTD \bTD \blah\blah\blah\blah\blah\blah blah blah blah \eTD\eTR
    \bTR                      \bTD Model 3\eTD \bTD \blah\blah \eTD\eTR
    \bTR                      \bTD Model 4\eTD \bTD \blah\blah blah blah blah \eTD\eTR
  \eTABLEbody
\eTABLE
\stoptext

which looks like

enter image description here

3
  • 1
    How ConTeXt do it? May be there are many passes throw the table data...
    – wipet
    Jun 5, 2014 at 10:30
  • 1
    @wipet: I don't know, but you can find the source for these "natural tables" in $TEXMF-DIST/tex/context/base/tabl-ntb.mkiv. ConTeXt sources are usually pretty pleasant to read.
    – morbusg
    Jun 5, 2014 at 10:49
  • 2
    @wipet: Yes, ConTeXt uses a too pass mechanism. The first pass to determine the maximum width of each cell, and the second pass to do the actual typesetting. Similar approach is also taken by LaTeX when typesetting aligned equations (align, falign, etc.)
    – Aditya
    Jun 5, 2014 at 12:50
10

I would show the solution based on OPmac. This macro package provides the \table command to create tables. Of course it uses \halign primitive. The following solution defines the \vtable alternative for \table based on \valign primitive. It redefines locally a few internal macros from OPmac. This is done in the \vtabledefs macro. A \vrule <-> \hrule, \vfil <-> \hfil etc. changes are performed here.

The user (in % document part) of the code can enjoy the OPmac table features, for example the non-intersected double lines.

% macros:
\input opmac

\def\vtable{\hbox\bgroup \catcode`\|=12 \vtabledefs \tableB}
\def\tableB#1#2{\offinterlineskip \def\tmpa{}\tabdata={}\scantabdata#1\relax
   \valign\expandafter{\the\tabdata\tabstrutA\cr#2\crcr}\egroup}
\def\vtabledefs{%
   \let\dopar=\hfilneg  % the items of paragraph format are prefixed by \dopar
   \def\setrowparams{\hsize=\dimen\tmpnum \leftskip=.5em \rightskip=\leftskip
      \normalbaselines \hsize=\tmpdim
      \emergencystretch=2em \noindent\hfil}%
   \def\topstrut{\vbox to3ex{}}\def\botstrut{\vtop to2ex{}}%
   \def\tabstrut{}%
   \def\multirow##1##2{\multispan{##1}\vfil\vbox{\setrowparams\topstrut##2\botstrut}\vfil\hrule}%
   \def\crl{\crcr\noalign{\vrule}}%
   \def\colw=##1 {\noalign{\global\tmpdim=##1}}%
   \def\addtabvrule{\ifx\tmpa\vrule \addtabdata{\kern\hhkern}%
      \ifnum\colnum=0\def\vvleft{\vvitem}\else\addto\ddlinedata{\vvitem}\fi\fi
      \let\tmpa=\vrule \addtabdata{\hrule}}%
   \def\crli{\crcr \omit \gdef\dditem{\omit\tablinefil}\gdef\vvitem{\tabvvline}%
      \vvleft\tablinefil\ddlinedata\cr}%
   \def\tablinefil{\leaders\vrule\vfil}%
   \def\tabvvline{\hrule\kern\hhkern\hrule}%
   \def\crlli{\crli\noalign{\kern\vvkern}\crli}%
   \tmpdim=100pt
   \def\tabdeclarec{\medskip\vfil\vbox{\setrowparams\topstrut####\unskip\botstrut}\vfil\medskip}%
}   
\def\vvkern{2pt} \def\hhkern{2pt}

% document:

\def\blah{blah blah blah blah blah blah blah blah}
\def\blahh{\blah\ \blah\ \blah\  blah blah blah}

\frame{\vtable{|c||c||c|c|c|}{\crli 
   \colw=20mm Type  & & \multirow3{Spring} \crlli
   \colw=20mm Specs & Model 1 & Model 2 & Model 3 & Model 4 \crlli
   \colw=40mm Uses  & \dopar\blah & \dopar\blahh & \dopar\blah & \dopar\blah\ blah \crli
}}
\bye

valign opmac doube lines

OPmac provides colors too. Then the second example uses this feature. The \vtabledefs is similar as above but new macros for colorization backgrounds of the items are added. Use pdftex to process it.

% macros:
\input opmac

\def\vtable{\hbox\bgroup \catcode`\|=12 \vtabledefs \tableB}
\def\tableB#1#2{\offinterlineskip \def\tmpa{}\tabdata={}\scantabdata#1\relax
   \valign\expandafter{\the\tabdata\tabstrutA\cr#2\crcr}\egroup}
\def\vtabledefs{%
   \let\dopar=\hfilneg  % the items of paragraph format are prefixed by \dopar
   \def\setrowparams{\hsize=\dimen\tmpnum \leftskip=.5em \rightskip=\leftskip 
      \normalbaselines \hsize=\tmpdim
      \emergencystretch=2em \noindent\hfil}%
   \def\topstrut{\vbox to3ex{}}\def\botstrut{\vtop to2ex{}}%
   \def\tabstrut{}%
   \def\crl{\crcr\noalign{\vrule}}%
   \def\colw=##1 {\noalign{\global\tmpdim=##1}}%
   \def\addtabvrule{\ifx\tmpa\vrule \addtabdata{\kern\hhkern}%
      \ifnum\colnum=0\def\vvleft{\vvitem}\else\addto\ddlinedata{\vvitem}\fi\fi
      \let\tmpa=\vrule \addtabdata{\hrule}}%
   \def\crli{\crcr \omit \gdef\dditem{\omit\tablinefil}\gdef\vvitem{\tabvvline}%
      \vvleft\tablinefil\ddlinedata\cr}%
   \def\tablinefil{\leaders\vrule\vfil}%
   \def\tabvvline{\hrule\kern\hhkern\hrule}%
   \def\crlli{\crli\noalign{\kern\vvkern}\crli}%
   \tmpdim=100pt
   \def\tabdeclarec{\medskip\vfil\vbox{\setrowparams\topstrut####\unskip\botstrut}\vfil\medskip}%
}
\def\vvkern{2pt} \def\hhkern{4pt}

\def\spancolor#1#2{\multispan{#1}{\localcolor#2\kern\vvkern\leaders\hrule width\tmpdim \vfil\kern\vvkern}}
\def\multirow#1#2{\multispan{#1}\vfil\vbox{\setrowparams\topstrut#2\botstrut}\vfil}%

\def\colitem#1{\omit{\localcolor#1\kern\vvkern\leaders\hrule width\tmpdim \vfil\kern\vvkern}}
\def\crc{\crcr\noalign{\global\advance\tmpdim by-\hhkern \hskip-\tmpdim \global\advance\tmpdim by-\hhkern}}
\def\crx{\crcr\noalign{\hskip\hhkern\hskip\hhkern}}

% document:

\def\blah{blah blah blah blah blah blah blah blah}
\def\blahh{\blah\ \blah\ \blah\  blah blah blah}  

\def\itemcolors#1#2#3#4#5{\colitem#1&\colitem#2&\colitem#3&\colitem#4&\colitem#5\crc}

\def\liRed{\setcmykcolor{0 .5 .5 0}}
\def\liBlue{\setcmykcolor{.3 .3 0 0}}
\def\liGreen{\setcmykcolor{.5 0 .5 0}}
\def\liOrange{\setcmykcolor{0 0.2 0.5 0}}
\def\liCyan{\setcmykcolor{.3 0 0 0}}

\vtable{ccccc}{
   \colw=20mm \colitem\liGreen & \colitem\liGreen & \spancolor3\liOrange \crc
   Type  & & \multirow3{Spring} \crx
   \colw=20mm \itemcolors\liRed\liBlue\liRed\liBlue\liRed
   Specs & Model 1 & Model 2 & Model 3 & Model 4 \crx
   \colw=40mm \itemcolors\liCyan\Yellow\liCyan\Yellow\liCyan
   Uses  & \dopar\blah & \dopar\blahh & \dopar\blah & \dopar\blah\ blah \crx
}
\bye

enter image description here

9

The plainTeX approach is here. This is my answer from here slightly improved. Two new features are here:

  • The code is divided to the macro part (done by macro programator) and document part (done by author).
  • The author can set the width of each column used in the table.

The code

% Macro code (by programator and designer)
\newcount\tmpnum
\def\setcolumnsA #1,{\if,#1,\else \advance\tmpnum by1 \dimen\tmpnum=#1 
   \expandafter \setcolumnsA \fi
}
\def\vtable #1#2{\vbox{\hbox{%
   \tmpnum=180 \setcolumnsA #1,,\tmpnum=180
   \everycr={\noalign{\vrule \global\advance\tmpnum by1}}% 
   \valign{&\hrule\vfil\vbox{\setrowparams\topstrut##\unskip\botstrut}\vfil\crcr
   #2\crcr}}\hrule}%
}
\def\multirow#1#2{\multispan{#1}\hrule\vfil\vbox{\setrowparams\topstrut#2\botstrut}\vfil}
\def\topstrut{\vbox to3ex{}} \def\botstrut{\vtop to2ex{}}
\def\setrowparams{\hsize=\dimen\tmpnum \leftskip=.5em \rightskip=\leftskip
   \ifdim\hsize=0pt \hsize=100pt \message{WARNING: the columnwidth is not set.}\fi
   \emergencystretch=2em \noindent\hfil}
\let\dopar=\hfilneg  % the items of paragraph format are prefixed by \dopar

% document (by author):
\def\blah{blah blah blah blah blah blah blah blah}
\def\blahh{\blah\ \blah\ \blah\  blah blah blah}

\vtable{25mm,25mm,40mm}{
   Type   & & \multirow3{Spring} \cr
   Specs  & Model 1 & Model 2 & Model 3 & Model 4 \cr
   Uses   & \dopar\blah & \dopar\blahh & \dopar\blah & \dopar blah blah \blah\ blah \cr
}

\end

You can process it by tex document or pdftex document. The result is the same as the table given in the question.

5

Here's a LaTeX solution:

\documentclass{article}
\usepackage{array,multirow}

\newcommand*\blah{blah blah blah blah }

\newcolumntype{z}[1]{>{\centering\arraybackslash}m{#1}}% a centered m-type column
\renewcommand*\multirowsetup{\centering}% default is \raggedright

\begin{document}

\begin{tabular}{|z{2cm}|z{2cm}|m{.3\linewidth}|}
  \firsthline
    \bfseries Type &
    \multicolumn{1}{c|}{\bfseries Specs} &
    \multicolumn{1}{c|}{\bfseries Uses} \\
  \hline
    & Model 1 & \blah\blah \\
  \hline
    \multirow{3}*[-2\baselineskip]{Spring}
    & Model 2 & \blah\blah\blah\blah\blah blah blah blah \\
  \cline{2-3}
    & Model 3 & \blah\blah \\
  \cline{2-3}
    & Model 4 & \blah\blah blah blah blah \\
  \lasthline
\end{tabular}

\end{document}

enter image description here

The »Spring« in the \multirow needed some vertical shift (the optional argument [-2\baselineskip]). If this is necessary depends on the actual use case and is explained in the manual.

Even easier and without the need for manual interference is using nested tabulars. We just need to suppress the space to the left and right of the inner tabular by inserting @{} to the column specs:

\documentclass{article}
\usepackage{array}

\newcommand*\blah{blah blah blah blah }

\newcolumntype{z}[1]{>{\centering\arraybackslash}m{#1}}

\begin{document}

\begin{tabular}{|z{2cm}|z{2cm}|m{.3\linewidth}|}
  \firsthline
    \bfseries Type &
    \bfseries Specs &
    \multicolumn{1}{c|}{\bfseries Uses} \\
  \hline
    & Model 1 & \blah\blah \\
  \hline
    Spring &
    \multicolumn{2}{@{}c@{}|}{%
      \begin{tabular}{z{2cm}|m{.3\linewidth}}
          Model 2 & \blah\blah\blah\blah\blah blah blah blah \\
        \hline
          Model 3 & \blah\blah \\
        \hline
          Model 4 & \blah\blah blah blah blah \\
      \end{tabular}%
    } \\
  \lasthline
\end{tabular}

\end{document}

The output is the same.

3
  • Thank you for LaTeX solution. But the main point of this thread is that we need to calculate the position of "Spring" automatically because we don't know how many blahs will be in the third column.
    – wipet
    Jul 8, 2014 at 10:14
  • 1
    @wipet that isn't entirely clear from the question: »How to create the following table«. I did look if this was required by your question but couldn't find it... I don't believe there is a ready made solution then in LaTeX
    – cgnieder
    Jul 8, 2014 at 10:20
  • 1
    @wipet I added a second solution that doesn't need manual adjusting
    – cgnieder
    Jul 8, 2014 at 11:58
1

An easy solution with tblr environment of the new LaTeX package tabularray:

\documentclass{article}

\usepackage{tabularray}

\newcommand*\blah{blah blah blah blah }

\NewColumnType{z}[1]{Q[m,c,#1]}% a centered m-type column

\begin{document}

\begin{tblr}{
  colspec ={|z{2cm}|z{2cm}|m{0.3\linewidth}|},
  row{1} = {c,font=\bfseries},
  cell{3}{1} = {r=3}{m,c}, % multirow
  hlines,
}
  Type   & Specs   & Uses \\
         & Model 1 & \blah\blah \\
  Spring & Model 2 & \blah\blah\blah\blah\blah blah blah blah \\
         & Model 3 & \blah\blah \\
         & Model 4 & \blah\blah blah blah blah \\
\end{tblr}

\end{document}

enter image description here

0

I always like the simplest way (little cheating), but this will work:

    \begin{table}
\begin{tabular}{|m{1cm}|m{3cm}|m{3 cm}|}
  \toprule
 Type & Specs & Uses \\
  \midrule
 & Model 1 & blah blah blah blah blah \\ \cline{1-3}
  & Model 2 & blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah \\ \cline{2-3}
Spring & Model 3 & blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah \\ \cline{2-3}
& Model 4 & blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah \\
\bottomrule
\end{tabular}
\end{table}

enter image description here

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .