16

Does anybody come up with a way to automatically arrange a few figures or boxes in a larger rectangle or page?

Here it is a real world example: One is producing a beamer presentation. One has 4 or 5 ready made figures, of different aspect ratios. And wants to distribute the figures regardless of any special order but want the slide to more or less fill up and the height or width of each figure to adjust "nicely" and not necessarily regular or rectangular.

The idea is to minimize the unused space and/or make the pictures align/resize nicely. But Doing this manually requires a lot of error and trial and keeping track of similar forced width or height of nearby images.

For example, Google Images and Google+ uses this technique to optimize the space taken by images and posts:

googleimages

Fake code (will display 5 things automatically arranged, sequential order may be lost):

\begin{frame}
\begin{arrangedfigure}[5] %five boxes/images
\includegraphics{fig1} &
\includegraphics{fig2} &
\includegraphics{fig3} &
\minipage{text} &
\includegraphics{fig4}
\end{arrangedfigure}
\end{frame}

Related questions, dealing with this but not in an automatic way:

Special arrangement of subfigures

What is the best way of arranging multiple minipages on a page?

How to arrange a figure consisting of four subfigures?

alfC
  • 14,350
  • 1
    This may be a helpful related solution, with LuaTeX used for a waterfilling problem with text. http://tex.stackexchange.com/questions/160811/reflow-text-blocks-in-a-page/167684#167684 – cslstr Mar 31 '14 at 19:26
  • @cslstr, definitely along the lines. I'll try to translate to my case. – alfC Mar 31 '14 at 19:39
  • Several showcase experiments have been introduced here: http://tex.stackexchange.com/questions/64340/create-a-yearbook-style-multi-page-layout-of-photos – Malipivo Apr 07 '14 at 08:49
  • Just a tip: I am using the shapepar package for text paragraph formatting, but I haven't tested it with graphics. It might be worth a try. – Malipivo Apr 07 '14 at 09:17
  • This is a simple example of pictures behaving like words: \documentclass[a4paper]{article} \usepackage{shapepar} \usepackage{mwe} \def\incl#1 {\includegraphics[height=2.5ex]{example-image-#1} }% or let's use \baselineskip \begin{document} \shapepar{\rectangleshape{1}{2}}\incl16x10 \incl16x9 \incl1x1 \incl4x3 \incl10x16 \incl9x16 \incl16x10 \incl16x9 \incl1x1 \incl4x3 \incl10x16 \incl9x16 \incl16x10 \incl16x9 \incl1x1 \incl4x3 \incl10x16 \incl9x16 \incl4x3 \incl10x16 \incl9x16 \incl4x3 \incl10x16 \incl9x16 \end{document} – Malipivo Apr 07 '14 at 11:00
  • It might help if you gave some guidance on constraints. For example, it's clear you want pictures shrunk if they are vertically too large, but do you want them grown if they are vertically "too small"? And if so, to the specified height, or only so that the image width cannot exceed some upper limit width constraint? You see my point. The more constraints you can tell us, the better it guides the solution. – Steven B. Segletes Apr 07 '14 at 17:18
  • @StevenB.Segletes, Suppose that there are no constrains, except that the blank (white, unused) are around the pictures or boxes is minimized, or approximately minimized. – alfC Apr 07 '14 at 17:20
  • OK, that makes it easy. The answer is to place one figure per page, scaled and stretched to fit the page size 8^). You have to have some guidance. Do the figures have to appear in a given order, or is rearrangement allowed (it makes it much more difficult, but would allow some optimization). Do I have to get a certain number of rows or figures on a page? – Steven B. Segletes Apr 07 '14 at 17:26
  • No constrains to begin with, no matter the order, no matter the number of rows columns. Yes, this is a hard optimization problem but any attempt (although no perfect optimization) is a step in the right direction. – alfC Apr 07 '14 at 17:29
  • Of course there are constraints, even if you have not mentioned them yet. For example, I don't think you would at all be interested in a solution where one image is grown to almost the full page size, and the others are shrunk to almost zero, even if that resulted in satisfying your optimization of minimizing "unused" space. So if I am right, there are, in fact, constraints in your head that you have not effectively voiced. – Steven B. Segletes Apr 07 '14 at 17:36
  • @StevenB.Segletes, touché! Yes, I think those enter into the vague "nicely" description I gave. My point is that you try to minimize both the blank space and minimize the disproportion between figures (preserving their aspect ratio), or minimize a balanced combination of both. – alfC Apr 07 '14 at 17:46

1 Answers1

11

