Consider the following scenario: By changing one or more parameters in an experimental method, we produce a series of figures. We then want to include these figures in a research report, manuscript, or thesis. It is often possible to reduce the amount of code/typing through automation of subfigure generation. More specifically, one sub-figure environment is usually enough to produce a series of subfigures using a loop. I will discuss the following two cases: 1) Sub-figures have the same base-filename and are consecutively numbered; 2) Sub-figures have arbitrary filenames.
Required packages
We use the foreach
macro, which is provided by the pgffor package (shipped with PGF). Moreover, we will make use of the subfigure
macro implemented by the subcaption package. We load these and additional helper packages in the preamble:
\usepackage{caption,subcaption} \usepackage{graphicx} \usepackage{pgffor}
Consecutively numbered figures
Let’s first consider a scenario where all sub-figures are consecutively numbered with the same base-filename. In this case, we can simply loop over a range of numbers, using foreach
. The range of numbers is equal to the numbers in the filenames. In the example below, I generated 12 figures, with filenames: image1.png
, image2.png
, etc. I can then directly use the value of index i
and combine it with the path/name. The file ending can be dropped for most common image file types. The graphicx bundle recognizes the figure format automatically. To control the number of columns, we set the width parameter of the subfigure
environment to a fraction of the total text width. Here, I set the width to 0.3\textwidth
to produce three columns, leaving 10% for extra spacing between figures. For the actual sub-figure, we want to use all available horizontal space (\linewidth
, which is equal to 0.3\textwidth
). Finally, \quad
adds some extra horizontal space between figures.
\begin{figure} \foreach \i in {1,...,12} {% \begin{subfigure}[p]{0.3\textwidth} \includegraphics[width=\linewidth]{figures/image\i} \caption{} \end{subfigure}\quad } \caption{Main figure caption}\label{fig:subfig} \end{figure}
Arbitrarily named figures
In the absense of a pattern in figure filenames, we can still use a loop to produce sub-figures. However, we’ll have to provide filenames in an array-like structure. I’m using the same filename structure as before for illustration purposes. We define a variable called names
, which contains the sub-figure filenames. Now we can loop over this variable. The code is similar to the previous example, except that the number-range was replaced by the filename array. Make sure not to forget any curly brackets in \names
.
\def\names{{image1},{image2},{image3},% {image4},{image5},{image6}} \begin{figure} \foreach \name in \names {% \begin{subfigure}[p]{0.47\textwidth} \includegraphics[width=\linewidth]{figures/\name} \caption{} \end{subfigure}\quad } \caption{Main figure caption}\label{fig:subfig} \end{figure}
Cross-referencing sub-figures
In order to cross-reference sub-figures, we’ll have to add labels. In the first case, where filenames are consecutively numbered, we might use the same index to create a label.
\begin{figure} \foreach \i in {1,...,12} {% \begin{subfigure}[p]{0.3\textwidth} \includegraphics[width=\linewidth]{figures/image\i} \caption{}\label{subfig:fig\i} \end{subfigure}\quad } \caption{Main figure caption}\label{fig:subfig} \end{figure} To reference, use \ref{subfig:fig4} and \subref{subfig:fig4}.
With arbitrary filenames, we may use the sub-figure counter to auto-generate a label. This is illustrated in the code below.
\def\names{{image1},{image2},{image3},% {image4},{image5},{image6}} \begin{figure} \foreach \name in \names {% \begin{subfigure}[p]{0.47\textwidth} \includegraphics[width=\linewidth]{figures/\name} \caption{}\label{subfig:fig\arabic{subfigure}} \end{subfigure}\quad } \caption{Main figure caption}\label{fig:subfig} \end{figure} To reference, use \ref{subfig:fig4} and \subref{subfig:fig4}.
Note: Using the sub-figure counter as part of the label is not a great idea, as a rearrangement of the figures would lead to a wrong reference. A better solution would be to use the filename itself as part of the label. By the way, the same problem exists in the previous example.
Adding sub-captions
When sub-figure are automatically generated, adding sub-captions can be rather tricky. A possible workaround is to provide captions together with filenames, using a separator. For example, we might separate the filename and the caption by a forward-slash (/
). This obviously only works when neither the filename nor the caption contain a slash.
\def\names{{image1/caption1},{image2/caption2},{image3/caption3},% {image4/caption4},{image5/caption5},{image6/caption6}} \begin{figure} \foreach \name/\subcap in \names {% \begin{subfigure}[p]{0.47\textwidth} \includegraphics[width=\linewidth]{figures/\name} \caption{\subcap} \end{subfigure}\quad } \caption{Main figure caption}\label{fig:subfig} \end{figure}
To omit the caption and the label altogether, we use:
\caption*{}\vspace{-1.2\baselineskip}%
Spacing between sub-figures
We previously saw how to add extra horizontal space between sub-figures, using \quad
or \qquad
(double). Spacing may also be controlled through the captionsetup
macro. For example, we may want to add extra vertical space after each sub-figure. To change the behavior globally, we set captionsetup
in the preamble. For a local change, we use the command within the specific figure
environment.
\begin{figure} \captionsetup[subfigure]{belowskip=20pt} % Sub-figure code \end{figure}
Complete code
\documentclass[11pt]{article} \usepackage{caption,subcaption} \usepackage{graphicx} \usepackage{pgffor} \begin{document} % Figure filenames are consecutively numbered \begin{figure} \foreach \i in {1,...,12} {% \begin{subfigure}[p]{0.3\textwidth} \includegraphics[width=\linewidth]{figures/image\i} \caption{Caption of figure \i}\label{fig:subfig\i} \end{subfigure}\quad } \caption{Main figure caption}\label{fig:subfig} \end{figure} This is a reference to \ref{fig:subfig4} and \subref{fig:subfig4}. % Arbitrary figure filenames \def\names{{image1},{image2},{image3},{image4},{image5},{image6}}% \begin{figure} \foreach \name in \names {% \begin{subfigure}[p]{0.47\textwidth} \includegraphics[width=\linewidth]{figures/\name} \caption{Caption of figure}\label{subfig:fig2\arabic{subfigure}} \end{subfigure}\quad } \caption{Main figure caption}\label{fig:subfig} \end{figure} This is a reference to \ref{subfig:fig24} and \subref{subfig:fig22}. % \def\names{{image1/caption1},{image2/caption2},{image3/caption3},{image4/cation4},{image5/caption5},{image6/caption6}}% \begin{figure} \foreach \name/\subcap in \names {% \begin{subfigure}[p]{0.47\textwidth} \includegraphics[width=\linewidth]{figures/\name} \caption{\subcap} \end{subfigure}\quad } \caption{Main figure caption}\label{fig:subfig} \end{figure} \end{document}