2

I made the following table with tabularx and expected that in the second row, all cells have the same width, since they all use multicolumn{2}. But they don't. Instead the third and sixth cell width is double that of the others.

Similar problems with rows 3 to 6. The first and fourth cell on each row is only half as wide as it should be, considering that it uses multicolumn{4}, while the other cells have double the expected width.

Am I doing sth. wrong or does tabularx behave different than I think it does? I thought that the width of an X column will be relative to the nr of columns defined with \multicolumn{n}. I. e. if the whole table has 12 columns and I specify \multicolumn{2} that column width will be a sixth of the whole table. But apparently that isn't the case, or rather it only works for the first row...

\documentclass{article}
\usepackage{tabularx}
\usepackage{booktabs}

\begin{document}

\begin{table}[h]
    \begin{tabularx}{\textwidth}{*{12}{X|}}
        \hline
        \multicolumn{6}{|X|}{6 cols} & \multicolumn{6}{|X|}{6 cols} \\
        \hline
        \multicolumn{2}{|X|}{2 cols} & \multicolumn{2}{X|}{2 cols} & \multicolumn{2}{X|}{2 cols} & \multicolumn{2}{|X|}{2 cols} & \multicolumn{2}{X|}{2 cols} & \multicolumn{2}{X|}{2 cols}\\
        \hline
        \multicolumn{4}{|X|}{4 cols} & & & \multicolumn{4}{|X|}{4 cols} & & \\
        \hline
        \multicolumn{4}{|X|}{4 cols} & & & \multicolumn{4}{|X|}{4 cols} & &  \\
        \hline
        \multicolumn{4}{|X|}{4 cols} & & & \multicolumn{4}{|X|}{4 cols} & & \\
        \hline
        \multicolumn{4}{|X|}{4 cols} & & & \multicolumn{4}{|X|}{4 cols} & & \\
        \hline
    \end{tabularx}
\end{table}

\end{document}
5
  • X is p{table-width/12} so all your multicolumn are too narrow Aug 7, 2023 at 20:25
  • 1
    You ask, "Am I doing something wrong?" Short answer: Yes. Slightly longer answer: Your tabularx environment contains too many, mutually conflicting pieces of information. In some cases, by shear [dumb?] luck, things just happen to look like could be working out. But that's just coincidence. What exactly are you trying to prove with the code you posted?
    – Mico
    Aug 7, 2023 at 20:40
  • @DavidCarlisle - I don't think it's a matter of \textwidth not being large enough.
    – Mico
    Aug 7, 2023 at 20:43
  • @Mico exactly. the value of the table width is not relevant, you can not span two X columns with \multicolumn{2}{|X|} Aug 7, 2023 at 21:01
  • @Mico: Not trying to prove anything. I'm just asking a question about the code I've posted, because... this is a place for people (incl. those with dumb luck) to ask questions about latex code? Aug 8, 2023 at 5:48

3 Answers 3

5

You asked,

Am I doing something wrong?

Short answer: Yes.

Slightly longer answer: Your tabularx environment contains too many mutually conflicting pieces of information; the result is a mess that cannot yield the "correct" column width. In some cases, it's by shear luck that things just happen to look like they're working out. However, that's just coincidence. The upshot? You need to stop providing these mutually conflicting directives.

Let's break up the whole tabularx into smaller parts. Let's start with a simple-looking case:

\begin{tabularx}{\textwidth}{|*{12}{X|}}
        \hline
        \multicolumn{6}{|X|}{6 cols} & 
        \multicolumn{6}{ X|}{6 cols} \\
        \hline
\end{tabularx}

This looks innocuous, doesn't it? But, as always, looks can be deceiving. The source of the trouble that's lurking just below the surface is a case of abuse of notation: The X column type is being forced to do double duty. First, since there are supposed to be 12 equal-width columns, the default usable width of each column equals \textwidth/12-2\tabcolsep-(13/12)\arrayrulewidth. (Aside: $13/12 \approx 1.08333$.) But in \multicolumn{6}{X|}{6 cols}, the width of the cell is actually 6 times as large. [I'll let the designer of the tabularx package explain why this abuse of notation was allowed to slide and doesn't throw an error...] Luckily -- by sheer happy coincidence, I must emphasize -- things turn out to be ok, i.e., LaTeX manages to figure out correctly what the width of combined columns is supposed to be. This is because

