Top-aligned subfigure with bottom-aligned caption
Here's a flexible solution; in a figure
environment you define with \xsubfigure
the objects you need and then arrange them as you like. Each command has as a first argument a symbolic key to be used in \makerow
; the second argument defines the objects via a key-value syntax (add \label
in the body of caption
, if needed).
\documentclass{article}
\usepackage[font=footnotesize]{subcaption}
\usepackage[demo]{graphicx}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\xsubfigure}{ m m }
{% #1 is a symbolic key, #2 is a list of key-value pairs
\roly_xsubfigure:nn { #1 } { #2 }
}
\NewDocumentCommand{\makerow}{ m }
{% #1 is a list of symbolic keys
\roly_makerow:n { #1 }
}
% define the keys
\keys_define:nn { roly/subfigures }
{
width .tl_set:N = \l_roly_subfig_width_tl,
body .tl_set:N = \l_roly_subfig_body_tl,
caption .tl_set:N = \l_roly_subfig_caption_tl,
}
% the needed variables
\dim_new:N \l_roly_row_height_dim
\box_new:N \l_roly_body_box
% this is the inner command that stores the properties
\cs_new_protected:Npn \roly_xsubfigure:nn #1 #2
{
\prop_if_exist:cTF { l_roly_subfig_#1_prop }
{
\prop_clear:c { l_roly_subfig_#1_prop }
}
{
\prop_new:c { l_roly_subfig_#1_prop }
}
\keys_set:nn { roly/subfigures } { #2 }
\prop_put:cnV { l_roly_subfig_#1_prop } { width } \l_roly_subfig_width_tl
\prop_put:cnV { l_roly_subfig_#1_prop } { body } \l_roly_subfig_body_tl
\prop_put:cnV { l_roly_subfig_#1_prop } { caption } \l_roly_subfig_caption_tl
}
% this is the inner command for producing a row
\cs_new_protected:Npn \roly_makerow:n #1
{
% get the heights of the objects on a row
\dim_zero:N \l_roly_row_height_dim
\clist_map_inline:nn { #1 }
{
\hbox_set:Nn \l_roly_body_box
{
\prop_item:cn { l_roly_subfig_##1_prop } { body }
}
\dim_compare:nT { \box_ht:N \l_roly_body_box > \l_roly_row_height_dim }
{
\dim_set:Nn \l_roly_row_height_dim { \box_ht:N \l_roly_body_box }
}
}
% produce a line
\clist_map_inline:nn { #1 }
{
% a subfigure is set here
\begin{subfigure}[t]{ \prop_item:cn { l_roly_subfig_##1_prop } { width } }
\raggedright
\vspace{0pt} % for top alignment
% the body is set in a suitably dimensioned parbox
\parbox[t][\l_roly_row_height_dim]{\textwidth}{
\prop_item:cn { l_roly_subfig_##1_prop } { body }
}
% add the caption
\caption{ \prop_get:cn { l_roly_subfig_##1_prop } { caption } }
\end{subfigure}
\hspace{2em} % some space between the objects in a row
}
\unskip\\ % end up the row
}
\ExplSyntaxOff
\begin{document}
\begin{figure}
\captionsetup[subfigure]{justification=justified,singlelinecheck=false}
\centering
\xsubfigure{A}{
width=0.3\textwidth,
body={\includegraphics[width=3cm,height=2cm]{fig/workflow-S}},
caption={workflow $S$ and some text added to go to the next line}
}
\xsubfigure{B}{
width=0.5\textwidth,
body={\includegraphics[width=6cm,height=2.5cm]{fig/workflow-S-run}},
caption={run of $S$}
}
\xsubfigure{C}{
width=0.3\textwidth,
body={\includegraphics[width=2cm,height=1.5cm]{fig/workflow-S'}},
caption={workflow $S'$}
}
\xsubfigure{D}{
width=0.5\textwidth,
body={\includegraphics[width=4cm,height=1cm]{fig/workflow-S'-run}},
caption={run of $S'$}
}
\makerow{A,B}
\medskip
\makerow{C,D}
\caption{Here's a figure}
\end{figure}
\end{document}
Note that if you're not satisfied with the arrangement, you can rearrange the subfigures by saying, for instance,
\makerow{A,D}
\medskip
\makerow{C,B}
In the example I set height and width for every \includegraphics
, as I don't have your images, but you can use the keys you prefer.
Solution Idea
Put the images inside boxes with a fixed height (use \vtop
to create
top aligned boxes). Use these boxes as images
to be included in subfigure
.
The two images which are placed side-by-side are to be given
identical heights as the first argument of
\imagebox
. The second argument is the \includegraphics
command.
Solution Code
\documentclass{article}
\usepackage{caption}
\usepackage[font=footnotesize]{subcaption}
\usepackage[draft]{graphicx}
\def\imagebox#1#2{\vtop to #1{\null\hbox{#2}\vfill}}
\begin{document}
\begin{figure}[!ht]
\captionsetup[subfigure]{justification=justified,singlelinecheck=false}
\centering
\begin{subfigure}[b]{0.3\textwidth}
\imagebox{37.5mm}{\includegraphics[scale=0.8]{fig/workflow-S}}
\caption{workflow $S$}
\end{subfigure}
\begin{subfigure}[b]{0.5\textwidth}
\imagebox{37.5mm}{\includegraphics[scale=0.8]{fig/workflow-S-run}}
\caption{run of $S$}
\end{subfigure}
\vspace{5.0mm}
\begin{subfigure}[t]{0.3\textwidth}
\imagebox{27.5mm}{\includegraphics[scale=0.8]{fig/workflow-S'}}
\caption{workflow $S'$}
\end{subfigure}
\begin{subfigure}[t]{0.5\textwidth}
\imagebox{27.5mm}{\includegraphics[scale=0.8]{fig/workflow-S'-run}}
\caption{run of $S'$}
\end{subfigure}
\caption{Here's a figure}
\end{figure}
\end{document}
Output
Limitations
I wish I could come up with a more general solution. Manually setting (needs trial and error) the heights for all the pairs is a bother. If I could find a solution where something in the preamble (or a macro definition) could take care of the whole document that would have been perfect.
If you have only a few figures to be aligned like this, this solution should
work. But if you have hundreds of figures like this, you will want to
write a more general macro with two arguments where the two arguments will be the two images
to be top aligned. The macro will first measure the height of the two, take the bigger one, then create two subfigure
s, where \imagebox
is called inside
using the bigger height previously found.