1

For a particular application, I need to know whether or not a page contains a top float. I have therefore taken the definition of the conditional \iftopfloat{<true>}{<false>} given in the following link: Is there a way to determine if there is a float on a page?.

Initially, this conditional was used in document headers and footers. But in my case, I need to use it in the "body" of the document. However, the conditional doesn't work in this context and always executes the true branch regardless of the presence or absence of a top float.

How do you determine (from the document "body") whether or not there is a top float on a page?

\documentclass{article}

\usepackage{mwe}

 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 % From : https://tex.stackexchange.com/questions/56673/is-there-a-way-to-determine-if-there-is-a-float-on-a-page
\makeatletter
\let\latex@makecol\@makecol
\def\@makecol{%
    \let\topfloat\@toplist%
    \latex@makecol%
}
\def\iftopfloat#1#2{\ifx\topfloat\empty #2\else #1\fi}
\makeatother
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\begin{document}
\iftopfloat{Yes}{No}

\clearpage
\begin{figure}[t]
\centering
\includegraphics{example-image}
\end{figure}
\iftopfloat{Yes}{No}

\clearpage\iftopfloat{Yes}{No}

\clearpage
\begin{figure}[t]
\centering
\includegraphics{example-image}
\end{figure}
\iftopfloat{Yes}{No}

\clearpage
\begin{figure}[t]
\centering
\includegraphics{example-image}
\end{figure}
\iftopfloat{Yes}{No}

\clearpage\iftopfloat{Yes}{No}

\clearpage\iftopfloat{Yes}{No}
\end{document}
3
  • you can't. Floats are added way after all macros in the document body have been evaluated. Mar 10 at 11:12
  • consider \clearpage\iftopfloat{Yes}{No} after the clearpage there are no pending floats but you can not test at that point if later in the document there is a figure that floats to the top of this page. Mar 10 at 12:23
  • 1
    what you can do is use \pdflastypos to see on the next run of latex if the first line is at the top of the page, and if not assume a float has been inserted and choose the correct code branch Mar 10 at 16:44

2 Answers 2

2

You can not test within the body of the document, but you can detect whether the first line after a clear page was set at the top of the page on the last run, and so choose an appropriate branch. This will always take at least two runs to converge.

enter image description here

\documentclass{article}

\usepackage{graphicx}

 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\makeatletter
% pdftex version, others would be similar
\def\iftopfloat{%
    \leavevmode
    \pdfsavepos
    \write\@auxout{\string\gdef\string\TPF\roman{page}{\the\pdflastypos}}%
    \ifdim\ifcsname TPF\roman{page}\endcsname
        \csname TPF\roman{page}\endcsname sp\else\z@\fi
      >400pt
      \expandafter\@secondoftwo
    \else
      \expandafter\@firstoftwo
      \fi    
    }
\makeatother
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\begin{document}
\Huge\bfseries

\iftopfloat{Yes}{No}

\clearpage
\begin{figure}[t]
\centering
\includegraphics{example-image}
\end{figure}
\iftopfloat{Yes}{No}

\clearpage\iftopfloat{Yes}{No}

\clearpage
\begin{figure}[t]
\centering
\includegraphics{example-image}
\end{figure}
\iftopfloat{Yes}{No}

\clearpage
\begin{figure}[t]
\centering
\includegraphics{example-image}
\end{figure}
\iftopfloat{Yes}{No}

\clearpage\iftopfloat{Yes}{No}

\clearpage\iftopfloat{Yes}{No}
\end{document}
1
  • Thanks for your reply. I've taken inspiration from it, using the idea of two successive compilations and writing to the auxiliary file. I've tried to generalise so that a \clearpage command is no longer necessary.
    – B Legrand
    Mar 11 at 12:13
1

Taking up David Carlisle's idea of two successive compilations and writing to the .aux file, I've modified the \@combinefloats command so that it writes to the .aux file the pages in which there is a top float.

\documentclass{article}

\usepackage{mwe,lipsum,refcount}

\makeatletter
\def \@combinefloats {%
    \ifx \@toplist\@empty%
    \else%
        \@cflt%
        \immediate\write\@auxout{\string\global\string\@namedef{pageWithTopFloat-\thepage}{1}}%
    \fi%
    \ifx \@botlist\@empty \else \@cflb \fi%
}

\newcounter{ifTopFloatCnt}

\def\iftopfloat#1#2{%
    \global\advance\c@ifTopFloatCnt\@ne%
    \label{\the\c@ifTopFloatCnt @ifTopFloat}%    
    \ifcsname pageWithTopFloat-\getpagerefnumber{\the\c@ifTopFloatCnt @ifTopFloat}\endcsname%
        {\Large\bfseries #1}%
    \else%
        {\Large\bfseries #2}%
    \fi%
}
\makeatother

\begin{document}
\iftopfloat{Yes}{No}

\noindent
p. 1: \ifcsname pageWithTopFloat-1\endcsname yes \else no \fi\\
p. 2: \ifcsname pageWithTopFloat-2\endcsname yes \else no \fi\\
p. 3: \ifcsname pageWithTopFloat-3\endcsname yes \else no \fi\\
p. 4: \ifcsname pageWithTopFloat-4\endcsname yes \else no \fi\\
p. 5: \ifcsname pageWithTopFloat-5\endcsname yes \else no \fi\\
p. 6: \ifcsname pageWithTopFloat-6\endcsname yes \else no \fi\\
p. 7: \ifcsname pageWithTopFloat-7\endcsname yes \else no \fi

\lipsum[1-4]

\clearpage
\begin{figure}[t]
\centering
\includegraphics{example-image}
\end{figure}
\iftopfloat{Yes}{No}

\lipsum[1-4]

\iftopfloat{Yes}{No}

\lipsum[1-4]

\begin{figure}[t]
\centering
\includegraphics{example-image}
\end{figure}
\iftopfloat{Yes}{No}

\lipsum[1-4]

\begin{figure}[t]
\centering
\includegraphics{example-image}
\end{figure}
\iftopfloat{Yes}{No}

\lipsum[1-4]

\iftopfloat{Yes}{No}

\lipsum[1-4]

\iftopfloat{Yes}{No}
\end{document}
5
  • 1
    this test is not at all guaranteed to give a reasonable result \ifcsname pageWithTopFloat-\thepage\endcsname% never access \thepage from the body you need to set a \label at that point and then test \pageref to see what page you are on. Mar 11 at 12:58
  • 1
    to see the issue make a document with a load of \begin{figure}[t] then a long multipage paragraph, The figures will be inserted where they are inserted but all tests in a paagraph will have the same value of \thepage so you will test page 1 for all cases. Mar 11 at 13:00
  • 1
    expansion like \ifcsname and \thepage happens as the input is read, before the paragraph is typeset into a long line that is then broken in to lines, and the lines broken in to pages, so all such macros always reflect the same value even if a paragraph is broken over a page and even the value at the start of the paragraph will be wrong if float pages are inserted. Mar 11 at 13:51
  • @DavidCarlisle Thanks for your feedback, I've corrected the definition of \iftopfloat to make it more robust.
    – B Legrand
    Mar 12 at 16:29
  • yep that looks more like it:-) Mar 12 at 16:36

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .