55

I am using knitr (1.9.5 and 1.9.17) and rmarkdown (0.5.3.1), and would like to hold figure position in the pdf output. The generated pdf file is working fine when chunk option fig.pos="H" is used.

However, the figure position is not hold when fig_caption: yes is set in the yaml header.

How should I fix this problem? Thanks for any suggestions.

EDIT:

After learning the float environment of Latex. I add float package into header.

\usepackage{float}

But the generated tex file always use htbp in the figure environment regard to any fig.pos options are used. After manually changing htbp to H, positions of all figures are hold.

This is my example of rmd file:

---
title: "Untitled"
output:
  pdf_document:
    fig_caption: yes
    includes:
        in_header: mystyles.sty
---

# Section 1


Note that the `echo = FALSE` parameter was added to the code chunk to prevent printing of the R code that generated the plot.

Note that the `echo = FALSE` parameter was added to the code chunk to prevent printing of the R code that generated the plot.

Note that the `echo = FALSE` parameter was added to the code chunk to prevent printing of the R code that generated the plot.

Note that the `echo = FALSE` parameter was added to the code chunk to prevent printing of the R code that generated the plot.


```{r fig1, echo=FALSE, fig.height=8.5, fig.pos="H"}
plot(cars)
```

# Section 2

More test

```{r fig2, echo=FALSE, fig.height=8.5, fig.pos="H"}
plot(cars)
```

# Section 3

```{r fig3, echo=FALSE, fig.height=8.5, fig.pos="H"}
plot(cars)
```

