Why Won't m{} Vertically Center My Contents?

I am trying to center ALL the contents of ALL the cells in the table below. It's working horizontally, but not vertically.

I definitely don't know how to best vertically center the last column, but I really thought that the m{} thing would center the first two columns. What's going on?

\documentclass[12pt,letterpaper]{article}

\usepackage{array}
\usepackage{tabularx}
\usepackage{tikz}
\usepackage{cellspace}
\setlength\cellspacetoplimit{10pt}
\setlength\cellspacebottomlimit{4pt}

\begin{document}

% To center the first two columns.
{\newcolumntype{C}[1]{>{\centering\arraybackslash}m{#1}}

% To center the final "X" column.
{\newcolumntype{Y}{>{\centering\arraybackslash}X} % Centers the X column.
\begin{tabularx}{16cm}{|C{2.5cm}|C{3cm}|Y|} \hline

\textbf{Parts Per Whole} & \textbf{Name of Each Part} & \textbf{Number Line} \\ [0.2cm] \hline

3 & third &
\begin{tikzpicture}[xscale=4 , yscale=2]
\draw (0,0)--(2,0) ;
\foreach \x in {0,...,6}
\draw (\x/3,-0.2)--(\x/3,0.2);
\foreach \x in {0,...,2} \node[below] at (\x,-0.35) {\x};
\end{tikzpicture} \\ [0.2cm] \hline

\end{tabularx}
}
}

\end{document}

• \m? I don't see that anywhere in the code you posted. – Sean Allred Jul 26 '15 at 21:04
• @SeanAllred Whoops, I meant m{} not \m{}. I'll fix that in the original post. In the code, there is a m{} underneath the comment " % To center the first two columns. " – WeCanLearnAnything Jul 26 '15 at 21:07
• m{..} doesn't work if it is not the last column. If it is, then all columns are vertically centered regardless of column specifier.This problem was ones already discussed in SE, but I cant remember the question. – Zarko Jul 26 '15 at 21:10
• @ Zarko. A couple issues. First is that nothing is centered vertically in the second row. Also, did you mean that m{...} works everywhere EXCEPT the last column? – WeCanLearnAnything Jul 26 '15 at 21:15
• Also... how do I make an IMGUR picture show up directly in this thread instead of just having a link to it? – WeCanLearnAnything Jul 26 '15 at 21:20

They are centred vertically. That is, they are centred on the current baseline. (See explanation below.) The problem is that the bottom of the tikzpicture is on the baseline by default. To centre that, we can use baseline in the argument for the picture:

\documentclass[12pt,letterpaper]{article}
\usepackage{array}
\usepackage{tabularx}
\usepackage{tikz}
\usepackage{cellspace}
\setlength\cellspacetoplimit{10pt}
\setlength\cellspacebottomlimit{4pt}
\newcolumntype{C}[1]{>{\centering\arraybackslash}m{#1}}
\newcolumntype{Y}{>{\centering\arraybackslash}X}
\begin{document}
\begin{tabularx}{16cm}{|C{2.5cm}|C{3cm}|Y|} \hline
\textbf{Parts Per Whole} & \textbf{Name of Each Part} & \textbf{Number Line} \\ [0.2cm] \hline
3 & third &
\begin{tikzpicture}[xscale=4 , yscale=2, baseline=(current bounding box.center)]
\draw (0,0)--(2,0) ;
\foreach \x in {0,...,6}
\draw (\x/3,-0.2)--(\x/3,0.2);
\foreach \x in {0,...,2} \node[below] at (\x,-0.35) {\x};
\end{tikzpicture} \\ [0.2cm] \hline
\end{tabularx}
\end{document}


Note that the tabular is too wide for the page. Also, you might want to read booktabs' manual which has some recommendations for laying out professional quality tables.

For example, adjusting things to fit and using booktabs:

\documentclass[12pt,letterpaper]{article}
\usepackage{array,booktabs}
\usepackage{tabularx}
\usepackage{tikz}
\usepackage{cellspace}
\setlength\cellspacetoplimit{10pt}
\setlength\cellspacebottomlimit{4pt}
\newcolumntype{C}[1]{>{\centering\arraybackslash}m{#1}}
\newcolumntype{Y}{>{\centering\arraybackslash}X}
\begin{document}
\noindent\begin{tabularx}{\textwidth}{C{2.5cm}C{3cm}Y}
\toprule
\textbf{Parts Per Whole} & \textbf{Name of Each Part} & \textbf{Number Line} \\\midrule
3 & third &
\begin{tikzpicture}[xscale=3, yscale=1.5, baseline=(current bounding box.west)]
\draw (0,0)--(2,0) ;
\foreach \x in {0,...,6}
\draw (\x/3,-0.2)--(\x/3,0.2);
\foreach \x in {0,...,2} \node[below] at (\x,-0.35) {\x};
\end{tikzpicture}\\ \bottomrule
\end{tabularx}
\end{document}


Explanation

This is obviously not a complete explanation but merely an indication of how TeX is aligning things vertically.

In this answer I illustrate the way TeX aligns things vertically by playing with some minipages and showing how the alignment options affect their position relative to a line of text or to each other.

Here, I use the same idea to illustrate alignment of m{} columns within a tabular. Each cell in the tabular includes a minipage. The top blue line is the baseline of the first line of text. The bottom one is the baseline of the last line of text. The blue letter t, b or c is the alignment of the minipage - top, bottom or centred. This tells TeX which point of the minipage should be aligned to the current baseline. The baseline is shown in red.

It is important to remember that everything is a box. TeX doesn't care what is inside the boxes. It just follows a set of rules for laying out boxes on a page. A single letter is a box. So is a comma. So is an entire tikzpicture or a minipage or the contents of a cell in a tabular. Smaller boxes can be put together to form bigger boxes: a tabular is a big box containing smaller boxes. How stuff is aligned depends on which box TeX is aligning and how that is aligned. The baseline is adjusted to ensure things are aligned according to the options (or defaults) requested.

Alignment is relative to the current baseline. The baseline is not fixed. The location of the baseline depends on the content of the line. A large box (like a tikzpicture) will shift the baseline down by default because the default setting is to align its bottom with the current baseline and the only way to make room for it is to shift the baseline down.

\documentclass[a4paper]{article}
\usepackage{geometry}
\geometry{vscale=.975}
\pagestyle{empty}
\usepackage{tikz,array,tikzpagenodes}
\usetikzlibrary{tikzmark}
\begin{document}
\newcommand\demobox[1]{%
\fbox{%
\begin{minipage}[#1]{.25\textwidth}
\tikz[baseline=(n.base)]{%
\node (n) [inner sep=0pt, outer sep=0pt, text width=\linewidth] {Top};
\draw [blue] (n.west |- n.base) -- (n.east |- n.base);}
\par
This is a box with baseline at \textcolor{blue}{\bfseries #1}.
\par
\tikz[baseline=(n.base)]{%
\node (n) [inner sep=0pt, outer sep=0pt, anchor=base, text width=\linewidth] {Bottom};
\draw [blue] (n.west |- n.base) -- (n.east |- n.base);}
\end{minipage}}}
\tikzmark{first}
\begin{tabular}{m{.25\textwidth}p{.25\textwidth}p{.25\textwidth}}
\demobox{c}&\demobox{c}&\demobox{c}\tikzmark{1}\\
\demobox{t}&\demobox{t}&\demobox{t}\tikzmark{2}\\
\demobox{b}&\demobox{b}&\demobox{b}\tikzmark{3}\\
\demobox{t}&\demobox{c}&\demobox{b}\tikzmark{4}\\
\end{tabular}
\vfill
\hrule
\vfill

\tikzmark{centre}
\begin{tabular}{p{.25\textwidth}m{.25\textwidth}p{.25\textwidth}}
\demobox{c}&\demobox{c}&\demobox{c}\tikzmark{5}\\
\demobox{t}&\demobox{t}&\demobox{t}\tikzmark{6}\\
\demobox{b}&\demobox{b}&\demobox{b}\tikzmark{7}\\
\demobox{t}&\demobox{c}&\demobox{b}\tikzmark{8}\\
\end{tabular}
\vfill
\hrule
\vfill

\tikzmark{final}
\begin{tabular}{p{.25\textwidth}p{.25\textwidth}m{.25\textwidth}}
\demobox{c}&\demobox{c}&\demobox{c}\tikzmark{9}\\
\demobox{t}&\demobox{t}&\demobox{t}\tikzmark{10}\\
\demobox{b}&\demobox{b}&\demobox{b}\tikzmark{11}\\
\demobox{t}&\demobox{c}&\demobox{b}\tikzmark{12}\\
\end{tabular}

\begin{tikzpicture}[remember picture, overlay]
\node [left, align=left, text width=.2\textwidth] at ({pic cs:first}) {Vertically centre \textcolor{blue}{\bfseries first} column};
\node [left, align=left, text width=.2\textwidth] at ({pic cs:centre}) {Vertically centre \textcolor{blue}{\bfseries middle} column};
\node [left, align=left, text width=.2\textwidth] at ({pic cs:final}) {Vertically centre \textcolor{blue}{\bfseries last} column};
\foreach \i in {1,...,12} \draw [red] ({pic cs:\i} -| current page text area.west) -- ({pic cs:\i} -| current page text area.east);
\end{tikzpicture}
\end{document}


Here is how this works with multiline text without minipages. The red lines mark the current baseline.

\documentclass[a4paper]{article}
\usepackage{array,geometry,tikz,tikzpagenodes}
\usetikzlibrary{tikzmark}
\geometry{scale=.9}
\newcommand\mykant{Let us suppose that the noumena have nothing to do with necessity, since knowledge of the Categories is a posteriori.}
\begin{document}
\begin{tabular}{m{.25\textwidth}p{.25\textwidth}p{.25\textwidth}}
\multicolumn{3}{c}{\bfseries First column vertically centred}\\
\mykant   & \tikzmark{a}some text &   \mykant\\
\end{tabular}
\bigskip
\hrule
\bigskip
\begin{tabular}{p{.25\textwidth}m{.25\textwidth}p{.25\textwidth}}
\multicolumn{3}{c}{\bfseries Middle column vertically centred}\\
\mykant   & some text\tikzmark{b} &   \mykant\\
\end{tabular}
\bigskip
\hrule
\bigskip
\begin{tabular}{p{.25\textwidth}p{.25\textwidth}m{.25\textwidth}}
\multicolumn{3}{c}{\bfseries Last column vertically centred}\\
\mykant   & some text\tikzmark{c} &   \mykant\\
\end{tabular}
\begin{tikzpicture}[remember picture, overlay]
\foreach \i in {a,b,c}
\draw [draw=red] ({pic cs:\i} -| current page text area.west) -- ({pic cs:\i} -| current page text area.east);
\end{tikzpicture}
\end{document}

• @cft, nice solution, however do you try, if it works, if you for example instead of tikzpicture with smart defined baseline, have for example multi line text? – Zarko Jul 26 '15 at 22:12
• @Zarko Yes. It works as expected. That is, as I expect it to given my understanding of how TeX aligns things which is, admittedly not initially entirely intuitive. See further edit above. I've added an illustration with just multiline content to the one which uses minipages. The point is that you need to know what is being aligned to the baseline in every case to predict the results. That's as true of multiline text (which is being typeset in a \parbox with alignment [t], I think, as it is with a tikzpicture or a minipage. – cfr Jul 26 '15 at 22:38
• @cfr, Thanks for this amazing post! When I get back home later on I'll take a closer look at it. – WeCanLearnAnything Jul 27 '15 at 0:55