49
votes

I'm trying to control the position of a plot when converting to PDF using knitr and pandoc. My .Rmd file looks this:

# My report

Some text some text some text some text some text some text some text some text some text


```{r myplot, echo=FALSE, fig.pos="placeHere", results='hide'}

library(ggplot2)

ggplot(mtcars, aes(mpg, drat)) + geom_point()

```

Some text some text some text some text some text some text some text some text some text

\usepackage{graphicx}
\begin{figure}[placeHere]
  \centering
    \includegraphics[width=0.5\textwidth]{placeHere}
\end{figure}

Some text some text some text some text some text some text some text some text some text

I'm converting to PDF using the functions provided here: http://quantifyingmemory.blogspot.co.uk/2013/02/reproducible-research-with-r-knitr.html

How can I place the plot between the second and third blocks of text? The latex code is not working as it currently stands.

EDIT: This is what I'm trying now.

# My report

   ```{r setup, include=FALSE}
# set global chunk options
opts_chunk$set(cache=FALSE)
library(ggplot2)
```

```{r, echo=FALSE, fig.height=3}

ggplot(mtcars, aes(disp, hp)) + geom_point()


```



Some text Some text Some text Some text Some text Some text Some text Some text Some text Some text Some text Some text Some text Some text Some text Some text Some text Some text Some text Some textSome text Some text Some text 

Some text Some text Some text Some text Some text Some text Some text Some text Some text Some text Some text Some text Some text Some text Some text Some text Some text Some text Some text Some textSome text Some text Some text 


Some text Some text Some text Some text Some text Some text Some text Some text Some text Some text Some text Some text Some text Some text Some text Some text Some text Some text Some text Some textSome text Some text Some text 


Some text Some text Some text Some text Some text Some text Some text Some text Some text Some text Some text Some text Some text Some text Some text Some text Some text Some text Some text Some textSome text Some text Some text 


```{r, echo=FALSE, fig.height=3}



ggplot(mtcars, aes(vs, am)) + geom_point()


```



Some text Some text Some text Some text Some text Some text Some text Some text Some text Some text Some text Some text Some text Some text Some text Some text Some text Some text Some text Some textSome text Some text Some text 

Some text Some text Some text Some text Some text Some text Some text Some text Some text Some text Some text Some text Some text Some text Some text Some text Some text Some text Some text Some textSome text Some text Some text 


Some text Some text Some text Some text Some text Some text Some text Some text Some text Some text Some text Some text Some text Some text Some text Some text Some text Some text Some text Some textSome text Some text Some text 


```{r, echo=FALSE, fig.height=6}



ggplot(mtcars, aes(disp, cyl)) + geom_point()

```


```{r, echo=FALSE, fig.height=6}

ggplot(mtcars, aes(hp, qsec)) + geom_point()


```


Some text Some text Some text Some text Some text Some text Some text Some text Some text Some text Some text Some text Some text Some text Some text Some text Some text Some text Some text Some textSome text Some text Some text 




```{r, echo=FALSE, fig.height=3}

ggplot(mtcars, aes(hp, wt)) + geom_point()

```



Some text Some text Some text Some text Some text Some text Some text Some text Some text Some text Some text Some text Some text Some text Some text Some text Some text Some text Some text Some textSome text Some text Some text 



```{r, echo=FALSE, fig.height=5}

ggplot(mtcars, aes(mpg, drat)) + geom_point()

```




