GeneralWrapper for subcaptionbox: automatic vertical alignment

LaTeX specific issues not fitting into one of the other forums of this category.
Post Reply
woj-k
Posts: 15
Joined: Wed Jul 28, 2010 7:25 pm

Wrapper for subcaptionbox: automatic vertical alignment

Post by woj-k »

Hello everyone,

I got stuck on designing easy-to-use command wrappers for multipanel floats (i.e. subfigures/subtables) built around the subcaption package. The problem has to do with vertical alignment of the individual panels of the float: the 'default' behaviour I have observed is bottom-alignment, but I would like the users to be able to specify rows where the panels are verticaly centered or top-aligned. This would require raising some of the panels by an amount which is dependent on the height of the 'tallest' panel in the given row.

In the MWE below I have omitted top-aligned panels for brevity.

The panel-environment evaluates its contents and dumps them into a macro \panelcontents. Although it does nothing with this value, it does evaluate the contents' height and stores it in \currentpanelheight---I imagine the final version will have to do it anyway, to decide which panel is the tallest automatically.

The problem disappears if I specify the tallest panel's height by hand (line 89 of the MWE). It is to have LaTeX determine this value automatically for each row that poses a problem. I considered a solution where each panel exports a value to an external file, and a separate macro selects the tallest panel on a subsequent run, rather than on-the-fly. There is probably a more elegant way to do it, but I am missing a piece of the puzzle. Can anyone offer any advice?

Code: Select all

\documentclass{book}
\usepackage{subcaption}
\usepackage[labelsep=space]{caption}

%Housekeeping code
\newlength\tallestpanelinrow
\newlength\currentpanelheight
\newlength\currentpanelwidth

\newif\ifcenterpanels
\newif\ifbottomalignpanels

\newcommand{\CenterPanels}{%
    \centerpanelstrue
    \bottomalignpanelsfalse
}%
\newcommand{\BottomAlignPanels}{%
    \centerpanelsfalse
    \bottomalignpanelstrue
}%
\BottomAlignPanels


%Row environments
\newenvironment{Bpanelrow}{\par\BottomAlignPanels}{}

%Centered panels dump contents in a savebox
%for future repositioning
\newsavebox{\rowpanelbox}
\newenvironment{Cpanelrow}{\par\CenterPanels%
\begin{lrbox}{\rowpanelbox}}%
{\end{lrbox}%
\usebox\rowpanelbox%
}


