4

My MWE

\documentclass[twoside]{book}%

% 2 Packages only for demonstration purposes:
\usepackage{tikzducks}% Delivers figures for testing purposes
\usepackage{lipsum}% Delivers blind text


\begin{document}
%\pushfiguretopage{16}% Push figure to page 16
\begin{figure}[b]% 
    \begin{center}
        \includegraphics[width=0.5\textwidth]{example-image-duck}
    \end{center}
    \caption{A duck}
\end{figure}
\lipsum
\lipsum
\lipsum
\lipsum
\lipsum
\lipsum
\lipsum
\lipsum
\lipsum
\lipsum
\lipsum
\lipsum
    
\end{document}

I would like a figure, now appearing on page 1, to appear exactly on page 16. I could do that with a nonfloating environment -- but that only holds, if I don't alter the text before the figure. Or I could do it with \afterpage -- but then I would have to use \afterpage 16 times and in the past then I got some problems with footnotes ...

Is there another possibility, a macro \pushfiguretopage{16}, as I called it in my MWE?

9
  • 2
    Off-topic: Don't use a center *environment` inside a figure (or, for that matter, a table) float, as doing so messes up the whitespace padding. Instead, use a single \centering directive immediately after \begin{figure}.
    – Mico
    Jun 25, 2023 at 14:05
  • 1
    Unrelated to your question but "\usepackage{tikzducks}% Delivers figures for testing purposes" is a bit misleading. example-image-duck comes from the duckuments package. However you only need to have it installed, loading it in your document is not actually necessary. Jun 25, 2023 at 14:13
  • I would try \afterpage first (see tex.stackexchange.com/questions/506766/…), but you could reset parameters using \AddToHook{shipout/after} as well (the previous page). Jun 25, 2023 at 14:22
  • 1
    Will your document contain any figure floats before page 16?
    – Mico
    Jun 25, 2023 at 14:46
  • @Mico: Concerning center and \centering: Thank you. My document can easily contain further figure before page 16: I simply have to put them before \pushfiguretopage{}, which can be used anywhere in the document.
    – ThorstenL
    Jun 25, 2023 at 17:22

3 Answers 3

6

This uses \AddToHook (standarad LaTeX) to reset the totalnumber counter. Note that this will not affect [!] floats, except that they must stay in order. Also note that you cannot reuse \pushfiguretopage until the current one is done (page 16).

\documentclass[twoside]{book}%

% 2 Packages only for demonstration purposes:
\usepackage{tikzducks}% Delivers figures for testing purposes
\usepackage{lipsum}% Delivers blind text

\newcounter{pushtopage}

