Figure position in markdown when converting to PDF with knitr and pandoc

68,899

Solution 1

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.

Solution 2

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)
```

Solution 3

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
```

Solution 4

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)

Solution 5

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.

Share:
68,899
luciano
Author by

luciano

Updated on May 16, 2020

Comments

  • luciano
    luciano almost 4 years

    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 
    
  • luciano
    luciano almost 11 years
    That seems to work if keeping the figure height the same in each plot. But doesnt work if varying figure heights. I've edited post to more closely reflect what my actual document looks like. If you try my code, you will see plots dont appear in same order in PDF as they do in .Rmd file.
  • Tyler Rinker
    Tyler Rinker almost 11 years
    have you looked at knitr's documentation? out.height='380px' Please spend some time with the documentation. Yihui has spent a great deal of time making terrific documentation and minimal examples.
  • Tyler Rinker
    Tyler Rinker almost 11 years
    This person is attempting to make an html2pdf document from an Rmd file not an Rnw file.
  • Andrew
    Andrew almost 11 years
    You're right sorry. It doesn't work. I don't know why I thought it did.
  • luciano
    luciano almost 11 years
    Having spent more time with this, I realise the problem occurs when the .md file (which is outputted by knitr) is converted to a .pdf file (by Pandoc). Adding a backslash to the html code in the .md file controls the figure placement, like this: ` ![plot of chunk unnamed-chunk-1](figure/unnamed-chunk-1.png)\ ` However, this introduces a new problem: the figure caption is lost. The problem continues...!
  • bjw
    bjw over 8 years
    This works nicely, and is much better than the accepted answer IMHO. You could simplify however as the references to vignettes etc are irrelevant here.
  • Farid Cheraghi
    Farid Cheraghi over 7 years
    Perfect solution. was looking for it for a while
  • splaisan
    splaisan over 7 years
    I have been struggling with this too. Thanks so much :-)
  • Ferran VilBer
    Ferran VilBer about 7 years
    I have just discover that in case it doesn´t work change: fig.pos='H' with fig.pos="H", with double quotation marks
  • pwaring
    pwaring about 7 years
    This answer fixed the problem for me. For anyone who doesn't know what an escaped space is, you use a backslash like so: ![SourceTree commit message](images/sourcetree-commit-message.png)\
  • jsta
    jsta about 6 years
    For me, this breaks figure captions and figure alignment.
  • Yihui Xie
    Yihui Xie almost 6 years
    I absolutely agree that this answer is more elegant than mine (posted five years ago), and I'd encourage the OP to accept this one instead.
  • Nova
    Nova over 5 years
    I have tried multiple other solutions here. This was the only one that worked.
  • emudrak
    emudrak about 5 years
    This is the first suggestion that has worked for me! This also works for including images from a file in markdown text outside of a chunk. Thanks so much!
  • Matifou
    Matifou about 5 years
    This answer seems also to work for plain rmarkdown include figures, such as ![Figure](fig.png), nice!
  • cibr
    cibr about 5 years
    If pandoc throws an error, make sure to add fig.pos = 'h'.
  • puslet88
    puslet88 almost 5 years
    If, like me, you encounter the same problem simultaneously for tables - here is a solution: stackoverflow.com/questions/44850011/…
  • dfrankow
    dfrankow almost 4 years
    I cannot contradict your experience, but in general it shouldn't matter. In R, there's no difference in interpretation between single and double quotes. stackoverflow.com/a/20572492/34935
  • Julien Colomb
    Julien Colomb almost 4 years
    SInce it took me 20 min to find it, I comment here, @yihui and team included a special option in bookdown to do that: bookdown.org/yihui/rmarkdown-cookbook/…