4

I need to generate a lot of reports and have written a program in R that writes LaTeX files. Most of these come out OK, but there is one quirk that affects the placement of 3 items in a multicolumn structure inside a minipage. I've pared down the report code to show this.

Here is example output. In the top left, notice that the multicolumn placed two items on the right. I don't want that to happen, I want 2 on left. In almost all of the other examples that have 3 items, it ends up with 2 on the left and 1 on the right. I fiddled the string in item 2 to cause the desired result in boxes on bottom and right.

multicolumn_placement

It is not entirely predictable how to cause the good result to happen. If that second item's text string is just a little bit longer, or quite a bit shorter, then the column placement comes out the way I want.

Since I'm generating 1000s of reports, it is not practical to sift through them and find these unexpected 3-item boxes and fix them. Hence, I hope you'll help me understand what causes this.

Maybe my document design is just too intricate. It is a section with 2 columns, in each column there are minipages in each of which there are 2 columns. These stylized bars with comments are a required element in the report. Sometimes the sentences are longer, sometimes shorter. Sometimes there will be 15 or 20 items with sentences of varying lengths. The design here seems to work dependably on the bigger, complicated cases, but this one with 3 items is, well, frustrating.

Here's the MRE. I have cut out headers, footers, lots of other boxes. Then I copied the trouble box to show different cases. I am leaving preamble because, if I have put a wrong thing there that causes this problem, I need you to spot it, tell me what to fix.

\documentclass[letterpaper,landscape,english,11pt]{article}
\usepackage[scaled=.92]{helvet}
\renewcommand{\familydefault}{\sfdefault}
\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc}
\usepackage{array}
\usepackage{longtable}
\usepackage{multicol}
\usepackage{setspace}
\setlength{\parskip}{0bp}
\setlength{\parindent}{0bp}
\makeatletter
\setlength{\columnsep}{1.5cm}

\DeclareUnicodeCharacter{00A0}{}
\providecommand{\tabularnewline}{\\}

\makeatother

\usepackage{calc}
\usepackage{setspace}
%% compiler says not needed now: \usepackage{fixltx2e}
\usepackage{graphicx}
\usepackage{grffile}
\usepackage{multicol}
\usepackage{multirow}
\usepackage[normalem]{ulem}
\usepackage[english]{babel}
\usepackage{color}
\usepackage{colortbl}
\usepackage[landscape,letterpaper,includehead,includefoot]{geometry}
\geometry{verbose,tmargin=1.5cm,bmargin=0.75cm,lmargin=2cm,rmargin=2cm}
\usepackage{fancyhdr}
\headheight=5pt 
\footskip=20pt
\marginparwidth=0pt
\marginparsep=0pt
\setlength{\parskip}{\smallskipamount}
\setlength{\parindent}{0pt}
\usepackage{adjustbox}

\pagestyle{fancy}
\usepackage{lastpage}
\usepackage[percent]{overpic}
\usepackage{moresize}
\usepackage{url}

\def\changemargin#1#2{\list{}{\rightmargin#2\leftmargin#1}\item[]}
\let\endchangemargin=\endlist

\begin{document}

\fancyhead{}
\fancyfoot{} 

\fancypagestyle{empty}{
  \fancyhf{}
  \fancyfoot[R]{Page  \thepage \hspace{1pt} of \pageref{LastPage}} 
  \renewcommand{\headrulewidth}{0pt}
  \renewcommand{\footrulewidth}{0pt}
}

\thispagestyle{empty}
%% Space between big boxes specified next
\setlength\columnsep{20pt}
\begin{multicols}{2}

