4

I am trying to typeset a nested table, like this:

\documentclass{article}
\usepackage{bigstrut}
\usepackage{multirow}

\begin{document}

\begin{tabular}{|lll|}
  \hline
   A & \multirow{2}{*}{
      \begin{minipage}{3cm}
        \begin{tabular}{|l|l|}
          \hline
          A & \hfill 1\textsuperscript{st}\bigstrut[t] \\
          \hline
          A & A \\
          \hline
        \end{tabular}
      \end{minipage}
        } &  A \\
   A & {} & A \\
   A & A  & A \\
  \hline
\end{tabular}

\end{document}

This causes a bad box: Overfull \vbox (3.19998pt too high) detected at line 19

I have been trying for a while to detect the precise source of this bad box (it's caused partly by the \bigstrut), but I do not know how to remove this warning. I tried various fixes of the sort \\[3.5pt], but I am not sure what's going wrong and how to address the issue. It might be the case that typesetting the table in an entirely different way turns out to be the "best" way, but for now I am interested in the source of the bad box and how to get rid of it.

Note: In this minimized example, the bottom middle A overlaps with the nested table, but even if I do something like \\[1cm] for the second-to-last line, the bad (overfull) \vbox message persists (with incidentally the same point size indication).


EDIT

Here's is an alternate MWE which creates a similar overfull error without having to read through a nested tabular environment:

\documentclass{article}
\usepackage{xcolor}
\usepackage{multirow}
\setlength{\parindent}{0pt}
\newcommand{\vstrut}[3][blue]{{\color{#1}\rule[-#2]{0.4pt}{#3}}}
\newcommand{\hstrut}[2][blue]{{\color{#1}\makebox[0pt][l]{\rule[-0.4pt]{#2}{0.4pt}}}}
\begin{document}

\begin{tabular}{|lll|}
  \hline
   A\vstrut{0ex}{5ex} & \multirow{2}{3cm}{%
      \begin{minipage}[t]{3cm}
            Trial \vstrut[red]{18pt}{18pt}  text
      \end{minipage}} 
                                          & A \\
   A\vstrut{3ex}{3ex}\hstrut{1.65in} & {} & A \\
   A                                 & A  & A \\
  \hline
\end{tabular}

\end{document}
6
  • I don't get any bad boxes. Are you using a different class/page size?
    – percusse
    Feb 24, 2013 at 2:21
  • @percuße I compile it with pdflatex (pdfTeX, Version 3.1415926-2.4-1.40.13) and get 0 errors, 0 warnings, and 1 bad box. My default is letter (not A4) where I am right now, but I'd be surprised if that mattered. Feb 24, 2013 at 2:23
  • 1
    It seems that the height of the \multirow is not correctly determined. Test this out by using the package lipsum and then replace the contents of the minipage environment with just \lipsum[1]
    – A.Ellett
    Feb 24, 2013 at 3:04
  • @tohecz You've added the tag "warnings"; I'm not disagreeing, but technically I'm getting "Warnings: 0" (!) and "Bax Boxes: 1". Just noting this for those good at editing tags, in case it matters. Feb 24, 2013 at 12:08
  • @LoverofStructure That's what your IDE says to you I think; it's true that bad boxes aren't shown as Warning:, still they belong to that category I think ;)
    – yo'
    Feb 24, 2013 at 13:43

2 Answers 2

6

TeX is right: the overfull box (3.2pt too high) should be there: the embedded table you are trying to fit in the height of two outer table rows is just too high. What made it too high? First, you have used the \bigstrut[t] in the embedded table. This has made it 2pt higher. Second, you have used three \hlines, each being \arrayrulewidth=0.4pt high: this accounts for the remaining 1.2pt.

A test: The inner table fits perfectly if the bigstrut[t] and \hlines are removed:

no bigstrut or hline

\documentclass{article}
\usepackage{bigstrut}
\usepackage{multirow}
\begin{document}
\begin{tabular}{|lll|}
  \hline
   A & \multirow{2}{*}{
        \begin{tabular}{|l|l|}%|
          %\hline
          A & \hfill 1\textsuperscript{st}%
          %\bigstrut[t]
          \\
          %\hline
          A & A \\
          %\hline
        \end{tabular}
        } &  A\\
   A & {} & A\\
   A & A  & A \\
  \hline
\end{tabular}
\end{document}

There is only one way of dealing with this: creating more space in the outer table. Given that you would probably like the rows of the inner and outer table to be aligned, I suggest parallelism. Whenever you use a \bigstrut in the inner table, use it in the outer table as well, in the same row.

There's a catch however. Whenever you make a row of the outer table higher than normal, you need to tell multirow about it in order to not get an overfull box. To do this, multirow provides the optional argument bigstruts that increases the height of the multirow cell for bigstruts * \bigstrutjot. Thus (I've cleaned up the MWE a bit), an example with (only) \bigstrut in the inner table, and consequently a \bigstrut in the outer table plus the optional argument [1].

bigstrut, no hlines

\documentclass{article}
\usepackage{bigstrut}
\usepackage{multirow}
\usepackage{xcolor}
\begin{document}
\begin{tabular}{|lll|}
  \hline
   A & \multirow{2}[1]{*}{\color{red}%
        \begin{tabular}{|l|l|}%|
          A & A\bigstrut[t] \\
          A & A\\
        \end{tabular}} &  A\bigstrut[t]  \\
   A & {} & A \\
   A & A  & A \\
  \hline
\end{tabular}
\end{document}

Next, \hline in the embedded table. First, parallelism: we have to get extra vertical space into the outer table as well. I propose using a strut of appropriate depth.

\def\hlinestrut{\rule[\dimexpr-\dp\strutbox-\arrayrulewidth]{\dimexpr\dp\strutbox+\arrayrulewidth}{0pt}}

However, this is not enough: again, we also have to tell multirow that the rows are higher than normal. However, we are faced with a problem. The only way to increase the height of the multirow cell is by the optional argument bigstruts, which takes only integer values, but the height of a \hline is not an integer multiple of \bigstrutjot. By default, \arrayrulewidth is one fifth of \bigstrutjot. I see no other way but patch multirow to accept floats for the bigstruts argument. Furtunately, this is quite easy, all we have to change is this:

%\ifnum#2>0 \advance\@tempdima\bigstrutjot \fi
\ifdim#2pt>0pt \advance\@tempdima\bigstrutjot \fi

The full example now:

bigstrut and one hline

\documentclass{article}
\usepackage{bigstrut}
\usepackage{multirow}
\usepackage{xcolor}
\def\hlinestrut{\rule[\dimexpr-\dp\strutbox-\arrayrulewidth]{\dimexpr\dp\strutbox+\arrayrulewidth}{0pt}}
\makeatletter
\def\@xmultirow#1[#2]#3[#4]#5{\@tempcnta=#1%
  \@tempdima\@tempcnta\ht\@arstrutbox
  \advance\@tempdima\@tempcnta\dp\@arstrutbox
  \ifnum\@tempcnta<0\@tempdima=-\@tempdima\fi
  \advance\@tempdima#2\bigstrutjot
  \if*#3\setbox0\vtop to \@tempdima{\vfill\multirowsetup
    \hbox{\strut#5\strut}\vfill}%
  \else
      \setbox0\vtop to \@tempdima{\hsize#3\@parboxrestore
                \vfill \multirowsetup \strut#5\strut\par\vfill}%
  \fi
  \ht0\z@\dp0\z@
  \ifnum\@tempcnta<0\advance\@tempdima-\dp\@arstrutbox
  \else\@tempdima\ht\@arstrutbox
     %\ifnum#2>0 \advance\@tempdima\bigstrutjot \fi
     \ifdim#2pt>0pt \advance\@tempdima\bigstrutjot \fi
  \fi
  \advance\@tempdima#4\relax\leavevmode\vtop{\vskip-\@tempdima\box0\vss}}
\@ifundefined{bigstrutjot}{\newdimen\bigstrutjot \bigstrutjot\jot}{}
\makeatother
\begin{document}
\begin{tabular}{|lll|}
  \hline
   A & \multirow{2}[1.2]{*}{\color{red}%
        \begin{tabular}{|l|l|}%|
          A & A\bigstrut[t] \\
          \hline
          A & A\\
        \end{tabular}} &  A\bigstrut[t]\hlinestrut  \\
   A & {} & A \\
   A & A  & A \\
  \hline
\end{tabular}
\end{document}

To go fully back to the original example (with three \hlines), one final complication: the top \hlines of the two tables should overlap. First, we increase bigstruts to 1.6 (one \bigstrut and three \hlines). Second: the inner \hline is a part of the outer cell! So, if we do nothing, the inner table will be pushed 0.4pt down. (And this will be too close to the cell in the third row.) The solution is to use \multirow's fixup optional parameter, which shifts the cell. (Omitting this optional parameter [\arrayrulewidth] means that the inside table is not shifted to have their top lines overlap.)

bigstrut and three hlines

\documentclass{article}
\usepackage{bigstrut}
\usepackage{multirow}
\usepackage{xcolor}
\def\hlinestrut{\rule[\dimexpr-\dp\strutbox-\arrayrulewidth]{\dimexpr\dp\strutbox+\arrayrulewidth}{0pt}}
\makeatletter
\def\@xmultirow#1[#2]#3[#4]#5{\@tempcnta=#1%
  \@tempdima\@tempcnta\ht\@arstrutbox
  \advance\@tempdima\@tempcnta\dp\@arstrutbox
  \ifnum\@tempcnta<0\@tempdima=-\@tempdima\fi
  \advance\@tempdima#2\bigstrutjot
  \if*#3\setbox0\vtop to \@tempdima{\vfill\multirowsetup
    \hbox{\strut#5\strut}\vfill}%
  \else
      \setbox0\vtop to \@tempdima{\hsize#3\@parboxrestore
                \vfill \multirowsetup \strut#5\strut\par\vfill}%
  \fi
  \ht0\z@\dp0\z@
  \ifnum\@tempcnta<0\advance\@tempdima-\dp\@arstrutbox
  \else\@tempdima\ht\@arstrutbox
     %\ifnum#2>0 \advance\@tempdima\bigstrutjot \fi
     \ifdim#2pt>0pt \advance\@tempdima\bigstrutjot \fi
  \fi
  \advance\@tempdima#4\relax\leavevmode\vtop{\vskip-\@tempdima\box0\vss}}
\@ifundefined{bigstrutjot}{\newdimen\bigstrutjot \bigstrutjot\jot}{}
\makeatother
\begin{document}
\begin{tabular}{|lll|}
  \hline
   A & \multirow{2}[1.6]{*}[\arrayrulewidth]{\color{red}%
        \begin{tabular}{|l|l|}%|
          \hline
          A & A\bigstrut[t] \\
          \hline
          A & A\\
          \hline
        \end{tabular}} &  A\bigstrut[t]\hlinestrut  \\
   A & {} & A \\
   A & A  & A \\
  \hline
\end{tabular}
\end{document}

Another complication arises when you use (parallel) \bigstruts but not in the first row. The thing is, \multirow automatically shifts the table for \bigstrutjot whenever the bigstruts argument is positive. However, this only makes sense if the \bigstrut occurs in the first row (I believe this is due to the fact that multirow uses \vtop top construct the cell content). So, in the situation described above, one must "unshift" the table using fixup, like so:

\begin{tabular}{|lll|}
  \hline
   A & \multirow{2}[1.6]{*}[\dimexpr\arrayrulewidth-\bigstrutjot]{\color{red}%
        \begin{tabular}{|l|l|}%|
          \hline
          A & A \\
          \hline
          A & A\bigstrut[t]\\
          \hline
        \end{tabular}} &  A\hlinestrut  \\
   A & {} & A\bigstrut[t] \\
   A & A  & A \\
  \hline
\end{tabular}
3
  • Is there a way of getting a result that is exactly like your last piece of code, except (1) with the inner table not shifted (i.e. without [\arrayrulewidth]) and (2) with the top two lines perfectly aligned? Feb 24, 2013 at 13:24
  • 1
    No, I don't think so (unless you shift manually within the cell's content, of course): as I said above, the whole inner table, including the rules, is part of the outer cell's content and as such appears under the top rule. Feb 24, 2013 at 14:00
  • To others: Please also see the very good answer by user A.Ellett. Mar 4, 2013 at 0:32
3

Notice that the same error is reproduced using the following text:

\documentclass{article}
\usepackage{xcolor}
\usepackage{multirow}
\setlength{\parindent}{0pt}
\newcommand{\vstrut}[3][blue]{{\color{#1}\rule[-#2]{0.4pt}{#3}}}
\newcommand{\hstrut}[2][blue]{{\color{#1}\makebox[0pt][l]{\rule[-0.4pt]{#2}{0.4pt}}}}
\begin{document}

\begin{tabular}{|lll|}
  \hline
   A\vstrut{0ex}{5ex} & \multirow{2}{3cm}{%
      \begin{minipage}[t]{3cm}
            Trial \vstrut[red]{18pt}{18pt}  text
      \end{minipage}} 
                                          & A \\
   A\vstrut{3ex}{3ex}\hstrut{1.65in} & {} & A \\
   A                                 & A  & A \\
  \hline
\end{tabular}

\end{document}

\multirow creates a \vtop box whose height and depth are set according to the rules for \vtop and the height and depth of \@arstrutbox. Now, \@arstrutbox is a box set up when a tabular environment is create. It is set to be a box whose height and depth are \arraystretch times the height and depth of a normal strut.

By playing with the visible struts in the above example, you can see the effects of how \multirow creates the box for its content. For example, even though you can place a strut to extend the size of the second row, this does not prevent an overfull box error when the strut inside the \multirow command force the contents of the box created by \multirow to be too big.

So, one solution would be to reset the value of \arraystretch. But that seems a bit of overkill: you probably don't want to change the \arraystretch of the whole table to fix just one box.

Keeping in mind how \multirow creates its box means a couple of things. Consider this next example where I tell \multirow that I only need one row.

\begin{tabular}{|lll|}
  \hline
   A\vstrut{0ex}{5ex} & \multirow{1}{3cm}{%
      \begin{minipage}[t][0pt]{3cm}
            Trial \vstrut[red]{18pt}{18pt}  text
      \end{minipage}} 
                                          & A \\
   A\vstrut{3ex}{3ex}\hstrut{1.65in} & {} & A \\
   A                                 & A  & A \\
  \hline
\end{tabular}

You can completely forgo using \multirow by creating a top aligning minipage of zero height.

\begin{tabular}{|lll|}
  \hline
   A\vstrut{0ex}{5ex} &% 
      {\begin{minipage}[t][0pt]{3cm}
            Trial \vstrut[red]{18pt}{18pt}  text
      \end{minipage}} 
                                          & A \\
   A\vstrut{3ex}{3ex}\hstrut{1.65in} & {} & A \\
   A                                 & A  & A \\
  \hline
\end{tabular}

Avoiding \multirow, you can still achieve something more like your original example, you can write:

\begin{tabular}{|lll|}
  \hline
   A &% 
      {\begin{minipage}[t][0pt]{3cm}
          \begin{tabular}{|l|l|}
            \hline
            A & \hfill 1\textsuperscript{st} \\
            \hline
            A & A \\
            \hline
          \end{tabular}
      \end{minipage}} 
          & A \\
   A & {} & A \\
   A & A  & A \\
  \hline
\end{tabular}

It seems the benefits of using \multirow is the ability to center its content with respect to the other rows it's supposed to straddle (see edit toward the end of this answer). So, here's an example that comes closer to what you want. (I've added a \hrule to better show the misalignment of the horizontal lines.)

\begin{tabular}{|lll|}
  \hline
   A &% 
      \multirow{2}{*}%
      {\begin{minipage}[c][0pt]{3cm}%
          \begin{tabular}[c]{|l|l|}
            \hline
            A & \hfill 1\textsuperscript{st} \\
            \hline
            A & A \\
            \hline
          \end{tabular}%
      \end{minipage}} 
          & A \\\hline
   A & {} & A \\
   A & A  & A \\
  \hline
\end{tabular}

Remember that tabular environments, much like minipages, can be centered with respect to the line they fall on.

To get the horizontal lines to align properly, add a vertical strut inside the minipage as follows (in this example, I use \raisebox to create a box of zero total height+depth):

\begin{tabular}{|lll|}
  \hline
   A &% 
      \multirow{2}{*}%
      {\raisebox{0pt}[0pt][0pt]{\begin{minipage}{3cm}\vspace{0.5pt}%
          \begin{tabular}[c]{|l|l|}
            %\hline % commented-out from original code b/c it slightly struts out at the top
            A & \hfill 1\textsuperscript{st} \\
            \hline
            A & A \\
            \hline
          \end{tabular}%
      \end{minipage}}} 
          & A \\\hline
   A & {} & A \\
   A & A  & A \\
  \hline
\end{tabular}

enter image description here

One additional point, you've got some whitespace creeping into your document at the end of the lines. This is causing widths to not quite be what you're defining them to be. I've eliminated a number of the more egregious occurrences.

EDIT

As @SašoŽivanović has pointed out, \multirow doesn't center its content. But what I'm talking about regarding centering is that \multirow will essentially center the contents of a box whose total height and depth is zero. This is because the contents of the \vtop used in the definition of \multirow are bracketted between \vfills resulting in content that is centered with respect to the expected height generated by the rows to be spanned.

Whitespace

In your original post you called

A & \multirow{2}{*}{
  \begin{minipage}{3cm}
    \begin{tabular}{|l|l|}
      \hline
      A & \hfill 1\textsuperscript{st}\bigstrut[t] \\
      \hline
      A & A \\
      \hline
    \end{tabular}
  \end{minipage}
    }

This is adding extra space at the line beginning \multirow... and it's adding extra space at the end when you write \end{minipage}. Look at my examples where I avoid this through placing % or closing arguments earlier than you do.

For more details on this, I suggest reading @egreg's answers posted to When is it harmful to add percent character at end of lines in a \newcommand, or similar

8
  • I beg to disagree on the statement that "multirow doesn't correctly adjust the box height". First, multirow doesn't adjust the row heights at all (if that was what you meant). Second, the strut's depth of 18pt in the alternative MWE is simply too large: the correct depth to reach the bottom of the second row would be 2\dp\strutbox+\ht\strutbox, which is 15.6pt. The difference is precisely 2.4pt reported by the overfull box warning. Another issue: it is clear from the code of \multirow that it doesn't center the content, but rather top-aligns it using \vtop. Feb 24, 2013 at 4:57
  • @SašoŽivanović I chose 18pt because the strut is still well within the second row and yet there's an overfull box error.
    – A.Ellett
    Feb 24, 2013 at 5:02
  • @SašoŽivanović Saying "adjust" was probably not a wish choice of words.
    – A.Ellett
    Feb 24, 2013 at 5:07
  • 1
    Yes but if you make the strut 15.6pt deep the overfull box is gone! Feb 24, 2013 at 5:11
  • Yes, that's exactly what I was getting at!
    – A.Ellett
    Feb 24, 2013 at 5:12

You must log in to answer this question.

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