4

My table needs to align its content both vertically and horizontally.

Here is the code:

\documentclass[twocolumn]{article}
\usepackage[T1]{fontenc}
\usepackage{booktabs, array}
\usepackage{lipsum}
\begin{document}
\begin{table*}
    \centering
      \begin{tabular}{>{\centering\arraybackslash}m{1cm}>{\centering\arraybackslash}m{1cm}}
        \toprule 1 & 2 \\ \midrule 3 & 4 \\ \bottomrule
      \end{tabular}
    \caption{table 1}
\end{table*}

\lipsum[1-15] % filler text
\end{document}

enter image description here

To the best of my understanding, m should align the contents vertically and these >{\centering\arraybackslash} segments should align it horizontally. However, if you measure the space above the digits and the space beneath them, you will see that there is more space beneath them.

The simple task is:

  • align cell content both horizontally and vertically, and
  • make column width scale automatically (with its content).

I found many similar questions here, but none of them actually addresses the problem on the elementary level.

3
  • 1
    Regarding "make column width scale automatically (with its content)." : wh not use a simple c type column?
    – leandriis
    Sep 19 at 16:45
  • 1
    " if you measure the space above the digits and the space beneath them, you will see that there is more space beneath them" this valid only in case, if in text you haven't letters g, p, y ...
    – Zarko
    Sep 19 at 17:06
  • I believe \toprule, \midrule and \bottomrule all add varying amounts of space above and below. Try \hline instead. Sep 19 at 19:50
4

The classic tool is the cellspace package: you prefix the column specifier with the letter S by default (or C if you load siunitx, or whatever letter you please with the [columntype=some letter] loading option):

\documentclass[twocolumn]{article}
\usepackage[T1]{fontenc}
\usepackage{booktabs, array}
\usepackage{lipsum}
\usepackage{cellspace}
\setlength{\cellspacetoplimit}{4pt}
\setlength{\cellspacebottomlimit}{4pt}

\begin{document}
\begin{table*}
    \centering
      \begin{tabular}{>{\centering\arraybackslash}S{m{1cm}}>{\centering\arraybackslash}S{m{1cm}}}
        \toprule 1 & 2 \\ \midrule 3 & 4 \\ \bottomrule
      \end{tabular}
    \caption{table 1}
\end{table*}

\lipsum[1-15] % filler text

\end{document} 

enter image description here

5

If you are in a hurry

fast answer

\documentclass[twocolumn]{article}
\usepackage[T1]{fontenc}
\usepackage{tabularray}     % <<----- added
\UseTblrLibrary{booktabs}   % <<----- added
\usepackage{booktabs, array}
\usepackage{lipsum}
\begin{document}

\begin{table*}
    \centering
    \begin{tblr}{colspec={Q[c,m]Q[c,m]},rows={rowsep=4pt},stretch=0}
        \toprule
         11 & 2 \\
        \midrule
         3 & 4444444 \\
        \bottomrule
    \end{tblr}
    \caption{tblr with numbers}
\end{table*}

\lipsum[1-15] % filler text
\end{document}

Long answer

Note 1: I've used a different package: tabularray
Note 2: I'd recommend you to read Mico's answer before mine.

About "align cell content both horizontally and vertically":

The tabularray package has a nice way to centralize everything. But as far as I know, it considers that the line to have a full height (with ascenders AND descenders) to perform the alignment. (Mico talks better about it)

You can see this in the following two examples stolen from the package documentation:

with text

\documentclass[twocolumn]{article}
\usepackage[T1]{fontenc}
\usepackage{tabularray}     % <<----- added
\UseTblrLibrary{booktabs}   % <<----- added
\usepackage{booktabs, array}
\usepackage{lipsum}
\begin{document}

\begin{table*}
    \centering
    \begin{tblr}{lccr}
        \hline
         Alpha & Beta & Gamma & Delta \\
        \hline
         Epsilon & Zeta & Eta & Theta \\
        \hline
         Iota & Kappa & Lambda & Mu \\
        \hline
    \end{tblr}
    \caption{tblr with text}
\end{table*}

\begin{table*}
    \centering
    \begin{tabular}{lccr}
        \hline
         Alpha & Beta & Gamma & Delta \\
        \hline
         Epsilon & Zeta & Eta & Theta \\
        \hline
         Iota & Kappa & Lambda & Mu \\
        \hline
    \end{tabular}
    \caption{tabular with text}