\fbox{\begin{minipage}{\columnwidth}
\raggedcolumns
%% Space between columns within box
\setlength\columnsep{10pt}
\begin{multicols}{2}
\begin{spacing}{0.7}
\begin{minipage}{\columnwidth}
\vspace{1pt}
{\footnotesize{}Construct understandings of text} \\
\begin{overpic}[height=0.45cm]{pp-11}\put(5,-0.5){\textit{\ssmall{}Mastered 13 of 45 skills}}\end{overpic}
\rule[0.5ex]{.75\columnwidth}{1pt}
\end{minipage}

\begin{minipage}{\columnwidth}
\vspace{1pt}
{\footnotesize{}Integrate ideas and information from text} \\
\begin{overpic}[height=0.45cm]{pp-11}\put(5,-0.5){\textit{\ssmall{}Mastered 6 of 15 skills}}\end{overpic}
\rule[0.5ex]{.75\columnwidth}{1pt}
\end{minipage}

\begin{minipage}{\columnwidth}
\vspace{1pt}
{\footnotesize{}Use writing to communicate} \\
\begin{overpic}[height=0.45cm]{pp-11}\put(5,-0.5){\textit{\ssmall{}Mastered 15 of 25 skills}}\end{overpic}
\rule[0.5ex]{.75\columnwidth}{1pt}
\end{minipage}
\end{spacing}
\end{multicols}
\vspace{5pt}
\end{minipage}}

\vspace{10pt}
\fbox{\begin{minipage}{1\columnwidth}
\raggedcolumns
\setlength\columnsep{10pt}
\begin{multicols}{2}
\raggedcolumns
\begin{spacing}{0.7}
\begin{minipage}{\columnwidth}
\vspace{1pt}
{\footnotesize{}Construct understandings of text} \\
\begin{overpic}[height=0.45cm]{pp-11}\put(5,-0.5){\textit{\ssmall{}Mastered 13 of 45 skills}}\end{overpic}
\rule[0.5ex]{.75\columnwidth}{1pt}
\end{minipage}

\begin{minipage}{\columnwidth}
\vspace{1pt}
{\footnotesize{}Integrate ideas and whatnot} \\
\begin{overpic}[height=0.45cm]{pp-11}\put(5,-0.5){\textit{\ssmall{}Mastered 6 of 15 skills}}\end{overpic}
\rule[0.5ex]{.75\columnwidth}{1pt}
\end{minipage}

\begin{minipage}{\columnwidth}
\vspace{1pt}
{\footnotesize{}Use writing to communicate} \\
\begin{overpic}[height=0.45cm]{pp-11}\put(5,-0.5){\textit{\ssmall{}Mastered 15 of 25 skills}}\end{overpic}
\rule[0.5ex]{.75\columnwidth}{1pt}
\end{minipage}
\end{spacing}
\end{multicols}
\vspace{5pt}
\end{minipage}}

\columnbreak

\vspace{10pt}
\fbox{\begin{minipage}{1\columnwidth}
\raggedcolumns
\setlength\columnsep{10pt}
\begin{multicols}{2}
\begin{spacing}{0.7}
\begin{minipage}{\columnwidth}
\vspace{1pt}
{\footnotesize{}Construct understandings of text} \\
\rule{0pt}{.45cm}\begin{overpic}[height=0.45cm]{pp-11}\put(5,-0.5){\textit{\ssmall{}Mastered 13 of 45 skills}}\end{overpic}
\rule[0.5ex]{.75\columnwidth}{1pt}
\end{minipage}

\begin{minipage}{\columnwidth}
\vspace{1pt}
{\footnotesize{}Integrate ideas and information \\ from text}\\
\begin{overpic}[height=0.45cm]{pp-11}\put(5,-0.5){\textit{\ssmall{}Mastered 6 of 15 skills}}\end{overpic}
\rule[0.5ex]{.75\columnwidth}{1pt}
\end{minipage}

\begin{minipage}{\columnwidth}
\vspace{1pt}
{\footnotesize{}Use writing to communicate} \\
\begin{overpic}[height=0.45cm]{pp-11}\put(5,-0.5){\textit{\ssmall{}Mastered 15 of 25 skills}}\end{overpic}
\rule[0.5ex]{.75\columnwidth}{1pt}
\end{minipage}
\end{spacing}
\end{multicols}
\vspace{5pt}
\end{minipage}}
\end{multicols}
\end{document}

