# Floats shortly after they have been \ref-erenced; Warn otherwise

In my thesis I have a many floating figures which I then reference using \ref. I use flafter to ensure that they do not appear before they are defined in the source code (See Force floats to be typeset after their occurrence in the source text?).

However, this doesn't stop it from appearing far before the first \ref which points to it, if the figure is located earlier in the source code. Also sometimes I have a \ref on one page and the figure two pages ahead, which makes it come very late in a single-page layout required for the soft-bound copies for the examiners (luckily the final hard-board copies can now be double-sided).

Is there an existing way to force figures (and maybe also tables) to be placed after the first \ref, i.e. on the bottom of the same page or on the next page? Again, this is not what flafter does! Alternatively a way to warn the document author about a figure appearing too early or too late would also be enough. Both would avoid the need to check and recheck all figures in the whole document.

-
Why not wait to include the figure or the table until you first reference it? Since you don't seem to want your reader to look at it until then, what is lost? –  Ethan Bolker May 27 '12 at 13:30
@EthanBolker: I usually do this, but references can move later under time pressure or a theses chapter can be a merge result of several papers etc. Then an automatic check if the figures and references are still in order would be beneficial. –  Martin Scharrer May 27 '12 at 14:15
One of the SE wizards will probably take up your TeX challenge. In the meanwhile a simple grep for \ref{fig: or \label{fig: would flag any out-of-order pairs. –  Ethan Bolker May 27 '12 at 15:28
You could probably make a shell script that checked whether the first \ref{fig: occurs far away from the \label{fig: by counting the line numbers between them. –  Seamus May 27 '12 at 15:39
@EthanBolker: I'm looking more for a general solution. grep also doesn't handle situations where there is one page between \ref and \label etc. –  Martin Scharrer May 27 '12 at 15:46

If you are prepared to blow one additional label per reference you can automatically detect this situation by comparing the page number of the source label (ie, the one inside your figure or table) with the page the \ref command is used on.

A solution that puts out information per \refcould look like this:

\documentclass{article}

\makeatletter

\def\@getrefpage#1{%
\ifx #1\relax \maxdimen \else \expandafter\@secondoftwo #1  \fi
}

\newcount\@sourcepage
\newcount\@refpage
\newcount\@refcount

\def\@comparerefpage #1{%
\label{cr@\romannumeral\@refcount}%
\@sourcepage=\expandafter\@getrefpage\csname r@#1\endcsname
\@refpage=\expandafter\@getrefpage\csname r@cr@\romannumeral\@refcount\endcsname
\ifnum\@refpage>\@sourcepage
\typeout{***Warning: source for label  '#1' on page \the\@sourcepage
\space < \the\@refpage \space (reference)}%
\else
\typeout{***Ok: source for label  '#1' on page \the\@sourcepage
\space >= \the\@refpage \space (reference)}%
\fi
}

\def\ref#1{\expandafter\@setref\csname r@#1\endcsname\@firstoftwo{#1}@comparerefpage{#1}}

\makeatother

\begin{document}

X\label{a}   X\label{b}

\ref{a}

\newpage

\ref{a}\ref{b}

\end{document}


That will give you the following information on the screen and in the log:

***Ok: source for label 'a' on page 1 >= 1 (reference)
[1{c:/texlive/2011/texmf-var/fonts/map/pdftex/updmap/pdftex.map}]
***Warning: source for label 'a' on page 1 < 2 (reference)
***Warning: source for label 'b' on page 1 < 2 (reference)


Of course this is a rather simple minded approach, ie, all references are tested not just those to figures or tables. If you want to restrict that to some reference "classes" you probably need to use some convention on the label names, e.g. fig:foo, so that you can restrict the code to just work on the references you are interested in. Or you can call the redefinition of \ref something like \figref and use that in your source whenever you want to have this check executed.

-