Some text Some text Some text Some text Some text Some text Some text Some text Some text Some text Some text Some text Some text Some text Some text Some text Some text Some text Some text Some textSome text Some text Some text 
8
I may be off base here but I think you're trying to control latex. You want to work with float placement as seen here.Tyler Rinker
Are you mixing knitr's coding for Rnw and Rmd syntax?Tyler Rinker
I've taken a look at the wiki page, and have tried to follow code. However still not placing plot where I want it. Post updated with the code I've triedluciano
Do you know latex? If so make and Rnw file and use latex coding. If you really want to use Rmd and then convert as you're doing you can't insert a figure in this way (to my knowledge). You'll need to insert an html way (maybe use ![](path/to/image). You can use captions in html as well. Also you may just want to use [html <img> ](w3schools.com/tags/tag_img.asp) tags to place the image.Tyler Rinker
I've tried the html approach ![](path/to/image) with my real document and the behaviour of the placement of figures is similar. Therefore, figures are not printing where I've told them to print (quite often they are higher up in document).luciano

8 Answers

30
votes

I'm not aware of such an option for pandoc to set the floating option of figures when converting a Markdown document to LaTeX. If you choose Markdown for its simplicity, you should not expect too much power from it, even with powerful tools like pandoc. Bottom line: Markdown is not LaTeX. It was designed for HTML instead of LaTeX.

Two ways to go:

  1. use the Rnw syntax (R + LaTeX) instead of Rmd (R Markdown) (examples); then you will be able to use the chunk option fig.pos='H' after you \usepackage{float} in the preamble; in this case, you have full power of LaTeX, and pandoc will not be involved

  2. hack at the LaTeX document generated by pandoc, e.g. something like

    library(knitr)
    knit('foo.Rmd')  # gives foo.md
    pandoc('foo.md', format='latex')  # gives foo.tex
    x = readLines('foo.tex')
    # insert the float package
    x = sub('(\\\\begin\\{document\\})', '\\\\usepackage{float}\n\\1', x)
    # add the H option for all figures
    x = gsub('(\\\\begin\\{figure\\})', '\\1[H]', x)
    # write the processed tex file back
    writeLines(x, 'foo.tex')
    # compile to pdf
    tools::texi2pdf('foo.tex')  # gives foo.pdf
    

If you do not like these solutions, consider requesting a new feature to pandoc on Github, then sit back and wait.

94
votes

I present an alternative solution. Instead of inserting [H] symbols into a latex document in a post-hoc manner, I suggest redefining the figure environment to ignore any position arguments and use [H].

To do this, create a .tex file in the same directory as the .Rmd file which redefines the figure environment, and update the YAML header in the .Rmd to include the file during compilation.

Here is an example of a .tex file:

\usepackage{float}
\let\origfigure\figure
\let\endorigfigure\endfigure
\renewenvironment{figure}[1][2] {
    \expandafter\origfigure\expandafter[H]
} {
    \endorigfigure
}

Here is example .Rmd which includes it (assuming you called the .tex file 'preamble-latex.tex'):

---
title: "example"
author: "you"
date: "`r format(Sys.time(), '%d %B %Y')`"
output:
  rmarkdown::pdf_document:
    fig_caption: yes        
    includes:  
      in_header: preamble-latex.tex
---

```{r, fig.cap='Markdownvellous!'}
plot(1:10, 1:10)
```
18
votes

I am using KnitR and markdown in RSTUDIO, the solution for my case is adding in the preamble \usepackage{float}:

    ---
title: "Proyect 2"
author: "FV"
date: "2016-12-3"
output:
  pdf_document:
    fig_caption: yes
    fig_crop: no
    fig_height: 2
    fig_width: 3
    highlight: haddock
    keep_tex: yes
    number_sections: yes
    toc: yes
    toc_depth: 2
  html_document:
    fig_caption: yes
    theme: journal
    toc: yes
    toc_depth: 2
header-includes: 
- \usepackage{graphicx}
- \usepackage{float}
---

And then adding this lines of code (fig.pos='H') in the very first lines:

```{r echo=FALSE,warning=FALSE}
 library(knitr)
  opts_chunk$set(fig.path='figure/graphics-', 
                 cache.path='cache/graphics-', 
                 fig.align='center',
                 external=TRUE,
                 echo=TRUE,
                 warning=FALSE,
                 fig.pos='H'
                )
  a4width<- 8.3
  a4height<- 11.7
```
9
votes