I cannot get the forum to allow the tiny pdf that is used in the overpics to be attached. I dropped a copy on my webpage, but I understand you don't want to go fishing: http://pj.freefaculty.org/scraps/pp-11.pdf

Thanks in advance for your insights

0
7

Here is the explanation for the behavior of the algorithm. Basically you are asking multicols to balance not single lines of text but big blocks (minipages) consisting of several lines which of course is rather hard to do. In your examples you have only 3 blocks so putting them onto two columns basically means one column gets 2 of them and one gets the other.

Now to balance, multicol makes a guess (which is deliberately too small) for the height of the columns and then tries to place everything. So first time around the first block ends up in column 1 and the other 2 go into column 2 (and overflow that column) -> failure.

Then multicol increases the column height (by one 1pt) and retries. Same result and so the column height slowly grows. But the only thing that happens is that the first column will be really underfull (as there still is only the one block inside).

However, at some point the height gets so large that the two blocks in the second column finally fit into the second column and that is what multicol then takes as the balance solution.

You can observe that behavior quite nicely by using the option balancingshow when loading the package. Then you get the following tracing:

Package multicol: Balance columns on input line 98: 


Column 1 badness: 10000  
First column = 38.20001pt (26.57309pt) <> last column = 59.4557pt
Rejected: last column too large!
Retry: using natural height of first column!

Column 1 badness: 0  
First column = 26.57309pt (26.57309pt) <> last column = 59.4557pt
Rejected: last column too large!

Column 1 badness: 12  
First column = 27.57309pt (26.57309pt) <> last column = 59.4557pt
Rejected: last column too large!

Column 1 badness: 100  
First column = 28.57309pt (26.57309pt) <> last column = 59.4557pt
Rejected: last column too large!

Column 1 badness: 336  
First column = 29.57309pt (26.57309pt) <> last column = 59.4557pt
Rejected: last column too large!

Column 1 badness: 800  
First column = 30.57309pt (26.57309pt) <> last column = 59.4557pt
Rejected: last column too large!

Column 1 badness: 1558  
First column = 31.57309pt (26.57309pt) <> last column = 59.4557pt
Rejected: last column too large!

Column 1 badness: 2698  
First column = 32.57309pt (26.57309pt) <> last column = 59.4557pt
Rejected: last column too large!

Column 1 badness: 4279  
First column = 33.57309pt (26.57309pt) <> last column = 59.4557pt
Rejected: last column too large!

Column 1 badness: 6396  
First column = 34.57309pt (26.57309pt) <> last column = 59.4557pt
Rejected: last column too large!

Column 1 badness: 10000  
First column = 35.57309pt (26.57309pt) <> last column = 59.4557pt
Rejected: last column too large!

Column 1 badness: 10000  
First column = 36.57309pt (26.57309pt) <> last column = 59.4557pt
Rejected: last column too large!

and many more tries like this ... and then finally ...

Column 1 badness: 10000  
First column = 58.57309pt (26.57309pt) <> last column = 59.4557pt
Rejected: last column too large!

Column 1 badness: 10000  
First column = 59.57309pt (26.57309pt) <> last column = 59.4557pt
Final badness: 0

Package multicol: Column spec: 330.57948pt = indent + columns + sep =
(multicol)        0.0pt + 2 x 160.28973pt + 1 x 10.0pt on input line 98.


Package multicol: Ending environment  (boxed mode) on input line 98.

which shows exactly the behavior explained above.

In the second example, the blocks have slightly different heights, so in that case multicol reaches a point where the first two blocks fit into the first column and that happens before the last two blocks fit into the second column. Thus in that case, one gets the desired outcome.

Getting a better result

multicol actually has a bunch of nobs to turn and improve the results, but they need to turned based on the type of input, unfortunately. The one to turn here is the counter columnbadness that controls how bad columns are allowed to get. The default is 10000 and that means badly underfull columns are ok in an emergency (only overfull ones are disallowed).

With the setup like this a better choice is something like

   \setcounter{columnbadness}{9999}

