Consolidate multiple figures into one
Written by Yifei Wang, December 2023
Besides using Jupyter notebooks on GitHub, we also recommend Overleaf for writing up your project results. Overleaf is an online LaTeX editor which is great for formal reports. It is better than PowerPoint for keeping track of daily updates to communicate with your colleagues, with a future manuscript in mind that you can shape this document to get there. However, adding lots of figures can be a bit more work than PowerPoint. A LaTeX document with many figures can also be long and takes lots of time to render.
To make it easier to add many figures to LaTeX document for informal documents, you can use ImageMagick to preprocess multiple figures into single PNG
file, then insert this one file to LaTeX.
Step 1: Generate Figures in PDF Format and Save to Disk
From R, save figures in PDF
format on your disk as separate files, for later processing.
Step 2: Combine PDFs into a single PNG Using ImageMagick
- First, install ImageMagick using
micromamba
orconda
.
conda install -c conda-forge imagemagick
or,
micromamba install -c conda-forge imagemagick
- Once ImageMagick is installed, use the
convert
command to combine yourPDF
files into a singlePNG
.
convert file1.pdf file2.pdf file3.pdf +append output.png
You can specify the resolution of the resulting combined figure using -density
switch for example:
convert -density 200 file1.pdf file2.pdf file3.pdf +append output.png
For simple concatenation in a single row or column, the append
option of the convert
tool is sufficient. Note that -append
concatenates all images vertically, and +append
concatenates horizontally.
- To get finer control over the layout, we would need the
montage
tool which is also available from ImageMagick. For example if you want to create a $3\times2$ grid layout:
montage file1.pdf file2.pdf file3.pdf file4.pdf file5.pdf file6.pdf -tile 3x2 -geometry +0+0 miff:- | convert - -density 500 output.png
-tile
controls the layout to be applied.tile
follows the format columns$\times$rows, but either side may be missing and montage
will figure out how to meet the constraints. The intermediate image is passed as a MIFF (Magick Image File Format) which preserves all detail and metadata and quality; convert
will further process it to render it well.
Step 3: Add panel labels to subpanels (optional)
Here is a more sophisticated script and documentation written by ChatGPT4 to annotate and add panel labels to figures before combining,
#!/bin/bash
# Usage: ./montage_script.sh --layout <tile_layout> --spacing <spacing> --density <density> <output_image> <image1> <image2> ...
layout=""
spacing=""
density=""
output_image=""
declare -a input_images=()
while [[ "$#" -gt 0 ]]; do
case "$1" in
--layout) layout="$2"; shift 2;;
--spacing) spacing="$2"; shift 2;;
--density) density="$2"; shift 2;;
*)
if [ -z "$output_image" ]; then
output_image="$1"
else
input_images+=("$1")
fi
shift;;
esac
done
# Check if required parameters are set
if [ -z "$layout" ] || [ -z "$spacing" ] || [ -z "$density" ] || [ -z "$output_image" ] || [ ${#input_images[@]} -eq 0 ]; then
echo "Error: Missing required parameters."
echo "Usage: $0 --layout <tile_layout> --spacing <spacing> --density <density> <output_image> <image1> <image2> ..."
exit 1
fi
label="A"
annotated_images=()
# Function to increment a character
increment_char() {
printf "\\$(printf '%03o' $(( $(printf '%d' "'$1") + 1 )))"
}
# Annotate each image
for img in "${input_images[@]}"; do
annotated_img="annotated_${img}"
convert "$img" -gravity NorthWest -pointsize 40 -weight Bold -annotate +10+10 "$label" "$annotated_img"
annotated_images+=("$annotated_img")
label=$(increment_char "$label")
done
# Combine the images using montage and convert
montage "${annotated_images[@]}" -tile "$layout" -geometry "$spacing" miff:- | convert - -density "$density" "$output_image"
# Clean up annotated images
for img in "${annotated_images[@]}"; do
rm "$img"
done
How to Use This Script:
- Save the script as
montage_script.sh
. - Make it executable:
chmod +x montage_script.sh
. - Run the script:
./montage_script.sh --layout 3x2 --spacing +0+0 --density 200 output.png image1.jpg image2.jpg image3.jpg image4.jpg
.
This script now accepts --layout
, --spacing
, and --density
as parameters, followed by the output file name and the list of input images. The montage is created as per your provided template, and the script handles labeling and cleanup as before.
For example:
./montage_script.sh --layout 2x1 --spacing +1+1 --density 500 colocboost_overview.png colocboost_flowchart.jpg colocboost_hybrid_data.png
This is a very rough script with many hard-coded values. You should change it for your project as you see fit.
Step 4: Insert Figures on Overleaf
Use the LaTeX command \includegraphics
to include the image in your Overleaf document, for example:
% Inserting the combined PNG image
\begin{figure}[ht]
\centering
\includegraphics[width=\textwidth]{output.png}
\caption{Combined image of the figures}
\label{fig:combinedimage}
\end{figure}
If you use the document template from this repo (which is the case for some of our lab members) you can use these customized LaTeX syntax,
\generateFig[optionalRotationDegrees]{figCodeName}{figureNamePath}{size:propOfTextwidth}
{\small Bold text main caption.}
{Smaller normal text caption}
\figCodeName
You can (and maybe should) also upload the original PDF file into the Overleaf repository to keep a copy of high resolution figure that might be useful down the road.