More test
Bangyou
  • 9,462
  • 16
  • 62
  • 94
  • I found Yihui's answer here, which may answer my question: http://stackoverflow.com/questions/16626462/figure-position-in-markdown-when-converting-to-pdf-with-knitr-and-pandoc – Bangyou Apr 17 '15 at 10:52
  • I have had a similar issue. I am assuming that fig.pos is not actually parsed from .Rmd to Pandoc, because when examining the .tex output it just lists the 4 options [htpb] for your figure. – kristang Apr 21 '15 at 14:03
  • @kristang, As Yihui mentioned in his answer, we can not expect too much about formatting from markdown. Just write some R script to replace htpb to H. Will post my scripts. – Bangyou Apr 21 '15 at 21:37
  • 1
    Of course. I just found it weird it is listed as an option when it does not get parsed. – kristang Apr 22 '15 at 18:43
  • Possible duplicate of [Figure position in markdown when converting to PDF with knitr and pandoc](https://stackoverflow.com/questions/16626462/figure-position-in-markdown-when-converting-to-pdf-with-knitr-and-pandoc) – Mureinik Sep 18 '18 at 21:36
  • Literally none of these work. – wolfsatthedoor Mar 24 '19 at 02:11

7 Answers7

44

For me adding the float package and then \floatplacement{figure}{H} in YAML solved the issue like :

---
title: "test"
date: "`r Sys.Date()`"
output: 
  pdf_document :
    keep_tex: true
    number_sections: true
header-includes:
 \usepackage{booktabs}
 \usepackage{longtable}
 \usepackage{array}
 \usepackage{multirow}
 \usepackage[table]{xcolor}
 \usepackage{wrapfig}
 \usepackage{float}
 \floatplacement{figure}{H}
---
Haribo
  • 2,071
  • 17
  • 37
26

As Andrew pointed out, this fig.pos doesn't work in chunks, but it does work if it is put in global options:

```{r global_options, include=FALSE}
knitr::opts_chunk$set(fig.pos = 'H')
```

EDIT: the above apparently used to work and needs \usepackage{float} in the preamble:

header-includes:
 \usepackage{float}

See also here and the Cookbook for some other ways.

Davor Josipovic
  • 5,296
  • 1
  • 39
  • 57
  • 7
    I found this to work except I had to use `fig.pos = 'h'` (i.e. lowercase instead of uppercase)... I also found that the location of this 'global_options' chunk matters, it has to be placed after the YAML header and before any chunks with include=TRUE. – James Cramer Oct 28 '16 at 18:19
  • Nice observation @InTheRed. Note that 'global_options' chunk name is arbitrary as far as I understand. The important part is that the `knitr::opts_chunk$set()` command - which sets the knitr chunk default options - should be executed as soon as possible during knitr-ing. So it should be somewhere at the top of the document. – Davor Josipovic Oct 28 '16 at 18:28
  • 19
    This does not work for me and my figures are still floating around. – shouldsee Oct 28 '17 at 19:40
  • Sometimes this answer didn't work for me, but the answer above including `float` and `\floatplacement{figure}{H}` did work. – dfrankow Jun 21 '22 at 16:08
18

Update look at this better solution here. (the summary of the problem below is still good, but follow the link to a better solution).

To summarise some testing in RStudio

The knitr chunk argument fig.pos = "H" works as long as fig_caption: yes is not in the yaml header.

Each figure in the generated .tex looks like this

\subsection{my_section}\label{my_section}

\includegraphics{path_to_fig.pdf}

But if fig_caption: yes is in the yaml header then the .tex looks like this

\subsection{my_section}\label{my_section}

\begin{figure}[htbp]
\centering
\includegraphics{path_to_fig.pdf}
\caption{}
\end{figure}

fig.pos = "H" has not been used, "htbp" is there instead.

A workaround for this using RStudio:

put

fig_caption: yes
keep_tex: yes

in the yaml as well as

header-includes: \usepackage{float}

then search and replace [htbp] with [H] in the generated .tex file

then open the .tex file in RStudio and use the "Compile PDF" button.


Example .Rmd

---
title: "Testing fig placement with captions"
author: "Andrew Dolman"
date: "1 September 2015"
output: 
  pdf_document: 
    fig_caption: yes
    keep_tex: yes
header-includes: \usepackage{float}
---

This is an R Markdown document. Markdown is a simple formatting syntax for authoring HTML, PDF, and MS Word documents. For more details on using R Markdown see <http://rmarkdown.rstudio.com>.

When you click the **Knit** button a document will be generated that includes both content as well as the output of any embedded R code chunks within the document. You can embed an R code chunk like this:

```{r}
summary(cars)
```

You can also embed plots, for example:

```{r, echo=FALSE, fig.pos="H"}
plot(cars)
```

Note that the `echo = FALSE` parameter was added to the code chunk to prevent printing of the R code that generated the plot.

```{r, echo=FALSE, fig.pos="H"}
plot(cars)
```
Community
  • 1
  • 1
Andrew
  • 733
  • 6
  • 11
11

Although the answer provided by @Bangyou works, it complicates knitting.

You can also set a global default option for figure placement in latex, including this in your YAML header includes:

\makeatletter\renewcommand*{\fps@figure}{H}\makeatother

As explained here (and here for the \makeat... part).

This way you can just use the knit button in RStudio or rmarkdown::render and be done with it.

Issue is, all figures fill be forced with H and you won't be able to set one to float around.

Oscar de León
  • 2,331
  • 16
  • 18
  • 3
    FWIW, of the solutions offered here, this is the one that seems to work for me. – jdobres May 17 '18 at 19:24
  • This 1-line gem seems to me the definitive answer. Too bad so few upvotes! – David C. Norris Jul 29 '18 at 12:55
  • This didn't work for me without the fig.pos = 'h' option also toggled on for each chunk, I've added a separate answer to summarize.. – Nova Aug 17 '18 at 21:03
  • Didn't work for me either. Received error `! LaTeX Error: Unknown float option \'H'.` Changed `H` to `h`. Did not need to add `fig.pos` to the code chunks. Everything works. – lowndrul May 17 '19 at 14:50
8

The option that worked for me:

In the .tex put at the beginning: \usepackage{float}.

At the beginning of the Rmd: knitr::opts_chunk$set(fig.pos = 'H'). The H in upper case).

And in every chunk with an image: fig.cap="lorem blabla" and out.extra='' (parameter value=empty string).

No need to define: fig_caption: yes and keep_tex: yes in the yaml.

These options make the image to keep their position, either for include_graphics and the plots generated by R code.

I used them in the bookdown enviroment, generating the pdf and the html as expected :)

Pablo Casas
  • 868
  • 13
  • 15
  • 1
    This answer explains why the `out.extra` option is used: https://stackoverflow.com/a/43245550/1494531 – stragu Jul 03 '18 at 13:25
6

The code from Figure position in markdown when converting to PDF with knitr and pandoc helps me, help anyone else find it useful.

---
title: "Example"
author: "Martin"
output: pdf_document
---

```{r}
knitr::knit_hooks$set(plot = function(x, options)  {
  knitr::hook_plot_tex(x, options)
})
```


```{r myplot, echo=FALSE, results='hide', fig.cap='Test', fig.pos='h'}
library(ggplot2)
ggplot(mtcars, aes(mpg, drat)) + geom_point()
```
Shixiang Wang
  • 2,147
  • 2
  • 24
  • 33
5

As Yihui mentioned in his answer (Figure position in markdown when converting to PDF with knitr and pandoc), we cannot expect too much about formatting from mardown. To workaround this problem, just write some R scripts to replace htbp to H.

Compared with knit from knitr package, I found render from rmarkdown is better to export a tex file. Just remember to add keep_tex: yes in the yaml header of your rmarkdown file.

library(rmarkdown)
render('filepath.Rmd')
x <- readLines('filepath.tex')
pos <- grep('begin\\{figure\\}\\[htbp\\]', x)
x[pos] <- gsub('htbp', 'H', x[pos])
writeLines(x, 'filepath.tex')
tools::texi2pdf('filepath.tex', clean = TRUE)  # gives foo.pdf

file.remove('filepath.tex')
Community
  • 1
  • 1
Bangyou
  • 9,462
  • 16
  • 62
  • 94