so that all attempts with badness 10000 are getting chucked out and that means multicol will continue to raise the height until the first column is no longer underfull.

(As an aside: the unbalance counter only helps here because that way the starting point is increased enough so that the two blocks fit already into the first column (but that is only true for that particular example. In other cases it might need a different unbalance setting so that is only good for manaual adjustment))

1
  • Thanks, sincerely. This truly helps me understand what is happening. – pauljohn32 Mar 22 '17 at 14:46
3

I cannot explain the behavior of multicolumns, but you might try setting the unbalance parameter to a value higher than zero.

\setcounter{unbalance}{2}

Apart from that, your code can be improved in several respects. It generates several underfull and overfull hboxes, several packages are loaded twice, and you shouldn't repeat the code, even if it is generated. To adjust the white space of the frame, you can set \fboxsep to some bigger value. Finally, you can easily generated the pictures instead of loading them, with tikz or pstricks (I haven't done this yet, without knowing the rationale behind loading the picture).

\documentclass[letterpaper,landscape,english,11pt]{article}
\usepackage[scaled=.92]{helvet}
\renewcommand{\familydefault}{\sfdefault}
\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc}
\usepackage{multicol}
\usepackage{setspace}
\usepackage[landscape,letterpaper,includehead,includefoot]{geometry}
\geometry{verbose,tmargin=1.5cm,bmargin=0.75cm,lmargin=2cm,rmargin=2cm}
\headheight=5pt 
\footskip=20pt
\marginparwidth=0pt
\marginparsep=0pt
\setlength{\parskip}{\smallskipamount}
\setlength{\parindent}{0pt}
\usepackage{moresize}
\usepackage{environ}
\usepackage{graphicx}
\NewEnviron{person}%
  {\par
   \vspace{10pt}%
   \fbox
    {\begin{minipage}{\dimexpr\columnwidth-2\fboxsep-2\fboxrule}%
       \setlength\columnsep{10pt}%
       \setcounter{unbalance}{2}%
       \begin{multicols}{2}%
         \raggedcolumns
         \begin{spacing}{0.7}%
         \BODY
         \end{spacing}%
       \end{multicols}
     \end{minipage}%     
    }%
  }
\newcommand\ability[4]%
  {\begin{minipage}{\columnwidth}%
    {\footnotesize#1\par}%
    \makebox[4pt][l]{\includegraphics[height=0.45cm]{#2}}%
    {\ssmall\itshape Mastered #3 of #4 skills}%
    \par
    \rule[1ex]{0.75\columnwidth}{1pt}%
    \end{minipage}%
  }
\begin{document}
\setlength\columnsep{20pt}
\begin{multicols}{2}
\begin{person}
\ability{Construct understandings of text}{pp-11}{13}{45}
\ability{Integrate ideas and information from text}{pp-11}{6}{15}
\ability{Use writing to communicate}{pp-11}{15}{25}
\end{person}
\begin{person}
\ability{Construct understandings of text}{pp-11}{13}{45}
\ability{Integrate ideas and whatnot}{pp-11}{6}{15}
\ability{Use writing to communicate}{pp-11}{15}{25}
\end{person}
\columnbreak
\begin{person}
\ability{Construct understandings of text}{pp-11}{13}{45}
\ability{Integrate ideas and information \\ from text}{pp-11}{6}{15}
\ability{Use writing to communicate}{pp-11}{15}{25}
\end{person}
\end{multicols}
\end{document}

enter image description here

1
  • Thanks. I don't know if this is the "right answer", so I'm marking it +1 and lets wait and see if there are counter arguments. I'll test unbalance on the actual document. I will see about your other efficiency advice. Because the sentences to be used change with every document, I got idea the underfull/overfull boxes were unavoidable. About the images, we've time tested generating the images within the LaTeX code and it takes much (much) longer with tikz than to generate 100 pdf images, one for each possible bar length, and then put them to use when needed. – pauljohn32 Mar 13 '17 at 3:03

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.