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

enter image description here

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
&&%
\global\advance\rowc\@ne
\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}

A pgfplotstable solution is also convenient.

\documentclass{article}
\usepackage{booktabs}
\usepackage{pgfplotstable}
\begin{document}
\pgfplotstableread{
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,
        every head row/.style={before row=\toprule,after row=\midrule},
        every last row/.style={after row=\bottomrule},
        after row=\midrule
]{\mytalltable}


\end{document}

enter image description here

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


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:

enter image description here

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}

\newlength{\WidthAdjustment}
\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
%% https://tex.stackexchange.com/questions/12234/how-do-i-expand-a-macro-into-a-tabular-head
%\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}

Tags:

Tables