\makeatletter
\newcommand{\pushfiguretopage}[1]{% #1 = page number
  \setcounter{pushtopage}{#1}%
  \addtocounter{pushtopage}{-1}% activate on previous page
  \setcounter{totalnumber}{0}% turn off all floats
  \global\@colnum=\c@totalnumber% this page too
  \AddToHook{shipout/after}[myhookid]{\ifnum\value{page}=\value{pushtopage}\relax
    \setcounter{totalnumber}{3}% default
    \RemoveFromHook{shipout/after}[myhookid]%
  \fi}}
\makeatother

\begin{document}
\pushfiguretopage{16}% Push figure to page 16

\begin{figure}[b]% will not work if [!].
    \begin{center}
        \includegraphics[width=0.5\textwidth]{example-image-duck}
    \end{center}
    \caption{A duck}
\end{figure}


\lipsum[1-100]
    
\end{document}

This version uses a barrier float, a float too big to ever print (except for \clearpage). It is simply removed from the queue in order to allow the next float to print.

This doesn't check to see if the float removed is in fact the barrier float, although it could (\ht\@id>\textheight).

\documentclass[twoside]{book}%

% 2 Packages only for demonstration purposes:
\usepackage{tikzducks}% Delivers figures for testing purposes
\usepackage{lipsum}% Delivers blind text

\newcounter{pushtopage}

\makeatletter
\newcommand{\pushfiguretopage}[1]{% #1 = page number
  \begin{figure}[ht]% create barrier float
    \rule{1.2\linewidth}{1.2\textheight}
  \end{figure}
  \setcounter{pushtopage}{#1}%
  \addtocounter{pushtopage}{-1}% activate on previous page
  \AddToHook{shipout/after}[myhookid]{\ifnum\value{page}=\value{pushtopage}\relax
    \@next\@id\@deferlist{}{}% remove next float from queue
    \@cons\@freelist\@id
    \RemoveFromHook{shipout/after}[myhookid]%
  \fi}}
\makeatother

\begin{document}
\pushfiguretopage{16}% Push figure to page 16

\begin{figure}[b]% will not work if [!].
    \begin{center}
        \includegraphics[width=0.5\textwidth]{example-image-duck}
    \end{center}
    \caption{A duck}
\end{figure}

\lipsum[1-100]
    
\end{document}
4
  • This works as well for me, much better solution with the hook than mine (I only used hooks for the first time in my life with this problem). But: If I place a bunch of figures BEFORE \pushfiguretopage, with my solution they are printed as attended before page 16 (as long as they are not too many). With your solution one of those additional figures will be printed on page 16, the one that should print there, is only printed at page 19 (with four additional figures). Perhaps one could combine both solutions: An invisible figure before the one to be printed on page 16 communicating with the hook?
    – ThorstenL
    Jun 26, 2023 at 9:41
  • If there are any figures already in the queue they will also be delayed. Note that some floats are added to the page as soon as they are created (@toplist and \@bottomlist) while others are transferred out of \@deferlist at the start of a new page. Jun 26, 2023 at 12:55
  • @ John Kormylo: In the presence of other floats m algorithm has got the problem, that another float may appear on the same page AFTER my float. With your idea I had the problem, that it was difficult, to leave the last float before the one to be pushed on its original page, while at the same time pushing the other -- as the algorithm works pagewise, it is not selective enough to distinguish between two single floats. I wanted that algorithm for producing a two-page panorama ...
    – ThorstenL
    Jun 29, 2023 at 15:05
  • At tex.stackexchange.com/questions/688991/… I show in my own answer to my question (about ten days after I asked), how I combined your and my algorithm to produce a solution, that avoids both problems -- and \afterpage.
    – ThorstenL
    Jun 29, 2023 at 15:08
2

When I tried to use my own algorithm from my own answer, it didn't always work completely reliably, but sometimes push the figure to page 17 instead. So I tried to enhance John Kormylos answer thus that one could place as many figures before \pushfiguretopage as possible without reaching page 16. For that inside \pushfiguretopage an "invisible figure" is issued at the end of all other figures, whichs label reduces totalnumber to 0 via Johns hook.

\documentclass[twoside]{book}%
\RequirePackage{zref-abspage,zref-user}% Needed for zlabel{}

% 2 Packages only for demonstration purposes:
\usepackage{tikzducks}% Delivers figures for testing purposes
\usepackage{lipsum}% Delivers blind text

\newcounter{pushtopage}

\makeatletter
\newcommand{\pushfiguretopage}[1]{% #1 = page number
    \setcounter{pushtopage}{#1}%
    \addtocounter{pushtopage}{-1}% activate on previous page

    % Invisible figure
    \setlength\textfloatsep{0pt}% no distance between text and float
    \begin{figure}[!htb]%
        \zlabel{testfloat}% This will be the last figure before ours
        % for more than one figure we need unique labels here
    \end{figure}%
    \AddToHook{shipout/after}[myhookid]{%
        \ifnum\value{page}=\zref@extractdefault{testfloat}{abspage}{-1}%
            \setcounter{totalnumber}{0}%
        \fi%
        \ifnum\value{page}=\value{pushtopage}\relax
        \setcounter{totalnumber}{3}% default
        \RemoveFromHook{shipout/after}[myhookid]%
        \fi}}
\makeatother

\begin{document}
    \begin{figure}[b]% will not work if [!].
        \begin{center}
            \includegraphics[width=0.5\textwidth]{example-image-duck}
        \end{center}
        \caption{A duck}
    \end{figure}
    \begin{figure}[b]% will not work if [!].
        \begin{center}
            \includegraphics[width=0.5\textwidth]{example-image-duck}
        \end{center}
        \caption{A duck}
    \end{figure}
    \begin{figure}[b]% will not work if [!].
        \begin{center}
            \includegraphics[width=0.5\textwidth]{example-image-duck}
        \end{center}
        \caption{A duck}
    \end{figure}
    \begin{figure}[b]% will not work if [!].
        \begin{center}
            \includegraphics[width=0.5\textwidth]{example-image-duck}
        \end{center}
        \caption{A duck}
    \end{figure}

    \pushfiguretopage{16}% Push following figure to page 16
    \begin{figure}[b]% will not work if [!].
        \begin{center}
            \includegraphics[width=0.5\textwidth]{example-image-duck}
        \end{center}
        \caption{This one should be placed at page 16}
    \end{figure}
    
    
    \lipsum[1-100]
    
\end{document}

Now the counter totalnumber, controlling the total number of floats on a page, is now not set to 0 from the beginning, but only when the "invisible figure" at the end of all other figures is printed. So, if you put \pushfiguretopage{} now exactly before the figure you want to push, all other figures before are printed just as normal.

0

My MWE:

\documentclass[twoside]{book}%
\RequirePackage{refcount}% For \getpagerefnumber{}
%\RequirePackage[maxfloats=256]{morefloats}% For not getting the error "too many unprocessed floats"
%\maxdeadcycles=200%


% 2 Packages only for demonstration purposes:
\usepackage{tikzducks}% Delivers figures for testing purposes
\usepackage{lipsum}% Delivers blind text


\newcount\invisiblefloat%
\invisiblefloat=0
\newcount\safety%
\safety=0

\makeatletter%
\def\pushfloattopage#1#2{% #1: page to reach
    \setlength\textfloatsep{0pt}% no distance between text and float makes empty float unvisible    
    \loop\ifnum\safety<40%
        \advance\invisiblefloat by 1\relax
        \ifnum\numexpr#1-1\relax < \getpagerefnumber{invisiblefloat\number\invisiblefloat}%
            \let\iterate\relax
        \fi
        \begin{@float}{#2}[b]% No \caption, so \counter{figure} is not increased
            \label{invisiblefloat\number\invisiblefloat}% test label: where are we?
        \end{@float}%
        \advance\safety by 1\relax
    \repeat
}% End \pushfloattopage
\makeatother    
    

\begin{document}
\pushfloattopage{16}{figure}% Push figure to page 16
\begin{figure}[!b]% Place it there, even if the float placement restrictions are not allowing it, as there is already the invisible float
    \begin{center}
        \includegraphics[width=0.5\textwidth]{example-image-duck}
    \end{center}
    \caption{A duck}
\end{figure}
\lipsum
\lipsum
\lipsum
\lipsum
\lipsum
\lipsum
\lipsum
\lipsum
\lipsum
\lipsum
\lipsum
\lipsum
    
\end{document}

The macro \pushfloattopage pushes the figure (or a table) forward by filling up the pages with "invisible figures" (or tables), till the page (16) is reached, where the figure is to be placed. These "invisible figures" don't step up the figure counter, as they don't have a caption.

Problems may occur if you want to push the figure forward by an excessive number of pages. Then you should enlarge the maximal number for the counter \safety from 40 to something more and perhaps the counter \maxdeadcycles as well.

And in this case as well as when you want to use this trick several times, you might need to enlarge the maximum number of floats in the queue with the package morefloats.

You might use the same macro for tables as well.

You must log in to answer this question.

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