Skip to content

Instantly share code, notes, and snippets.

@burchill
Last active May 24, 2022 07:57
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save burchill/8873d2ade156b27e92a238a774ce2758 to your computer and use it in GitHub Desktop.
Save burchill/8873d2ade156b27e92a238a774ce2758 to your computer and use it in GitHub Desktop.
How to make figures and text stay in the order you wrote them in R Markdown when convert to LaTeX!

Keep figures and text in the order you wrote them

Want to keep the order of figures and text the way you wrote them in R Markdown when you convert to LaTeX? Tired of having to insert \FloatBarrier after every chunk you want plotted?

Just use knitr's hooks! Let's look at how we can do it:

Adding the placeins LaTeX package

First, you need to add the placeins LaTeX package to the header of your R Markdown file with \usepackage{placeins}. This lets you use the \FloatBarrier LaTeX command.

Example:

Here's an example YAML header for your R Markdown file:

---
title: "Look Ma, Less Floating!"
date: \today
header-includes:
  - \usepackage{placeins}
output: pdf_document
---

Adjusting knitr's hooks

Second, you need to add a custom "hook" in knitr.

Generally, you should probably do that in the first chunks in your file, right after the YAML header. When you make a new .Rmd file in R Studio, such a chunk is automatically added, called "setup". I sometimes use this chunk to also load my libraries. Here's an example:

```{r setup, include=FALSE, message=FALSE, warning=FALSE}
library(tidyverse)
library(lme4)
knitr::opts_chunk$set(echo = FALSE, cache=FALSE)
```

In order to prevent more floating, you need to include the following at the end of such a chunk:

knitr::knit_hooks$set(plot = function(x, options)  {
  paste0(knitr::hook_plot_tex(x, options), "\n\\FloatBarrier\n")
})

This effectively pastes \FloatBarrier after every figure chunk you make, preventing the figures from floating down farther from where you wrote them!

A more flexible version

If for some reason you want to be able to change the floating behavior for individual chunks, you can use the following code instead:

knitr::knit_hooks$set(plot = function (x, options) {
  float_correct <- function(f, y, opts)  {
    if (is.null(opts$regfloat) || opts$regfloat==FALSE)
      paste0(f(y, opts), "\n\n\\FloatBarrier\n")
    else
      f(y, opts)
  }
  if (!is.null(options$out.width) || !is.null(options$out.height) ||
      !is.null(options$out.extra) || options$fig.align != "default" ||
      !is.null(options$fig.subcap)) {
    if (is.null(options$fig.scap))
      options$fig.scap = NA
    return(float_correct(knitr:::hook_plot_tex, x, options))
  }
  return(float_correct(knitr:::hook_plot_md_base, x, options))
})

With that code, you can specifiy regfloat=TRUE in the chunk heading to turn off the automatic \FloatBarrier.

Full example:

---
title: "Example Rmd File"
header-includes:
  - \usepackage{placeins}
output: pdf_document
---

```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = FALSE)
knitr::knit_hooks$set(plot = function (x, options) {
  float_correct <- function(f, y, opts)  {
    if (is.null(opts$regfloat) || opts$regfloat==FALSE)
      paste0(f(y, opts), "\n\n\\FloatBarrier\n")
    else
      f(y, opts)
  }
  if (!is.null(options$out.width) || !is.null(options$out.height) ||
      !is.null(options$out.extra) || options$fig.align != "default" ||
      !is.null(options$fig.subcap)) {
    if (is.null(options$fig.scap))
      options$fig.scap = NA
    return(float_correct(knitr:::hook_plot_tex, x, options))
  }
  return(float_correct(knitr:::hook_plot_md_base, x, options))
})
```

## R Markdown

This is just an example `.Rmd` file. Try changing `regfloat=FALSE` to `regfloat=TRUE` for both figure chunks to see how the the hook changes their behavior.  In a normal file, you can just leave out the `regfloat` option to have it default to the less floaty behavior. 

## The plots

Blah blah blaaaaaaaaaah!

```{r pressure, fig.cap="wowowowow\\label{fig:first-fig}", regfloat=FALSE}
plot(pressure)
```

```{r pressure2, fig.cap="BABABA", regfloat=FALSE}
plot(pressure)
```


## Blag bla blah

This text shouldn't be above the plots when they both have `regfloat=FALSE` (or don't have `regfloat` at all). Blaha fjdsaklfdjsa ofdisafoealkdfjaslkfdjas.
@DerickDiana
Copy link

This is life saving. I have been wanting something like this forever! Thank you so much!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment