# tabular input by columns (i.e. transpose a table)

I would like to be able to transpose a tabular(x) table like in the following example. It is not necessary to be completely automated, but I don't want to change the data order, which is a painful and stupid. By "not completely automated" I mean that e.g. the headers can be done seperately etc.

Let's see the MWE:

\documentclass{article}

\usepackage{booktabs}
\def\Midrule{\midrule[\heavyrulewidth]}

\begin{document}

\centering

\begin{tabular}{*6c}\toprule
\bfseries Name & Alice & Bob & Chuck & Dave & Eve\\\Midrule
\bfseries Sex & Female & Male & Male & Male & Female\\\midrule
\bfseries Age & 18 & 19 & 20 & 21 & 22\\\bottomrule
\end{tabular}

\bigskip

Which I want to look like

\bigskip

\begin{tabular}{*3c}\toprule
\bfseries Name & \bfseries Sex & \bfseries Age\\\Midrule
Alice & Female & 18\\\midrule
Bob & Male & 19\\\midrule
Chuck & Male & 20\\\midrule
Dave & Male & 21\\\midrule
Eve & Female & 22\\\bottomrule
\end{tabular}

\end{document}


Note: I know that there's an expl3 solution, but I would like to get it without expl3 (mostly because people would might use my code quite often have an old LaTeX installed and I cannot be convincing them to change this).

-

You can use \valign instead of \halign

\documentclass{article}

\usepackage{booktabs,array}
\def\Midrule{\midrule[\heavyrulewidth]}
\newcount\rowc

\makeatletter
\def\ttabular{%
\hbox\bgroup
\let\\\cr
\def\rulea{\ifnum\rowc=\@ne \hrule height 1.3pt \fi}
\def\ruleb{
\ifnum\rowc=1\hrule height 1.3pt \else
\ifnum\rowc=6\hrule height \heavyrulewidth
\else \hrule height \lightrulewidth\fi\fi}
\valign\bgroup
\global\rowc\@ne
\rulea
\hbox to 10em{\strut \hfill##\hfill}%
\ruleb
&&%
\hbox to 10em{\strut\hfill##\hfill}%
\ruleb
\cr}
\def\endttabular{%
\crcr\egroup\egroup}

\begin{document}

\centering

\begin{ttabular}
\bfseries Name & Alice & Bob & Chuck & Dave & Eve\\
\bfseries Sex & Female & Male & Male & Male & Female\\
\bfseries Age & 18 & 19 & 20 & 21 & 22\\
\end{ttabular}

\bigskip

Which I want to look like

\bigskip

\begin{tabular}{*3c}\toprule
\bfseries Name & \bfseries Sex & \bfseries Age\\\Midrule
Alice & Female & 18\\\midrule
Bob & Male & 19\\\midrule
Chuck & Male & 20\\\midrule
Dave & Male & 21\\\midrule
Eve & Female & 22\\\bottomrule
\end{tabular}

\end{document}

-
Now I need to understand what this is doing. Is it possible to avoid user-specified column width? –  tohecz Oct 8 '12 at 10:01
You need a user specified width there for same reason you need a user specified width in a tabular p column (everything is transposed:-) so the answer is yes or no, depending if you want to rely on on a single pass tex primitive alignment or a multi-pass X column trial that works out a good width, and how much time you have to program the latter:-) –  David Carlisle Oct 8 '12 at 10:04

Here is an alternate solution that uses the collcell package in conjunction with the datatool package to store each of the data elements for later processing. So, the following code:

\begin{Ttabular}{cccccc}
\bfseries Name & Alice & Bob & Chuck & Dave & Eve\\
\bfseries Sex & Female & Male & Male & Male & Female\\
\bfseries Age & 18 & 19 & 20 & 21 & 22\\
\end{Ttabular}


yields:

The environ package is used so that we can typeset the original table into a \savebox so it does not produce unwanted space in the output.

## Notes:

• The original column specification is applied to the transposed table. Hence, the number of columns in the original table must be greater than the number of rows. Otherwise just need to over specify the tabular columns in the source table (since it gets applied to the number of rows). In this example the first three column specification are applied to the transposed table, and the others are ignored.

## Further Enhancements:

• The line after the header row is \midrule. I attempted quite few things to be able to use \Midrule for that but was not able to get it to work. It thought that incorporating the solution from Equivalent of \DTLiflastrow would solve this but was not able to get it to work. I am starting to realize that tabular is even more finicky than I thought.

## Code:

\documentclass{article}
\usepackage{collcell}
\usepackage{xstring}
\usepackage{datatool}
\usepackage{booktabs}
\usepackage{environ}
%\usepackage{showframe}

\def\Midrule{\midrule[\heavyrulewidth]}

\newcounter{CurrentRow}% = column of transposed table
\newcounter{CurrentColumn}
\setcounter{CurrentColumn}{0}
\newtoggle{DoneWithFirstRow}

\newcommand*{\FirstColumn}[1]{%
\IfEq{\arabic{CurrentColumn}}{0}{%
% This is the start of the very first data entry in first row.
\global\togglefalse{DoneWithFirstRow}%
\setcounter{CurrentRow}{1}% initial value
}{%
% We have already completed a row. Now starting a new row.
\global\toggletrue{DoneWithFirstRow}%
\stepcounter{CurrentRow}%
}%
\setcounter{CurrentColumn}{0}%
\NewData{#1}%
}
\newcommand*{\NewData}[1]{%
\dtlexpandnewvalue%
\stepcounter{CurrentColumn}%
\iftoggle{DoneWithFirstRow}{%
\dtlgetrow{TransposedTabularDB}{\arabic{CurrentColumn}}%
\dtlappendentrytocurrentrow{\Alph{CurrentRow}}{#1}%
\dtlrecombine%
}{%
\DTLnewrow{TransposedTabularDB}%
\DTLnewdbentry{TransposedTabularDB}{\Alph{CurrentRow}}{#1}%
}%
}%

\newcolumntype{F}{>{\collectcell\FirstColumn}c<{\endcollectcell}}
\newcolumntype{C}{>{\collectcell\NewData}{c}<{\endcollectcell}}

%% No longer needed since we switched to NewEnviron
%\newcommand{\SaveColumnSpecificationAsZ}[1]{\newcolumntype{Z}{#1}}

\newtoggle{EncounteredDataRow}

\newsavebox{\TempBox}
\DTLnewdb{TransposedTabularDB}

\NewEnviron{Ttabular}[1]{%
%\SaveColumnSpecificationAsZ{#1}%
% Initialize in case of multiple uses
\setcounter{CurrentColumn}{0}%
\global\togglefalse{EncounteredDataRow}%
\savebox{\TempBox}{%
\begin{tabular}{FCCCCCC}% over speced tabular
\BODY%
\end{tabular}%
}%
\begin{tabular}{#1}\toprule%
% This could be made smarter to detect number of columns
\DTLforeach*{TransposedTabularDB}{\Aa=A, \Ba=B, \Ca=C}{%
\DTLiffirstrow{}{\\\midrule}%
\Aa & \Ba & \Ca %
}\\\bottomrule%
\end{tabular}%
}%

\begin{document}
\noindent
\begin{Ttabular}{cccccc}
\bfseries Name & Alice & Bob & Chuck & Dave & Eve\\
\bfseries Sex & Female & Male & Male & Male & Female\\
\bfseries Age & 18 & 19 & 20 & 21 & 22\\
\end{Ttabular}

\bigskip\noindent
Which I want to look like
\bigskip

\noindent
\begin{tabular}{*3c}\toprule
\bfseries Name & \bfseries Sex & \bfseries Age\\\Midrule
Alice & Female & 18\\\midrule
Bob & Male & 19\\\midrule
Chuck & Male & 20\\\midrule
Dave & Male & 21\\\midrule
Eve & Female & 22\\\bottomrule
\end{tabular}
\end{document}

-
This looks great! I'll have to test it and probably add some small features. (I prefer the line after the header to be \heavyrulewidth, but I think I'm able to do this myself). But this is something I thought must be doable. –  tohecz Nov 23 '12 at 7:38

A pgfplotstable solution is also convenient.

\documentclass{article}
\usepackage{booktabs}
\usepackage{pgfplotstable}
\begin{document}
Name   Alice   Bob   Chuck   Dave   Eve
Sex   Female   Male   Male   Male   Female
Age  18   19   20   21   22
}\mywidetable

\pgfplotstabletranspose[string type,
colnames from=Name,
input colnames to=Name
]\mytalltable{\mywidetable}

\pgfplotstabletypeset[string type,

If you really don't want to touch the data, then you can add col sep=&,row sep=\\ keys to the \pgfplotstableread.