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?

11
  • 1
    This may be a helpful related solution, with LuaTeX used for a waterfilling problem with text. tex.stackexchange.com/questions/160811/…
    – cslstr
    Mar 31, 2014 at 19:26
  • @cslstr, definitely along the lines. I'll try to translate to my case.
    – alfC
    Mar 31, 2014 at 19:39
  • Several showcase experiments have been introduced here: tex.stackexchange.com/questions/64340/…
    – Malipivo
    Apr 7, 2014 at 8: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 7, 2014 at 9: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 7, 2014 at 11:00

1 Answer 1

11
+250

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}}}
7
  • 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 7, 2014 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... Apr 7, 2014 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, 2014 at 1: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. Apr 12, 2014 at 2: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, 2014 at 23:38

You must log in to answer this question.

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