\begin{tabularx}{\textwidth}{| *{12}{X|} }
        \hline
        \multicolumn{6}{|X|}{6 cols} & 
        \multicolumn{6}{ X|}{6 cols} \\
        \hline
\end{tabularx}

can be simplified w.l.o.g. to

\begin{tabularx}{\textwidth}{| X | X |}
        \hline
        1 col & 1 col \\
        \hline
\end{tabularx}

for which there's no more any abuse of notation. Put differently, LaTeX solves the puzzle by discarding the redundancies built into the first tabularx environment.


Let's consider a slightly more interesting case:

\begin{tabularx}{\textwidth}{| *{12}{X|} }
        \hline
        \multicolumn{6}{|X|}{6 cols} & 
        \multicolumn{6}{ X|}{6 cols} \\
        \hline
        \multicolumn{2}{|X|}{2 cols} & 
        \multicolumn{2}{ X|}{2 cols} & 
        \multicolumn{2}{ X|}{2 cols} & 
        \multicolumn{2}{ X|}{2 cols} & 
        \multicolumn{2}{ X|}{2 cols} & 
        \multicolumn{2}{ X|}{2 cols} \\
        \hline
\end{tabularx}

Observe the rampant abuse of notation leading to the width of an X-type column potentially having three [3!] separate values. But a moment's reflection shows that this must be the same as

\begin{tabularx}{\textwidth}{|*{6}{X|}}
        \hline
        \multicolumn{3}{|X|}{3 cols} & 
        \multicolumn{3}{ X|}{3 cols} \\
        \hline
        1 col & 1 col & 1 col & 1 col & 1 col & 1 col \\
        \hline
\end{tabularx}

for which there are, once again, no ambiguities. The point is that there aren't really 12 independent columns, but only 6, and LaTeX now has just enough information to skate back and forth between the two possible values for the width of an X-type column. Put differently, the simpler problem has no fatal ambiguities.


Finally, let us turn to a case where the redundancies cannot be eliminated unambiguously.

\begin{tabularx}{\textwidth}{| *{12}{X|} }
        \hline
        \multicolumn{6}{|X|}{6 cols} & 
        \multicolumn{6}{ X|}{6 cols} \\
        \hline
        \multicolumn{4}{|X|}{4 cols (?!)} & a & b & 
        \multicolumn{4}{ X|}{4 cols (?!)} & c & d  \\
        \hline
\end{tabularx}

enter image description here

LaTeX has been provided enough information to figure out that the combined width of the first three cells in row 2 must equal the width of the first cell in row 1. However, there simply isn't enough information left over to allow LaTeX to also infer that the width of the first cell in row 2 must be equal to 4 times the width of cells 2 and 3 in that row. Instead, what you end up getting is three cells of equal width in row 2. Ouch.

To resolve the situation, what's really needed is something like this:

\newlength\mylen
\setlength\mylen{\textwidth/12-2\tabcolsep-1.08333\arrayrulewidth}
\begin{tabularx}{\textwidth}{| *{2}{*{4}{X|} *{2}{wl{\mylen}|}} }
        \hline
        \multicolumn{6}{|X|}{6 cols} & 
        \multicolumn{6}{ X|}{6 cols} \\
        \hline
        \multicolumn{4}{|X|}{4 cols} & a & b & 
        \multicolumn{4}{ X|}{4 cols} & c & d  \\
        \hline
\end{tabularx}

which produces this result:

enter image description here

The reason this "works as expected" is that we're now giving LaTeX enough information to let it infer that the width of the cell given by \multicolumn{4}{|X|}{4 cols} must be two thirds (rather than just one third) of the width of the cell given \multicolumn{6}{|X|}{6 cols}.