I have a few projects where I convert from .Rmd to .pdf (mostly a beamer slide presentation) and want the graphs to not float (floating figures really don't work with slide presentations).

The approach that I use is to add an escaped space after the line in the .md file. This means that the graph is inside of a paragraph rather than being a paragraph of its own, this means that pandoc will not wrap it in a figure environment (it also means that I cannot use a caption with it) and therefore places it at exactly that position.

I use a Makefile to do all the conversions for me, so after running R and knitr it will automatically run a Perl script (though it could be done using R or other tools) that finds where the plots are inserted and adds the escaped space at the end of the line.

9
votes

If what you are looking for is to just control manually where to put your figures, using this webpage: http://www.rci.rutgers.edu/~ag978/litdata/figs/, I found that if you add one backslash "\" somewhere after your plot commands, the plots will not be floating but instead will be printed in their current location.

If you want only some plots to appear, you can modify that option for each.

In your example:

# My report

```{r setup, include=FALSE}
# set global chunk options
knitr::opts_chunk$set(cache=FALSE)

library(ggplot2)
```

Some text Some text Some text Some text Some text Some text Some text Some       text Some text Some text Some text Some text Some text Some text Some text Some text Some text Some text Some text Some textSome text Some text Some text 

```{r, echo=FALSE, fig.height=3}
ggplot(mtcars, aes(disp, hp)) + geom_point()
```
\

Some text Some text Some text Some text Some text Some text Some text Some       text Some text Some text Some text Some text Some text Some text Some text Some text Some text Some text Some text Some textSome text Some text Some text 

(etc)

6
votes

Using a knitr hook

I somehow stumbled over this question and want to add another approach. Here I make use of the awesome flexibility supplied by knitr hooks. I simply change the plot hook to use the knitr function hook_plot_tex(). Afterwards I can just use the chunk option fig.pos as we are used to in Rnw documents in order to position figure environments (fig.cap must be set in order to invoke the figure environment).

This works in the examples provided by the OP. I guess they also work in (somehow) more complicated examples. Why this can be done that easily and is not the default for Rmd documents, I am not sure. Maybe Yihui can clarify that.

Here is the code:

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

```{r}
knitr::knit_hooks$set(plot = function(x, options)  {
  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()
```

Without fig.pos='h', the plot will usually jump to the second page.

0
votes

Is this what you're after:

```{r setup, include=FALSE}
# set global chunk options
opts_chunk$set(cache=FALSE)
library(ggplot2)
```

# My report

Some text some text some text some text some text some text some text some text some text

Some text some text some text some text some text some text some text some text some text

```{r myplot, echo=FALSE}

ggplot(mtcars, aes(mpg, drat)) + geom_point()

```

Some text some text some text some text some text some text some text some text some text
0
votes

The solution is not too straightforward, maybe someone else will be able to streamline it.

The basic steps. (Windows 7)

  1. You can add the argument fig.pos="H" to the knitr options, either globally or for each individual chunk. NOTE the capital H. This instructs latex to place figure floats exactly where they are called in the Rmd file.

  2. BUT, this requires the package to be used by latex, this you can specify in the template that pandoc uses to construct pdf files. You do this by adding the line \usepackage{float}

  3. BUT, you first need to find the current template file to modify. I could not find this anywhere but you can get pandoc to print the contents of the template to the console with this command: pandoc -D latex

  4. Cut and paste this template code into an empty text file.

  5. Add the line: \usepackage{float}

  6. Save under the filename "default.latex" in a directory such as C:\Users\YOURNAME\pandoc\templates

  7. Add the option --data-dir=C:/Users/YOURNAME/pandoc/templates" to your call to pandoc OR Pandoc.convert("my file.md", format="pdf", options=c("--data-dir=C:/Users/YOURNAME/pandoc/templates")) if using pander in R.

I hope this works for you.