3

I have a two column document and I try to place a figure not relative to the text but to a page and column (e.g second page, right column, even if I add text later).
Currently, No matter where I put the figure, or which flags I use (e.g !ht) The figure is not placed in the right column.

\begin{figure}[!ht]
\begin{center}
\fbox{\rule{0pt}{2in} \rule{0.9\linewidth}{0pt}}
   %\includegraphics[width=0.8\linewidth]{egfigure.eps}
\end{center}
   \caption{Some comment}
\end{figure}

I am using Overleaf and the CVPR 2018 Template

Edit:
Following John Kormylo remarkable answer, I'm trying to do a similar thing for single-column documents as well, But probably miss something in how I should change the code.
This is my current version for single-column pages:

\newcommand{\delayfloat}[3]{% #1=figure or table, #2=page, #3=savebox
  \ifnum\value{page}<#2\relax
    \afterpage{\delayfloat{#1}{#2}{#3}}%
  \else
    \delaymatchtrue

    \ifdelaymatch
      \begin{#1}[t]
        \box#3
      \end{#1}
    \else
      \afterpage{\delayfloat{#1}{#2}{#3}}%
    \fi
  \fi}

\newenvironment{delayed}[3]{% #1=figure or table, #2=page, #3=savebox

  \def\delayed@box{#3}% copy args to macros
  \def\delayed@args{{#1}{#2}{#3}}%
  \begin{lrbox}{#3}\begin{minipage}{\columnwidth}%
    \def\@captype{#1}%
}{% \enddelayed (no args)
  \end{minipage}\end{lrbox}%
  \global\setbox\delayed@box=\copy\delayed@box
  \expandafter\delayfloat\delayed@args
}

\newif\ifdelaymatchtop

\newcommand{\delaytop}[2]{% #1=page, #2=savebox
    \afterpage{\delaytop{#1}{#2}}%
  }

\newenvironment{delayedtop*}[3]{% #1=figure or table, #2=page, #3==savebox
  \def\delayedtop@box{#3}% copy args to macros
  \def\delayedtop@args{{#2}{#3}}%
  \begin{lrbox}{#3}\begin{minipage}{\textwidth}%
    \def\@captype{#1}%
}{% \enddelayed* (no args)
  \end{minipage}\end{lrbox}%
  \global\setbox\delayedtop@box=\copy\delayedtop@box
  \expandafter\delaytop\delayedtop@args
}

But the images and tables are completely missing from the document. A sample image in the new document:

\begin{delayedtop*}{figure}{11}{\tempboxPartial}
  \centering% the center environment wastes space
  \includegraphics[width=\linewidth]{photos/partial_corr.png}
  \caption{Caption.} 

  \label{fig:partial_corr}
\end{delayedtop*}
3
  • Well, your given link needs to register or have a account on overleaf. Not all people here have or want an account there. So please give a link to the used template without overleaf. And can you please make your code snippet compilable? Then we do not have to guess where you tried to insert the figure in document ...
    – Mensch
    Sep 3, 2019 at 11:15
  • 1
    @Mensch: The particular document/template is really not the issue here. From what I understand, this is about precisely placing a graphic in general. Sep 3, 2019 at 15:53
  • You really should make part 2 a separate question, if only to avoid confusion. You can lose the \ifdelaymatch (and the blank line) with only one column.used. The number of arguments saved in \delaylayedtop@args doesn't match the number used by \delayfloat. Feb 24, 2020 at 13:33

3 Answers 3

5

This solution uses \afterpage to delay the creation of the float to the desired page and column (in this case, page 2, right column). Note that you need to create a new \delayfloat macro for every figure or table you want delayed.

Also, the caption numbers may be off.

\documentclass[twocolumn]{article}
\usepackage{afterpage}
\usepackage{lipsum}% MWE only

\begin{document}

\makeatletter
\newcommand{\delayfloatA}{\ifnum\value{page}=2
  \if@firstcolumn \afterpage{\delayfloatA}%
  \else
    \begin{figure}[t]
      \centering% the center environment wastes space
      \fbox{\rule{0pt}{2in} \rule{0.9\linewidth}{0pt}}
      %\includegraphics[width=0.8\linewidth]{egfigure.eps}
      \caption{Some comment}
    \end{figure}
    \global\let\delayfloatA=\relax
  \fi
\else \afterpage{\delayfloatA}%
\fi}
\makeatother

\delayfloatA
\lipsum[1-16]

\end{document}

The version requires one savebox for each delayed float. All you need to do is pass the float type, page, column number, savebox id (arguments) and float contents (body) to the delayed environment.

Captions will be numbered in the order they are put into saveboxes.

\documentclass[twocolumn]{article}
\usepackage{afterpage}
\usepackage{lipsum}% MWE only

\makeatletter
\newif\ifdelaymatch

\newcommand{\delayfloat}[4]{% #1=figure or table, #2=page, #3=1/2 (column), #4=savebox
  \ifnum\value{page}<#2\relax
    \afterpage{\delayfloat{#1}{#2}{#3}{#4}}%
  \else
    \delaymatchfalse
    \ifcase#3\relax\or% #3=1
      \if@firstcolumn \delaymatchtrue \fi
    \or% #3=2
      \if@firstcolumn\else \delaymatchtrue \fi
    \fi
    \ifdelaymatch
      \begin{#1}[t]
        \box#4
      \end{#1}
    \else
      \afterpage{\delayfloat{#1}{#2}{#3}{#4}}%
    \fi
  \fi}

\newenvironment{delayed}[4]{% #1=figure or table, #2=page, #3=1/2 (column), #4=savebox
  \ifcase#3\relax
    \errmessage{Bad delayed column argument: #3 (must be 1 or 2)}%
  \or\or\else
    \errmessage{Bad delayed column argument: #3 (must be 1 or 2)}%
  \fi
  \def\delayed@box{#4}% copy args to macros
  \def\delayed@args{{#1}{#2}{#3}{#4}}%
  \begin{lrbox}{#4}\begin{minipage}{\columnwidth}%
    \def\@captype{#1}%
}{% \enddelayed (no args)
  \end{minipage}\end{lrbox}%
  \global\setbox\delayed@box=\copy\delayed@box
  \expandafter\delayfloat\delayed@args
}
\makeatother

\newsavebox{\tempboxA}

\begin{document}

\begin{delayed}{figure}{2}{2}{\tempboxA}
  \centering% the center environment wastes space
  \fbox{\rule{0pt}{2in} \rule{0.9\linewidth}{0pt}}
  %\includegraphics[width=0.8\linewidth]{egfigure.eps}
  \caption{Some comment}
\end{delayed}

\lipsum[1-16]

\end{document}

This version installs a figure* on page 2. More precisely, it uses the title of \twocolumn to fake a figure*. Only one per page, and if you try to use the current page it will break the page immediately.

\documentclass[twocolumn]{article}
\usepackage{afterpage}
\usepackage{lipsum}% MWE only
%\usepackage{showframe}

\makeatletter
\newif\ifdelaymatch

\newcommand{\delaytop}[2]{% #1=page, #2=savebox
  \ifnum\value{page}<#1\relax
    \afterpage{\delaytop{#1}{#2}}%
  \else
    \twocolumn[\box#2\par\vskip\dbltextfloatsep]%
  \fi}

\newenvironment{delayed*}[3]{% #1=figure or table, #2=page, #3==savebox
  \def\delayed@box{#3}% copy args to macros
  \def\delayed@args{{#2}{#3}}%
  \begin{lrbox}{#3}\begin{minipage}{\textwidth}%
    \def\@captype{#1}%
}{% \enddelayed* (no args)
  \end{minipage}\end{lrbox}%
  \global\setbox\delayed@box=\copy\delayed@box
  \expandafter\delaytop\delayed@args
}
\makeatother

\newsavebox{\tempboxB}

\begin{document}

\begin{delayed*}{figure}{2}{\tempboxB}
  \centering% the center environment wastes space
  \fbox{\rule{0pt}{2in} \rule{0.9\linewidth}{0pt}}
  %\includegraphics[width=0.8\linewidth]{egfigure.eps}
  \caption{Some comment}\label{test}
\end{delayed*}

\lipsum[1-16]

\end{document}
12
  • Wow, it is definitely the best solution I've found in all the time I spent working on it, thanks you! where should I now put commands like \setlength{\belowcaptionskip}{-10pt} or \label? (it seems to not respond to them now). Is there a simple way to allow it to also support figure* (span over two columns)? Your answer is much appreciated!
    – DsCpp
    Sep 4, 2019 at 4:37
  • Where you able to put multiple figures using that method? It seems like only one is presented.
    – DsCpp
    Sep 4, 2019 at 4:55
  • 1
    \label should go inside the delayed environment after the caption (note that \pageref will give the page it appears on). You should use \vspace* at the top or bottom, but \setlength{\belowcaptionskip}{-30pt} seems to work fine. Since figure* needs to be inserted one page ahead, one should use everypage instead of afterpage. Sep 4, 2019 at 14:18
  • 1
    As it turns out, you can't load floats from an everypage hook (not in outer par mode). Do you really need a special macro for this? See tex.stackexchange.com/questions/499556/… for example. Sep 4, 2019 at 23:07
  • 1
    Instead of using figure*, I now use \twocolumn and fake the figure*. Sep 5, 2019 at 16:32
1

Another way to put your figure where you want is to use the package float.

You write the code of your figure in the place that you want your figure and put beside the beginning of your figure an H.

Example:

\begin{figure}[H]
    your code here
\end{figure}
0

If you don't want to your floats to float (a figure is a float object), you can place them manually. Get rid of the figure environment and include the graphic precisely where you want it. You can use the caption package to manually place captions.

\documentclass[twocolumn]{article}

\usepackage{caption}

\begin{document}

\begin{center}
   \includegraphics[width=0.8\linewidth]{egfigure.eps}
\end{center}
\captionof{figure}{Some comment}

\end{document}

Note that this approach relies on you manually positioning the graphic. It does not allow to define a position like "second page, right column" independent of the surrounding text. You might be able to work something out with TikZ (see TikZ manual, page 257, section "Referencing the Current Page Node – Absolute Positioning").

You must log in to answer this question.

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