Moral of the story? Don't be surprised to learn that if you don't provide enough useful information to tabularx, it won't be able to solve the column width assignment problem correctly.


Just for completeness, here are all six tabularx environments mentioned above:

enter image description here

\documentclass{article}
\usepackage{tabularx,calc}

% code needed for the final 'tabularx' example:
\newlength\mylen
\setlength\mylen{\textwidth/12-2\tabcolsep-1.08333\arrayrulewidth}

\setlength\parindent{0pt} % just for this example

\begin{document}

\begin{tabularx}{\textwidth}{|*{12}{X|}}
        \hline
        \multicolumn{6}{|X|}{6 cols} & 
        \multicolumn{6}{ X|}{6 cols} \\
        \hline
\end{tabularx}

\smallskip
\begin{tabularx}{\textwidth}{|X|X|}
        \hline
        1 col & 1 col \\
        \hline
\end{tabularx}


\bigskip
\begin{tabularx}{\textwidth}{*{12}{X|}}
        \hline
        \multicolumn{6}{|X|}{6 cols} & 
        \multicolumn{6}{ X|}{6 cols} \\
        \hline
        \multicolumn{2}{|X|}{2 cols} & 
        \multicolumn{2}{ X|}{2 cols} & 
        \multicolumn{2}{ X|}{2 cols} & 
        \multicolumn{2}{ X|}{2 cols} & 
        \multicolumn{2}{ X|}{2 cols} & 
        \multicolumn{2}{ X|}{2 cols} \\
        \hline
\end{tabularx}

\smallskip
\begin{tabularx}{\textwidth}{|*{6}{X|}}
        \hline
        \multicolumn{3}{|X|}{3 cols} & 
        \multicolumn{3}{ X|}{3 cols} \\
        \hline
        1 col & 1 col & 1 col & 1 col & 1 col & 1 col \\
        \hline
\end{tabularx}

\bigskip
\begin{tabularx}{\textwidth}{|*{12}{X|}}
        \hline
        \multicolumn{6}{|X|}{6 cols} & 
        \multicolumn{6}{ X|}{6 cols} \\
        \hline
        \multicolumn{4}{|X|}{4 cols (?!)} & a & b & 
        \multicolumn{4}{ X|}{4 cols (?!)} & c & d  \\
        \hline
\end{tabularx}

\smallskip
\begin{tabularx}{\textwidth}{| *{2}{*{4}{X|} *{2}{wl{\mylen}|}} }
        \hline
        \multicolumn{6}{|X|}{6 cols} & 
        \multicolumn{6}{ X|}{6 cols} \\
        \hline
        \multicolumn{4}{|X|}{4 cols} & a & b & 
        \multicolumn{4}{ X|}{4 cols} & c & d  \\
        \hline
\end{tabularx}

\end{document}
8
  • 1
    +1 back:-)..... Aug 7, 2023 at 22:17
  • > However, there simply isn't enough information left over to allow LaTeX to also > infer that the width of the first cell in row 2 must be equal to 4 times the width of > cells 2 and 3 in that row. Hmm... imo the information is there: the first cell is defined as \multicolumn{4}{x}, which to me means "4 times the determined column width", while the others are just X, i. e. the determined column width (\textwidth / 12). At least that would be an intuitive user interface. But apparently, tabularx works differently... Aug 8, 2023 at 6:09
  • @Mico: Thanks for the examples. I understand how you compute \mylen but it would be nice if you could explain how you came up with the {| *{2}{*{4}{X|} *{2}{wl{\mylen}|}} } arguments, because that's obviously the magic that fixes it... Aug 8, 2023 at 6:26
  • @seeplusn00b - Regarding your first comment: The problem is that because the tabularx machinery tolerates some abuse of notation, it's actually not unambiguous as to when the basic width calculation applies (what you call "the determined column width", or roughly \textwidth/12) and when the widths implied by either \multicolumn{6}{|X|}{...} and \multicolumn{4}{|X|}{...} apply. Taking a point from David Carlisle's own answer, one may infer that specifying \multicolumn{6}{|>{\hsize=\dimexpr6\hsize+10\tabcolsep+5\arrayrulewidth}X|}{...} ...
    – Mico
    Aug 8, 2023 at 8:41
  • @seeplusn00b -- (continuing the comment...) -- and \multicolumn{4}{|>{\hsize=\dimexpr4\hsize+6\tabcolsep+3\arrayrulewidth}X|}{...} would suffice to resolve the ambiguity. In the absence of such helpful information, the best tabularx can do to determine the column widths is to fall back on simpler heuristics. As I hope my answer has demonstrated, sometimes the simpler heuristics happen to "work", but sometimes they don't.
    – Mico
    Aug 8, 2023 at 8:45
