2

Background: My TeX file is generated from R Markdown and captions are automatically placed below included figures. Here is a minimal example of what my generated TeX file looks like:

\documentclass[man]{apa7}
\title{Test}

\begin{document} \maketitle

Lorem ipsum

\begin{figure} The figure \caption{The caption.} \end{figure}

\end{document}

Problem: Figure captions need to be rendered above the corresponding figure (as per APA guidelines) without moving \caption.

What I have tried: I understand that captions can be rendered above the figure without changing the code via the floatrow package and \floatsetup[figure]{style=plaintop}. However, loading floatrow interferes with endfloat, which is loaded by apa7. Specifically, figures are no longer placed at the end of the document but rendered in place:

\documentclass[man]{apa7}
\usepackage{floatrow}
\floatsetup[figure]{style=plaintop}

\title{Test}

\begin{document} \maketitle

Lorem ipsum

\begin{figure} The figure \caption{The caption.} \end{figure}

\end{document}

According to the documentation of endfloat, floatrow should always be loaded before endfloat (and, thus, before apa7). Hence, I try to load floatrow via \RequirePackage{} but this yields errors. I can fix some of those by undefining two lengths, but this leaves me with the following error that I can't seem to resolve:

! Missing \endcsname inserted.
<to be read again> 
                   \@classoptionslist 
l.1453 \ProcessOptionsWithKV{floatrow}

Here's the minimal reproducible example:

\RequirePackage{floatrow}
\let\abovecaptionskip\undefined
\let\belowcaptionskip\undefined

\documentclass{apa7}

\begin{document}

Lorem ipsum

\end{document}

Note that despite the error message I get a rendered PDF file that looks as expected. Also this is not specific to apa7; I get the same error when I use the article or book document class.

crsh
  • 597
  • 1
    What's the reason for trying to load the package before \documentclass? – egreg Sep 17 '20 at 20:39
  • 1
    apa7 loads endfloat to place figures at the end of the document. When I load floatrow after \documentclass and, thus, after loading endfloat, figures are rendered in place rather than being delayed. – crsh Sep 18 '20 at 06:19
  • Note that if you use floatrow just for caption position then you can also do this by just entering the caption before the float, e.g., \begin{figure}\caption{xyz}\includegraphics{}\end{figure}, then you don't need to load floatrow at all. – Marijn Sep 18 '20 at 06:38
  • 1
    Thanks for your comments. I just updated my question to provide more context and a more detailed description of the problem. As noted, my TeX is automatically generated, so I don't have control over the placement of \caption inside the figure environment. – crsh Sep 18 '20 at 06:43

2 Answers2

2

Interestingly, apa7 converts figure into figure*. Anyway, the basic idea is to store the caption and figure into separate saveboxes and reverse their order.

\documentclass[man]{apa7}
%\documentclass{article}
%\usepackage{endfloat}
\usepackage{lipsum}% MWE only

% udbox is a \vbox version of lrbox \makeatletter \def\udbox#1{% \edef\reserved@a{% \endgroup \setbox#1\vbox{% \begingroup\aftergroup}% \def\noexpand@currenvir{@currenvir}% \def\noexpand@currenvline{\on@line}}% \reserved@a @endpefalse \color@setgroup \ignorespaces} \def\endudbox{\unskip\color@endgroup} \makeatother

\newsavebox{\mycaptionbox} \newsavebox{\myfigurebox}

\makeatletter \let\normalmakecaption=@makecaption \def@makecaption#1#2{\def\test{figure}% \ifx@captype\test \global\setbox\mycaptionbox=\vbox{\normalmakecaption{#1}{#2}}% \else \normalmakecaption{#1}{#2}% \fi} \makeatother

\let\normalfigure=\figure \let\endnormalfigure=\endfigure

\renewenvironment{figure}[1][tbp]{\normalfigure \begin{udbox}{\myfigurebox}}% {\end{udbox}\unvbox\mycaptionbox \unvbox\myfigurebox\endnormalfigure}

\expandafter\let\expandafter\normalfigurestar\csname figure\endcsname \expandafter\let\expandafter\endnormalfigurestar\csname endfigure\endcsname

\renewenvironment{figure*}[1][tbp]{\normalfigurestar \begin{udbox}{\myfigurebox}}% {\end{udbox}\unvbox\mycaptionbox \unvbox\myfigurebox\endnormalfigurestar}

\title{Test}

\begin{document} \maketitle

Lorem ipsum

\begin{figure} \lipsum[1] \caption{The caption.} \end{figure}

\end{document}

John Kormylo
  • 79,712
  • 3
  • 50
  • 120
2

The efloat package is doing its re-definitions of figure, figure* etc. inside \efloat@AtBeginDocument, and usually \efloat@AtBeginDocument is defined as either \@iden or \AtBeginDocument. In this case both would do the re-definitions too early since the floatrow package does its re-definitions \AtBeginDocument. So the trick to get your situation solved is to delay the re-definitions done by the endfloat package even further.

Luckily the definition of \efloat@AtBeginDocument is done with \providecommand since the author of efloat already had in mind to give the user an option to self-determine the exact moment when the re-definitions should be done: "(Note: \efloat@AtBeginDocument will be defined using \providecommand so document classes and packages can pre-define it if needed.)" (Quote taken from the efloat code documentation)

The solution below defines its own version of \efloat@AtBeginDocument, storing the content into a macro called \efloatredefinitions which could be applied later on, especially after the re-definitions of the floatrow package were already done.

% Store the code of efloat re-definitions into \efloatredefinitions
% (This code must be defined before the efloat package is loaded.)
\makeatletter
\newcommand\efloatredefinitions{}
\newcommand\efloat@AtBeginDocument{\g@addto@macro\efloatredefinitions}
\makeatother

\documentclass[man]{apa7}

\usepackage{floatrow} \floatsetup[figure]{style=plaintop}

% Do the efloat re-definitions after the re-definitions of floatrow were done %\show\efloatredefinitions \AtBeginDocument{\efloatredefinitions} % or simply \efloatredefinitions after \begin{document}

\title{Test}

\begin{document} \maketitle

Lorem ipsum

\begin{figure} The figure \caption{The caption.} \end{figure}

\end{document}

P.S.: It would be nice if the endfloat package would offer an option "storeredefinitions" or similar so \PassOptionsToPackage{storeredefinitions}{endfloat} could be used instead of defining \efloat@AtBeginDocument on its own. Will write an e-mail to the author of endfloat about this...