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?

ThorstenL
  • 161
  • 2
    Off-topic: Don't use a center *environmentinside afigure(or, for that matter, atable) float, as doing so messes up the whitespace padding. Instead, use a single\centeringdirective immediately after\begin{figure}`. – Mico Jun 25 '23 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. – samcarter_is_at_topanswers.xyz Jun 25 '23 at 14:13
  • I would try \afterpage first (see https://tex.stackexchange.com/questions/506766/pin-figure-to-page-and-column-in-a-2-column-document), but you could reset parameters using \AddToHook{shipout/after} as well (the previous page). – John Kormylo Jun 25 '23 at 14:22
  • 1
    Will your document contain any figure floats before page 16? – Mico Jun 25 '23 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 '23 at 17:22
  • @samcarter_is_at_topanswers.xyz: You are right, I didn't know that ... – ThorstenL Jun 25 '23 at 17:25
  • @John Kormylo: I have tried \afterpage in my original document since years. But then I ran into problems with footnotes, see here: https://tex.stackexchange.com/questions/688815/footnotetext-jumps-to-next-page-and-back-again. There I got the advice not to use the packages fewerfloatpages and afterpage. So I try to replace now my original solution with \afterpage by one without. On that way I found the solution above for pushing a float -- and thought, it might possibly help others. I tried to do with \AddToHook before, but I didn't manage and it became very complicated -- I gave up. – ThorstenL Jun 25 '23 at 17:37
  • You could get rid of fewerfloatpages instead. Serosly, all you need is to adjust \floatpagefraction, which is better done manually anyway. – John Kormylo Jun 25 '23 at 18:50
  • @John Kormylo: After the advice, not to use fewerfloatpages, I dropped the package fewerfloatpages and tried to adjust the parameters totalnumber, bottomnumber, topnumber, floatpagefraction, textfraction and so on -- and that according to your advice as well really made things much better generally. But unfortunately, my problems with footnotes stayed unchanged. So I decided, I should try without afterpage as well ... – ThorstenL Jun 25 '23 at 21:01

3 Answers3

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}

John Kormylo
  • 79,712
  • 3
  • 50
  • 120
  • 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 '23 at 09: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. – John Kormylo Jun 26 '23 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 '23 at 15:05
  • At https://tex.stackexchange.com/questions/688991/two-page-panorama-without-afterpage-tables-as-well-as-figures/689127#689127 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 '23 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.

ThorstenL
  • 161
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.

ThorstenL
  • 161