3

an X column is a p column for a width which is determined for the whole table,

so if the first two columns are |X|X| (the first | is missing in your example), then
\multicolumn{2}{|X|}{...} will span the columns but ... will be forced into a parbox of the width determined by X which is less than half the required width.

You could use \multicolumn{2}{|l|}{...} so the width is automatic, or if you need linebreaking,
\multicolumn{2}{|>{\hsize=\dimexpr2\hsize+2\tabcolsep+\arrayrulewidth}X|}{...}
so the p column is the width of two X columns and the spanned padding and rule.

2
  • Nice answer (+1). I've provided an answer that's much wordier than yours.
    – Mico
    Aug 7, 2023 at 21:59
  • Thanks! But I'm not sure what you mean by "you could use \multicolumn{2}{|l|}{...}". Replacing every occurrence of multicolumn{n}{|X|}{...} with \multicolumn{n}{|l|}{...}, without any other changes? I tried that, but it didn't change the result at all. Aug 8, 2023 at 6:18
0

I decided to answer my own question, since I couldn't fix the table using the provided answers. Thanks anyway @mico and @david-carlisle.

TL;DR: I gave up explaining LaTeX how to determine the correct column width and did it manually. The following code results in the table I want:

\begin{tabular}{*{12}{l}}
        \hline
        \multicolumn{6}{|p{\dimexpr(\textwidth-3\arrayrulewidth-4\tabcolsep)/2\relax}|}{
            6 col
        } & \multicolumn{6}{p{\dimexpr(\textwidth-3\arrayrulewidth-4\tabcolsep)/2\relax}|}{
            6col
        } \\
        \hline
        \multicolumn{2}{|p{\dimexpr(\textwidth-7\arrayrulewidth-12\tabcolsep)/6\relax}|}{
            2 col
        } &
        \multicolumn{2}{p{\dimexpr(\textwidth-7\arrayrulewidth-12\tabcolsep)/6\relax}|}{
            2 col
        } &
        \multicolumn{2}{p{\dimexpr(\textwidth-7\arrayrulewidth-12\tabcolsep)/6\relax}|}{
            2 col
        } &
        \multicolumn{2}{p{\dimexpr(\textwidth-7\arrayrulewidth-12\tabcolsep)/6\relax}|}{
            2 col
        } &
        \multicolumn{2}{p{\dimexpr(\textwidth-7\arrayrulewidth-12\tabcolsep)/6\relax}|}{
            2 col
        } &
        \multicolumn{2}{p{\dimexpr(\textwidth-7\arrayrulewidth-12\tabcolsep)/6\relax}|}{
            2 col
        } \\
        \hline
        \multicolumn{4}{|p{\dimexpr(\textwidth-7\arrayrulewidth-12\tabcolsep)/3\relax}|}{
            4 col
        } & 
        \multicolumn{1}{p{\dimexpr(\textwidth-13\arrayrulewidth-24\tabcolsep)/12\relax}|}{
            1 col
        } & 
        \multicolumn{1}{p{\dimexpr(\textwidth-13\arrayrulewidth-24\tabcolsep)/12\relax}|}{
            1 col 
        }& 
        \multicolumn{4}{p{\dimexpr(\textwidth-7\arrayrulewidth-12\tabcolsep)/3\relax}|}{
            4 col
        } & 
        \multicolumn{1}{p{\dimexpr(\textwidth-7\arrayrulewidth-24\tabcolsep)/12\relax}|}{
            1 col
        } & 
        \multicolumn{1}{p{\dimexpr(\textwidth-13\arrayrulewidth-24\tabcolsep)/12\relax}|}{
            1 col 
        } \\
        \hline      
    \end{tabular}