\end{table*}

\lipsum[1-15] % filler text
\end{document}

However, when you only use numbers (As Mico said, numbers have ascenders but not descenders) you get this, on which the tblr works even worse than tabular:

with numbers

\begin{table*}
    \centering
    \begin{tblr}{Q[c,m,1cm]Q[c,m,1cm]}
        \toprule
         1 & 2 \\
        \midrule
         3 & 4 \\
        \bottomrule
    \end{tblr}
    \caption{tblr with numbers}
\end{table*}

\begin{table*}
    \centering
      \begin{tabular}{>{\centering\arraybackslash}m{1cm}>{\centering\arraybackslash}m{1cm}}
        \toprule 1 & 2 \\ \midrule 3 & 4 \\ \bottomrule
      \end{tabular}
    \caption{tabular with numbers}
\end{table*}

Option 1 (this one is better)

Thanks to L.J.R.'s suggestion we can use stretch=0. I also used rowsep=4pt to make the table look less squished.

with numbers - LJR suggestion

\begin{table*}
    \centering
    \begin{tblr}{colspec={Q[c,m,1cm]Q[c,m,1cm]},stretch=0}
        \toprule
         1 & 2 \\
        \midrule
         3 & 4 \\
        \bottomrule
    \end{tblr}
    \caption{tblr without rowsep=4pt}
\end{table*}

\begin{table*}
    \centering
    \begin{tblr}{colspec={Q[c,m,1cm]Q[c,m,1cm]},stretch=0,rows={rowsep=4pt}}
        \toprule
         1 & 2 \\
        \midrule
         3 & 4 \\
        \bottomrule
    \end{tblr}
    \caption{tblr with rowsep=4pt}
\end{table*}

Option 2 (old solution)

You can manually fix this problem very easily by using abovesep+ to add space above text like so:

with numbers - old solution

\begin{table*}
    \centering
    \begin{tblr}{colspec={Q[c,m,1cm]Q[c,m,1cm]},rows={abovesep+=2pt}}
        \toprule
         1 & 2 \\
        \midrule
         3 & 4 \\
        \bottomrule
    \end{tblr}
    \caption{tblr with numbers}
\end{table*}

\begin{table*}
    \centering
      \begin{tabular}{>{\centering\arraybackslash}m{1cm}>{\centering\arraybackslash}m{1cm}}
        \toprule 1 & 2 \\ \midrule 3 & 4 \\ \bottomrule
      \end{tabular}
    \caption{tabular with numbers}
\end{table*}

About "make column width scale automatically (with its content)":

Not setting a width to Q column would solve this issue, wouldn't it?

with numbers - column width

\documentclass[twocolumn]{article}
\usepackage[T1]{fontenc}
\usepackage{tabularray}     % <<----- added
\UseTblrLibrary{booktabs}   % <<----- added
\usepackage{booktabs, array}
\usepackage{lipsum}
\begin{document}

\begin{table*}
    \centering
    \begin{tblr}{colspec={Q[c,m]|Q[c,m]},stretch=0,rows={rowsep=4pt}}
        \toprule
         1 & 2 \\
        \midrule
         3 & 4 \\
        \bottomrule
    \end{tblr}
    \caption{tblr with numbers}
\end{table*}

\begin{table*}
    \centering
    \begin{tblr}{colspec={Q[c,m]|Q[c,m]},stretch=0,rows={rowsep=4pt}}
        \toprule
         11 & 2 \\
        \midrule
         3 & 4444 \\
        \bottomrule
    \end{tblr}
    \caption{tblr with numbers}
\end{table*}

\lipsum[1-15] % filler text
\end{document}

Problem when you mix number and letters

The problem reappears when you mix letters and numbers (see Table 1 below). It's important to note that the alignment is being performed as if each character in the same row had the same total height as a box formed by them all. So a 3 and a p will be aligned as if they were 3p, which causes a visual misalignment.

problem

Note that 3 has no depth and p has less height than 3. Here is a good discussion on this topic of height and depth.

dimensions

\documentclass{article}
\usepackage[T1]{fontenc}
\usepackage{tabularray}     % <<----- added
\UseTblrLibrary{booktabs}   % <<----- added
\usepackage{xcolor}         % <<----- added
\usepackage{booktabs,array}

