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.

4
  • 1
    What's the reason for trying to load the package before \documentclass?
    – egreg
    Sep 17, 2020 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, 2020 at 6: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, 2020 at 6: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, 2020 at 6:43

2 Answers 2

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}
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...

1
  • Beautiful, thank you!
    – crsh
    Sep 22, 2020 at 14:06

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.