Long version: I tried to fix my table using the examples from @Mico, but I failed. E. g. the following code:

\documentclass{article}
\usepackage{tabularx,calc}
\begin{document}

\newlength\mylen
\setlength\mylen{\textwidth/12-2\tabcolsep-1.08333\arrayrulewidth}
\begin{tabularx}{\textwidth}{| *{2}{*{4}{X|} *{2}{wl{\mylen}|}} }
        \hline
        \multicolumn{6}{|X|}{6 cols} & 
        \multicolumn{6}{ X|}{6 cols} \\
        \hline
        \multicolumn{4}{|X|}{4 cols} & a & b & 
        \multicolumn{4}{ X|}{4 cols} & c & d  \\
        \hline
\end{tabularx}

\end{document}

rendered a wrong table locally and also on https://www.papeeria.com. What I didn't realize is that the default LaTeX version on papeeria.com is too old (from 2015!) to correctly compile that code. And locally, the code renders correctly when using a fresh document, but not when pasting it into my existing one. I did not debug this, as I already had my own working solution above when I realised that.

UPDATE: I found a more elegant (and much shorter) solution using tabularray:

\documentclass{article}
\usepackage{tabularray}
\begin{document}
\begin{table}
\begin{tblr}{
        width=\textwidth,
        colspec={|X|X|X|X|X|X|X|X|X|X|X|X|},
        hline{1-Z} = {1-Z}{solid},
        vline{1-Z} = {1-Z}{solid},
        cells = {l},
        cell{1}{1,7} = {c=6}{l},
        cell{2}{1,3,5,7,9,11} = {c=2}{l},
        cell{3-6}{1,7} = {c=4}{l},
        }
        6 cols & & & & & & 6 cols & & & & & \\
        2 cols & & 2 cols & & 2 cols & & 2 cols & & 2 cols & & 2cols & \\
        4 cols & & & & 1 col & 1 col & 4 cols & & & & 1col & 1col \\
\end{tblr}
\end{table}
\end{document}

This also results the table that I wanted.

6
  • tabularray˙˙ example also works with simple tabular` table and not enable split cells text in several lines. ...
    – Zarko
    Aug 8, 2023 at 11:02
  • @Mico: did you also try papeeria.com? That shows the 88 errors with the code I pasted above. I'm using TexMaker 5.0.3. and pdfTeX 3.141592653-2.6-1.40.22. Aug 8, 2023 at 15:09
  • @seeplusn00b - If you're going to use papeeria.com, then by all means tell it to compile the test document with TeXLive2019. The default would appear to be TeXLive2015... Sheesh. FWIW, the current TeXLive distribution is numbered 2023 -- 4 years newer than the newest option provided by papeeria.com... Or, do you have a compelling reason for wishing to be stuck with TeXLive2015?
    – Mico
    Aug 8, 2023 at 15:42
  • @Mico: I'm not actually "using" papeeria.com at all. It was just the first free online LaTeX editor I found, that didn't require registration. Which one would you recommend? Btw, since your code works in the 2019 version, I retried it locally with a new document and now it works there too, but not when I paste it into my document. Maybe there's some conflict with a package I'm using? Not going to debug it, as I already have a working solution now, but I'll update my response. Aug 9, 2023 at 6:19
  • @seeplusn00b - Glad to learn that you're not actually a "user" of papeeria.com. For online free LaTeX compilation sites, I don't think you'd go wrong with Overleaf. Incidentally, I had to "register" with papeeria.com as well -- no different from Overleaf, really. My main advice to just about anyone, though, would be that as long as you have a computer that's less than about 5 or 6 years old, I'd try to install a full TeX distribution -- I'm indifferent between TeXLive and MikTeX -- on that computer.
    – Mico
    Aug 9, 2023 at 7:49

You must log in to answer this question.

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