\newlength\height
\newlength\depth
\newlength\totalheight

\newcommand{\RULE}[1]{%
    \settoheight{\height}{#1}%
    \settodepth{\depth}{#1}%
    \setlength\totalheight{\dimexpr\height+\depth\relax}%
    \rule[-\depth]{0.1pt}{\totalheight}#1\rule[-\depth]{0.1pt}{\totalheight}%
}

\newcommand{\STH}[1]{%
    \settoheight{\height}{#1}%
    \settodepth{\depth}{#1}%
    \setlength\totalheight{\dimexpr\height+\depth\relax}%
    height of \textcolor{red}{#1}: \textcolor{blue!70!gray}{\the\height}\par
    depth of \textcolor{red}{#1}: \textcolor{blue!70!gray}{\the\depth}\par
    total height of \textcolor{red}{#1}: \textcolor{blue!70!gray}{\the\totalheight}\par
    \vspace{8pt}
}

\begin{document}

\STH{3}
\STH{p}
\STH{3p}

\begin{table*}[t]
    \centering
    \begin{tblr}{colspec={Q[c,m]Q[c,m]},stretch=0}
        \toprule
         1 & 2 \\
        \midrule 
         AAAA & 6 \\
        \midrule 
         g & pppp \\
        \midrule
         33 & pppp \\
        \midrule
         \RULE{3} & \RULE{p} \\
        \midrule 
         \RULE{\vphantom{3p}3} &  \RULE{\vphantom{3p}p}\\
        \midrule 
         \RULE{3p} &  \RULE{3p}\\
        \bottomrule
    \end{tblr}
    \caption{tblr with numbers and letters}
\end{table*}

\end{document}
4
  • 2
    What the OP wants is removing the strut. Setting stretch=0 will do the trick for any case.
    – L.J.R.
    Sep 20 at 12:31
  • Thank you @L.J.R.! You are the package creator, so I have no choice but to learn from you. I've updated my answer to include your suggestion and also added an issue that arises when we mix numbers and letters. If you have time to read my answer, please let me know whether you agree with everything I have said so that I can correct the remaining mistakes. Feel free to modify my answer any way you want.
    – Leone
    Sep 20 at 15:40
  • The result is correct when you mix numbers and letters: the space above 3 is the same as the space below p.
    – L.J.R.
    Sep 21 at 0:10
  • @L.J.R. Oh yes, this is theoretically correct, yes. All the characters in the same row are being considered to have the same total height, hence they are aligned relative to this invisible box generated by 3p. However I think the OP wanted a vertical alignment in visual way, i. e., as if the 3 didn't have depth and the p didn't have as much height as 3. I will expand the problem section in my answer to make that clear to future readers.
    – Leone
    Sep 21 at 16:57
4

I'd like to question your claim that the m column type doesn't center its contents vertically.

Your claim appears to be based in part on a very specific choice for the contents of the cells in your test table: the characters you chose have only ascenders (lines that rise above the x-line) but no descenders (lines that fall below the baseline). Once you relax this extreme choice, you'll find that the vertical whitespace between thr upper \midrule and the tips of the ascendersis very close to the amount of vertical whitespace between the bottoms of the descenders and the lower\midrule`.

You also wrote:

if you measure the space above the digits and the space beneath them, you will see that there is more space beneath them.

Again, that's true only if you only use characters that have ascenders and no descenders. For sure, if you were to use characters that have neither ascenders nor descenders -- acemnorsuvwxz -- your finding would have to be reversed.

In short: do learn to trust LaTeX to get the vertical alignment right. :-)

enter image description here

\documentclass[twocolumn]{article}
\usepackage[T1]{fontenc}
\usepackage{booktabs, array}
\begin{document}
\begin{table}
    \centering
      \begin{tabular}{*{2}{>{\centering\arraybackslash}m{3cm}}}
        \midrule 
        pqyhbkpqy & acemnorsuvwxz \\ 
        \midrule 
        acemnorsuvwxz & pqyhbkpqy \\ 
        \midrule
      \end{tabular}
\end{table}
\end{document}
1
  • That makes sense. However, it would be great if I could vertically align content in a dynamic fashion; in the sense that first the content is placed and then centering is applied. That way both, e.g., l and g can be centered.
    – foki
    Sep 20 at 13:24

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.