I'm using the method developed in Making the text fit in a specific space in Latex to explore various aspects to this question. I am not rearranging any items, but am assuming that I have a string of N images that I am being asked to stuff into a certain size rectangle.

I am treating each image as text, and allowing line breaking to create the rows. So far, I've tried three version.

1) The raw version, relative figure sizes stay as given

2) make all figures same height

3) manually tweak the scaling, in an informal effort to avoid vast disparities in figure height and width, and to not leave last line largely un-full.

I have drawn a box around the image to help us gauge whether the boxes are overfull. REVISED to use \raggedright and \hfill to successfully avoid overrunning margins.

\documentclass{article}
\usepackage{scalerel}
\usepackage{fp}
\usepackage{xcolor}
\usepackage{fancyhdr}
\pagestyle{fancy}
\newcount\boxheight
\newcount\boxwidth
\newlength\constrainedwidth
\newsavebox\testbox
\newlength\currentwidth

\newcommand\aspect[1]{%
  \boxheight=\ht#1\relax%
  \boxwidth=\wd#1\relax%
  \FPdiv\testaspect{\the\boxheight}{\the\boxwidth}%
%\testaspect\\%                  COMMENT THIS LINE TO REMOVE ASPECT-RATIO PRINTS
}
% TARGET-HEIGHT, TARGET-WIDTH, CONTENT, GUESS>NATURAL-WIDTH, dWIDTH
\newcommand\constraintext[5]{%
  \def\svfboxsep{\the\fboxsep}%
  \setlength\fboxsep{0pt}%
  \setlength\constrainedwidth{#2}%
  \sbox\testbox{\rule{#2}{#1}}%
%TARGET ASPECT RATIO\\%          COMMENT THIS LINE TO REMOVE COMMENT
%V\\%                            COMMENT THIS LINE TO REMOVE COMMENT
  \aspect{\testbox}%
  \edef\aspectratio{\testaspect}%
  \constrainsize{#1}{\aspectratio}{#3}{#4}{#5}%
  \setlength\fboxsep{\svfboxsep}%
}
\newcommand\constrainsize[5]{%
  \sbox{\testbox}{\fbox{\begin{minipage}[b]{#4}{#3}\end{minipage}}}%
  \aspect{\testbox}%
  \FPiflt{\testaspect}{#2}%
    \setlength{\currentwidth}{#4}%
    \addtolength{\currentwidth}{-#5}%
    \constrainsize{#1}{#2}{#3}{\currentwidth}{#5}%
  \else
    \setlength\constrainedwidth{#1}%
    \FPdiv\result{1.0}{#2}%
%RESET ANY OTHER COUNTERS, TO AVOID ITERATION CREEP
   \setcounter{section}{0}%
   \setcounter{figure}{0}%
%                               CHANGE \framebox TO \makebox TO REMOVE FRAME
    \framebox[\result\constrainedwidth]{\hfill%
      \scaleto{\begin{minipage}[b]{\currentwidth}\raggedright #3\end{minipage}}{#1}%
      \hfill%
    }%
  \fi%
}

\newsavebox\Ab
\newsavebox\Bb
\newsavebox\Cb
\newsavebox\Db
\newsavebox\Eb
\newsavebox\Fb

\def\A{\usebox{\Ab}\hfill}
\def\B{\usebox{\Bb}\hfill}
\def\C{\usebox{\Cb}\hfill}
\def\D{\usebox{\Db}\hfill}
\def\E{\usebox{\Eb}\hfill}
\def\F{\usebox{\Fb}\hfill}

\def\AA{\textcolor{green}{\rule{3in}{2in}}}
\def\BB{\textcolor{red}{\rule{2in}{1in}}}
\def\CC{\textcolor{cyan!50}{\rule{1.75in}{2in}}}
\def\DD{\textcolor{blue!40}{\rule{1.5in}{2in}}}
\def\EE{\textcolor{blue}{\rule{2.25in}{2.25in}}}
\def\FF{\textcolor{red!20}{\rule{2.5in}{1.5in}}}

\def\testcase{%
  \centering\constraintext{.999\textheight}{.999\textwidth}{%
  \A\B\C\F\D\E%
  \B\C\A\E\D\F%
  \D\B\F\C\A\E%
  \E\F\D\C\A\B%
  \F\C\B\D\E\A%
  }{3\textheight}{1ex}%May have to increase next-to-last argument if divide by 0
  \clearpage
}
\begin{document}
\fancyhead[c]{Method 1: All images remain the same relative size}
\savebox{\Ab}{\AA}
\savebox{\Bb}{\BB}
\savebox{\Cb}{\CC}
\savebox{\Db}{\DD}
\savebox{\Eb}{\EE}
\savebox{\Fb}{\FF}
\testcase

\fancyhead[c]{Method 2: All images scaled to the same height}
\savebox{\Ab}{\AA}
\savebox{\Bb}{\scalerel*{\BB}{\AA}}
\savebox{\Cb}{\scalerel*{\CC}{\AA}}
\savebox{\Db}{\scalerel*{\DD}{\AA}}
\savebox{\Eb}{\scalerel*{\EE}{\AA}}
\savebox{\Fb}{\scalerel*{\FF}{\AA}}
\testcase

\fancyhead[c]{Method 3: Manually Scale images}
\savebox{\Ab}{\scalebox{.98}{\AA}}
\savebox{\Bb}{\scalebox{1.8}{\BB}}
\savebox{\Cb}{\scalebox{1.0}{\CC}}
\savebox{\Db}{\scalebox{1.0}{\DD}}
\savebox{\Eb}{\scalebox{.95}{\EE}}
\savebox{\Fb}{\scalebox{1.05}{\FF}}
\testcase
\end{document}

enter image description here

enter image description here

enter image description here


EDIT: To answer the OP's question about vertical centering of the figures, it can be done by defining the images as centered about the baseline. In the case of \includegraphics, it would require a \raisebox of minus 1/2 the image height. In the case of my MWE, the down shift of \rules can be obtained with the optional argument.

\def\AA{\textcolor{green}{\rule[-1in]{3in}{2in}}}
\def\BB{\textcolor{red}{\rule[-.5in]{2in}{1in}}}
\def\CC{\textcolor{cyan!50}{\rule[-1in]{1.75in}{2in}}}
\def\DD{\textcolor{blue!40}{\rule[-1in]{1.5in}{2in}}}
\def\EE{\textcolor{blue}{\rule[-1.125in]{2.25in}{2.25in}}}
\def\FF{\textcolor{red!20}{\rule[-.75in]{2.5in}{1.5in}}}
  • My thoughts: I think that the empty space in the right bottom corner is one of the key problems. I believe that horizontal (between figures) and vertical spaces (between rows) are fixed and therefore this problem is so unique in opposition to common output from the shapepar package, because we must manipulate with individual figures during or after the optimization. I was thinking about having the same area for all the figures and if a change in either direction (making some figure bigger or smaller) is needed then we would need to start penalizing it. – Malipivo Apr 07 '14 at 19:57
  • @Malipivo I thank you for your thoughts and I tend to agree with you. I will give the problem more thought. Perhaps treating the images as text is not the best way... – Steven B. Segletes Apr 07 '14 at 22:36
  • This looks pretty good, I didn't tried yet. In this figures as "text" based solution. Is is possible to center the figures vertically in each line? – alfC Apr 12 '14 at 01:48
  • @alfC Yes, in my MWE, if the \rules are all centered about their baseline (e.g,, via the optional argument \rule[-1in]{3in}{2in}). For real figures, you would need to import it in a manner such as \newsavebox\AAfig \setbox0=\hbox{\includegraphics[options]{filename}} \savebox{\AAfig}{\raisebox{-.5\ht0}{\box0}} \def\AA{\textcolor{green}{\usebox{\AAfig}}}. One strange thing, however. When I shifted the \rules halfway down as I describe, it still works, but affected the horizontal justification, for reasons I can't understand. – Steven B. Segletes Apr 12 '14 at 02:57
  • @StevenB.Segletes, If I try to use this with beamer I get ! Arithmetic overflow. \calc@next@digit ... \multiply \calc@numerator 10 \calc@Acount \calc@numerat.... I will award the bounty at the moment, since this is the closest to an answer. – alfC Apr 13 '14 at 23:38
  • @alfC First, for beamer, I would eliminate the use of fancy headers and the fancy package. But, to get the method to compile, you will note near the end of the macro \testcase the following comment: ``%May have to increase next-to-last argument if divide by 0. If you change the next to last argument from3\textheightto, for example,10\textheight`, my example will compile. If you follow to my linked answer at http://tex.stackexchange.com/questions/123614/making-the-text-fit-in-a-specific-space-in-latex/123650#123650, you will learn more about that argument being a 1st guess. – Steven B. Segletes Apr 13 '14 at 23:54
  • @alfC Also, you may wish to use less that .999\textheight and .999\textwidth as the first two arguments to \testcase, unless you want it to fill the whole page. – Steven B. Segletes Apr 14 '14 at 00:01