%The panel environment
\newsavebox{\panelbox}
\newenvironment{panel}[2][1.0]{%
%Housekeeping code
  \setlength{\currentpanelwidth}{#1\textwidth}%
  \def\panellabel{#2}%
%This code stores the panelcontents in the \panelbin savebox
  \begin{lrbox}{\panelbox}}{\end{lrbox}%
  \def\panelcontents{\usebox\panelbox}%
%The panel contents are now stored in \panelcontents
%
%Initialise \currentpanelheight
  \settoheight{\currentpanelheight}{\panelcontents}
%
%First panel assumes it is the tallest, if no tallest panel has been defined
\ifdim\tallestpanelinrow<0pt%
    \setlength{\tallestpanelinrow}{\currentpanelheight}
\fi
%
%Output the panel
\ifbottomalignpanels
    \subcaptionbox{\strut\label{\panellabel}}%
                  [\currentpanelwidth]%
                  {\vbox to\tallestpanelinrow{\vfil\hbox{\panelcontents}}}%
    \else\ifcenterpanels
        \subcaptionbox{\strut\label{\panellabel}}%
                      [\currentpanelwidth]%
                      {\vbox to\tallestpanelinrow{\vfil\hbox{\panelcontents}\vfil}}%
    \fi
\fi
}

%The table
\newenvironment{multipaneltable}[3][tbhp]{%
\begin{table}[#1]
\begin{center}%
    \captionsetup{type=table,hypcap=false,position=bottom,subrefformat=parens}
    \caption{#2\label{#3}}%
    \setlength{\tallestpanelinrow}{-1pt}%To detect first panel
}%
{%
\end{center}%
\end{table}%
}



\begin{document}

Some text.

\begin{multipaneltable}[h]{Caption goes here.}{tablelabel}%
%
%Un-comment this line to make vert. alignment work.
%\setlength{\tallestpanelinrow}{8em}
%
\begin{Bpanelrow}
    \begin{panel}[0.2]{panelone}
        \rule{1em}{8em}
    \end{panel}
    \begin{panel}[0.2]{paneltwo}
        \rule{1em}{1em}
    \end{panel}
    \begin{panel}[0.2]{panelthree}
        \rule{1em}{3em}
    \end{panel}
\end{Bpanelrow}
%
\begin{Cpanelrow}
    \begin{panel}[0.2]{panelfour}
        \rule{1em}{8em}
    \end{panel}
    \begin{panel}[0.2]{panelfive}
        \rule{1em}{1em}
    \end{panel}
    \begin{panel}[0.2]{panelsix}
        \rule{1em}{3em}
    \end{panel}
\end{Cpanelrow}
%
\begin{Cpanelrow}
    \begin{panel}[0.2]{panelfour}
        \rule{1em}{1em}
    \end{panel}
    \begin{panel}[0.2]{panelfive}
        \rule{1em}{3em}
    \end{panel}
    \begin{panel}[0.2]{panelsix}
        \rule{1em}{8em}
    \end{panel}
\end{Cpanelrow}
%
\end{multipaneltable}

Some text.

\end{document}
Last edited by woj-k on Mon Jun 17, 2013 2:27 pm, edited 1 time in total.

Recommended reading 2024:

LaTeXguide.org • LaTeX-Cookbook.net • TikZ.org
LaTeX Beginner's Guide LaTeX Cookbook LaTeX TikZ graphics TikZによるLaTeXグラフィックス
woj-k
Posts: 15
Joined: Wed Jul 28, 2010 7:25 pm

Wrapper for subcaptionbox: automatic vertical alignment

Post by woj-k »

Fixed up a solution using the \VerbatimOut facility of the fancyvrb package, with export of each row to an external file and using the code twice---once to determine the size and once to print the correctly aligned row. It all happens on the same run. Had to redefine \panel for the size-determination step, and for some reason I could not simply return it to the previous version using \global\let---had to use \renewcommand again instead. Here's a top-aligned and centred example.

Code: Select all

\documentclass{article}
\usepackage{fancyvrb,caption}
\usepackage[labelsep=space]{subcaption}

\newlength\currentheight
\newlength\tallesttemp
\newlength\currentpanelwidth


\newenvironment{multipaneltable}[3][tbhp]{%
\begin{table}[#1]%
\begin{center}%
    \captionsetup{type=table,hypcap=false,position=bottom,subrefformat=parens}%
    \caption{#2\label{#3}}%
}%
{\end{center}\end{table}}


\newenvironment{Cpanelrow}%
  {%
    \newcommand{\panel}[3][1.0]{\setlength{\tallesttemp}{0.0pt}%
    \setlength{\currentpanelwidth}{##1\textwidth}%
    \gdef\panellabel{##2}%
    \gdef\panelcontents{##3}%
    \settoheight{\currentheight}{\panelcontents}\addtolength{\tallesttemp}{-\currentheight}%
    \subcaptionbox{\strut\label{\panellabel}}[\currentpanelwidth]{\raisebox{0.5\tallesttemp}{\panelcontents}}}%
    \VerbatimOut{\jobname.pnl}%
  }%
  {%
    \endVerbatimOut\par%
    \renewcommand{\panel}[3][1.0]{\gdef\panelcontents{##3}\raisebox{0.5\tallesttemp}{\panelcontents}}%
    \settoheight{\tallesttemp}{\input{\jobname.pnl}}%
    \xdef\hhtemp{\the\tallesttemp}%
%
    \renewcommand{\panel}[3][1.0]{\setlength{\tallesttemp}{0.0pt}%
    \setlength{\currentpanelwidth}{##1\textwidth}%
    \gdef\panellabel{##2}%
    \gdef\panelcontents{##3}%
    \settoheight{\currentheight}{\panelcontents}%
    \setlength{\tallesttemp}{\hhtemp}%
    \addtolength{\tallesttemp}{-\currentheight}%
    \subcaptionbox{\strut\label{\panellabel}}[\currentpanelwidth]{\raisebox{0.5\tallesttemp}{\panelcontents}}}%
%
    \input{\jobname.pnl}%
  }%

\newenvironment{Tpanelrow}%
  {%
    \newcommand{\panel}[3][1.0]{\setlength{\tallesttemp}{0.0pt}%
    \setlength{\currentpanelwidth}{##1\textwidth}%
    \gdef\panellabel{##2}%
    \gdef\panelcontents{##3}%
    \settoheight{\currentheight}{\panelcontents}\addtolength{\tallesttemp}{-\currentheight}%
    \subcaptionbox{\strut\label{\panellabel}}[\currentpanelwidth]{\raisebox{1.0\tallesttemp}{\panelcontents}}}%
    \VerbatimOut{\jobname.pnl}%
  }%
  {%
    \endVerbatimOut\par%
    \renewcommand{\panel}[3][1.0]{\gdef\panelcontents{##3}\raisebox{1.0\tallesttemp}{\panelcontents}}%
    \settoheight{\tallesttemp}{\input{\jobname.pnl}}%
    \xdef\hhtemp{\the\tallesttemp}%
%
    \renewcommand{\panel}[3][1.0]{\setlength{\tallesttemp}{0.0pt}%
    \setlength{\currentpanelwidth}{##1\textwidth}%
    \gdef\panellabel{##2}%
    \gdef\panelcontents{##3}%
    \settoheight{\currentheight}{\panelcontents}%
    \setlength{\tallesttemp}{\hhtemp}%
    \addtolength{\tallesttemp}{-\currentheight}%
    \subcaptionbox{\strut\label{\panellabel}}[\currentpanelwidth]{\raisebox{1.0\tallesttemp}{\panelcontents}}}%
%
    \input{\jobname.pnl}%
  }%
\begin{document}

\begin{multipaneltable}{Vertical alignment: \subref{panelonelabel}--\subref{panelthreelabel}~centred row; \subref{panelfourlabel}--\subref{panelsixlabel}~top-aligned row.}{tab:tablelabel}
\begin{Cpanelrow}
\panel[0.2]{panelonelabel}{\rule{4em}{5em}}
\panel[0.2]{paneltwolabel}{\rule{4em}{2em}}
\panel[0.2]{panelthreelabel}{\rule{4em}{8em}}
\end{Cpanelrow}
\begin{Tpanelrow}
\panel[0.2]{panelfourlabel}{\rule{4em}{6em}}
\panel[0.2]{panelfivelabel}{\rule{4em}{3em}}
\panel[0.2]{panelsixlabel}{\rule{4em}{1em}}
\end{Tpanelrow}
\end{multipaneltable}

\end{document}
Post Reply