Can't control position of tables and figures in knitted pdf document

I am using RMarkdown to create a pdf report and I need the graphs and tables to appear in the order in which they are generated and placed within the text at the point where they are generated in the Rmardown file. This seeems like a reasonable thing to want to do. However...strange - the plots all go to the end and out of order. Why? How can I make them show up in the order of execution in the Rmarkdown document??

NOTE: when I generate the report as a HTML or a word doc, the tables and figures appear in the correct order. But I need to prepare the report as a pdf and would like to do that directly.

I have seen other similar questions asked here, but the level of discussion is over my head and it is not clear to me that anyone has resolved this problem. Some of the discussion involves Tex commands that I am not familiar with. I know there is an issue with "float" and I have read what is available on the web, but I am new to Rmarkdown/Bookdown and really cannot interpret the information. Perhaps it is not possible to do what I want to do and if so I would appreciate knowing that. but if it is possible I would be eternally grateful if someone can show me how to modify this Rmarkdown file to make that happen.... Thanks!!!

FYI I am running this file under RStudio Version 1.2.1335, which is running R version 3.6.0.

The "offending" Rmd file is given below that should execute and exhibit the strange behavior described above...

---
title: "My title"
author: "Me"
output:
  word_document: default
  extra_dependencies: float
  fig_caption: yes
  html_document:
    df_print: paged
  number_sections: yes
  pdf_document: default
  bookdown::pdf_document2: null
---

```{r}
knitr::opts_chunk$set(fig.pos = "!H")
```

```{r plot1,fig.cap="This graph is supposed to appear first, but it comes out third???",fig.height = 5, fig.width = 5}
x <- 1:10
y <- rnorm(10)
plot(x,y)
```

```{r plot2, fig.cap="This graph is supposed to appear second but it comes out last???.",fig.height = 5, fig.width = 5}
plot(y,x)
```

The thing below is a table

```{r table1}
knitr::kable(mtcars[1:5, 1:5], caption = "I need this to be the third thing that appears. But it comes out first???")
```

The thing below is a bigger table

```{r table2}
knitr::kable(mtcars[1:6, 1:6], caption = "I need this to be the fourth thing that appears. But it comes out second???")
```
1 Like

You'll need to look at the kableExtra package. You're right that your tables and plots are 'floating' so you need to 'hold' them in position.

You can take a look at this similar question her Control order of output chunks in PDF document

1 Like

I'm not sure what the definitive approach is here (or even if there is one), but here's one option that should work:

First, create a separate text file (see image below for how to open a new text file in RStudio) and name it, say, my_header.tex.

Put the following in that file (source):

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

These are the latex instructions that will result in the figures being placed where we want them.

Then in your rmarkdown file, include the following in the YAML header (the text at the top that's bounded at the top and bottom by ---).

output:
  rmarkdown::pdf_document:
    fig_caption: yes        
    includes:  
      in_header: my_header.tex

The in_header: my_header.tex puts the latex we just created into the preamble of the latex document that gets generated when you click Knit.

The code in your question isn't a reproducible rmarkdown document, so here is a sample document to work with:

---
title: With Latex Header File
output:
  pdf_document:
    fig_caption: yes        
    includes:  
      in_header: my_header.tex
---

```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE)
```

Here is a histogram of the poisson distribution:

```{r cars, fig.cap="my caption"}
hist(rpois(100,3))
```

The thing below is a table:

```{r}
knitr::kable(mtcars[1:5, 1:5], caption = "I need this to be the third thing that appears. But it comes out first???")
```

The thing below is a bigger table:

```{r}
knitr::kable(mtcars[1:6, 1:6], caption = "I need this to be the fourth thing that appears. But it comes out second???")
```

Here is a base graphics plot:

```{r pressure, echo=FALSE, fig.cap="Another caption"}
plot(pressure)
```

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

Below on the left is what the PDF output looks like with the rmarkdown document above. Below on the right is what the PDF output looks like if we change to the following YAML header:

---
title: Without Latex Header File
output:
  pdf_document:
    fig_caption: yes        
---

As you can see, with the Latex Header File, the figures and tables are placed exactly where they are created in the rmarkdown document.

5 Likes

Thank you Joel!!! Worked as advertised. I really appreciate the extra effort you went to to provide a working example as I learn best from examples like this and I have not seen one until now. I do not claim to understand the syntax/mechanism used here. I have a lot to learn I guess. But this will help me get my work done. I consider this the definitive answer to my question.

Thank you jdb. Your quick response to my question is greatly appreciated. I have loaded the kableExtra package and read through the link that you provided. But I don't know how to implement this tool to solve my problem because I have so little experience with Rmarkdown. I'm not sure kableExtra would solve my problem because I (seem to) need to control the placement of both figures and tables. My understanding (which may be wrong) is that kableExtra would control only table placement. What would really help me would be a toy example that implements the kableExtra solution. I would learn allot from that I think.

1 Like

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.