Option for figure to appear just before the first reference in the text?

Using some combination of the [htpb!] options (or some other means I'm not aware of), is it possible to allow a floating figure to be placed immediately before the first reference in the text, rather than on the following page?

Consider an example:

\documentclass{article}
\usepackage{graphicx}
\usepackage{lipsum}% MWE only
\usepackage{cleveref}

\begin{document}

\section{Lorem ipsum}
\lipsum[1-2]

\section{Results}

\lipsum[3]

Results are shown in \cref{fig:results}.

\begin{figure}[hbt]
\includegraphics{Figures/results}
\caption{Some results}
\label{fig:results}
\end{figure}

\lipsum[1-4]

\end{document}


For my "results" figure (a pdf, roughly 5cm square), this code will place it at the top of the following page. In this case, I would prefer that the figure be on the same page, just above the first reference in the text if necessary.

Is there combination of [htpb!] that will use this order of preference for placing the float?

1. Here
3. Just before "Here"
4. At the top of the next page

Number 3 seems to be the option that is missing. From my understanding of float behavior, LaTeX will always place the float between text paragraphs, meaning there should be space between \lipsum[3] and the paragraph where I've referenced the figure. That space is the "just before" where I would like LaTeX to automatically place the figure when the next option would be the following page.

Without invoking the figure before the reference in the text, is there a way to have the figure appear before the text where it is invoked?

Here's what I want it to look like:

I accomplished this by moving the figure above the reference. I want to LaTeX to do that for me, but not all the time -- only when the next best option is the top of the next page.

• Well, the [t] option will place it on the same page as the reference is made. Else, one could manually invoke the figure with [ht] option as its own paragraph, prior to the \cref. – Steven B. Segletes May 17 '17 at 14:12
• So you would specify two locations in the text, the second being the preferred location and the first being the alternate. – John Kormylo May 17 '17 at 14:17
• the posted code should always demonstrate the problem, a fragment that can no t be run is not so useful. the t option means exactly what you ask for (unless you are using the flafter package. (It's almost always best to include p as well) – David Carlisle May 17 '17 at 14:19
• @LShaver no, see how everyone answering has had to construct a full test document, had you provided one that extra work would not be needed. – David Carlisle May 17 '17 at 14:31
• @LShaver it isn't clear what you mean in your comment to Steven, the t option does naturally allow it to appear before it is invoked as it can appear at the top of that page. – David Carlisle May 17 '17 at 14:37

As per my understanding, the intended solution should try to prevent the figure from floating. The proposed solutions given below does exactly this.

The first solution does not make the figure float at all. It simply utilizes the \captionof command from the caption package.

The second solution forces the float at its current location by utilizing the H placement option from the float package.

\documentclass{article}

\usepackage{lipsum}

\usepackage{caption}

\usepackage{float}

\usepackage{cleveref}

\begin{document}

\section{First Method --- Use the \texttt{caption} Package}

\lipsum[1]

\begin{center}
Actual Figure\\
Actual Figure\\
Actual Figure
\captionof{figure}{Figure caption 1.}
\label{fig:results1}
\end{center}

Results are shown in \cref{fig:results1}.

\section{Second Method --- Use the \texttt{float} Package}

\lipsum[2]

\begin{figure}[H]
\begin{center}
Actual Figure\\
Actual Figure\\
Actual Figure
\caption{Figure caption 2.}
\label{fig:results2}
\end{center}
\end{figure}

Results are shown in \cref{fig:results2}.

\end{document}

• +1 because this is the answer; but if I can propose an improvement, I’d make two separate listings for the two solutions, so users can tell that the first requires only the caption package, and the second only the float package. – GuM May 17 '17 at 14:34
• @GustavoMezzetti I see nothing in the question that indicates that the figure shouldn't float? – David Carlisle May 17 '17 at 14:35
• Thanks, that was the way I wanted to go first, then I tried to see whether both the solutions can be put together. – Masroor May 17 '17 at 14:35
• @DavidCarlisle: I think that this request is implicit: your answer shows that, indeed, there’s nothing in the float placement algorithm of the LaTeX2e kernel that prevents floats from appearing above their first reference, provided that the figure and the reference both fit into the same page. In your code, above, it suffices to add one more line to the “aaa” text and the figure will move to the next page. The OP says that, in this case, (s)he would prefer the figure to go on the next page too. – GuM May 17 '17 at 14:46
• @GustavoMezzetti hmm that must be fixable: (page break between the migrated figure and the line it migrated from) – David Carlisle May 17 '17 at 14:51

The default figure positioning will place the figure at the top of the current page. In this example it is placed at the top even though the reference (and the figure source) are on the last line of the page.

\documentclass{article}
\usepackage{cleveref}
\usepackage{graphicx}

\begin{document}

aaa\\aaaaaa\\aaaaaa\\aaaaaa\\aaaaaa\\aaaaaa\\aaaaaa\\aaaaaa\\aaa
aaa\\aaaaaa\\aaaaaa\\aaaaaa\\aaaaaa\\aaaaaa\\aaaaaa\\aaaaaa\\aaa

\section{Results}
Results are shown in \cref{fig:results}%
\begin{figure}
\includegraphics[width=\textwidth]{example-image}
\label{fig:results}
\end{figure}.

aaa\\aaaaaa\\aaaaaa\\aaaaaa\\aaaaaa\\aaaaaa\\aaaaaa\\aaaaaa\\aaa
aaa\\aaaaaa\\aaaaaa\\aaaaaa\\aaaaaa\\aaaaaa\\aaaaaa\\aaaaaa\\aaa

\end{document}


The reference is to section 1 not to the figure as there is no caption, a feature of the code in the question:-)

This solution uses tikzpagenodes to determine how much space is left on the page. It also uses the aux file to communicate between the two locations. Consequently, it takes 3 runs to get a stable solution.

The idea is to place the bifigure environment where you want it to go if it won't fit at the desired location, \bilocation. If it won't fit in either location, it will be moved to the top of the next page.

In this case, 26\baslineskip or less will fit the desired location, 27\baselineskip will fit the first location, and 33\baselineskip will wind up on the next page.

\documentclass{article}
\usepackage{graphicx}
\usepackage{tikzpagenodes}
\usepackage{environ}
\usepackage{afterpage}
\usepackage{lipsum}% MWE only
\usepackage{cleveref}

\newcounter{binumber}
\newsavebox{\bipolar}
\newlength{\bidistance}
\newif\ifbipolar% okay to expand image at \bilocation

\newcommand{\newbilocation}[3]% #1 = bifigure counter, #2 = \thepage, #3 = \bidistance)
{\expandafter\xdef\csname bipage#1\endcsname{#2}
\expandafter\xdef\csname bidistance#1\endcsname{#3}}

\makeatletter
\NewEnviron{bifigure}{% place at secondary (first) location
\stepcounter{binumber}%
\parindent=0pt
\parskip=0pt
\def\@captype{figure}%
\global\setbox\bipolar=\vbox{\BODY}%
\@ifundefined{bipage\thebinumber}% first time
{\afterpage{\clearpage\usebox\bipolar\vskip\textfloatsep}}%
{\expandafter\let\expandafter\bipage\csname bipage\thebinumber\endcsname\relax
\ifnum\bipage=\value{page}%
\expandafter\bidistance\csname bidistance\thebinumber\endcsname\relax
\else
\bidistance=0pt
\fi
\ifdim\bidistance<\dimexpr \ht\bipolar+\dp\bipolar+\textfloatsep\relax
\tikz[remember picture]{\pgfextracty{\bidistance}{\pgfpointdiff{\pgfpointorigin}%
{\pgfpointanchor{current page text area}{south}}}%
\global\bidistance=-\bidistance}%
\ifdim\bidistance<\dimexpr \ht\bipolar+\dp\bipolar+\textfloatsep\relax
\global\bipolartrue% let \bilocation handle it
\else
\vskip\textfloatsep
\usebox\bipolar
\vskip\textfloatsep
\global\bipolarfalse
\fi
\else
\global\bipolartrue
\fi}%
}

\newcommand{\bilocation}% place at preferred (second) location
{\tikz[remember picture]{\pgfextracty{\bidistance}{\pgfpointdiff{\pgfpointorigin}%
{\pgfpointanchor{current page text area}{south}}}%
\global\bidistance=-\bidistance}%
\ifbipolar
\ifdim\bidistance<\dimexpr \ht\bipolar+\dp\bipolar+\textfloatsep\relax
\afterpage{\clearpage\usebox\bipolar\vskip\textfloatsep}% next apge
\else
\vskip\textfloatsep
\usebox\bipolar
\vskip\textfloatsep
\fi
\else% account for existing image
\fi
\protected@write\@auxout{\let\arabic=\relax}%
{\string\newbilocation{\thebinumber}{\arabic{page}}{\the\bidistance}}%
}
\makeatother

\begin{document}
\rule{1pt}{33\baselineskip}

\begin{bifigure}
\centering
\includegraphics[height=.2\textheight]{example-image}
\caption{Needed for label}\label{fig:results}
\end{bifigure}

\section{Results}
Results are shown in \cref{fig:results}.

\bilocation

\lipsum[1-4]\clearpage
\end{document}