0

Let's say I have a dataset with several variables, which I want to explore by plotting their distributions e.g. in a bar diagram each. I create a Rmarkdown report and automate this plotting in a vectorized function. Easy enough:

---
title: "Doc title"
output: html_notebook
---

```{r setup}
library(tidyverse, magrittr)

opts_knit$set(root.dir = ROOT_DIR)
opts_chunk$set(results = 'asis', warning = FALSE)
```

```{r dataset}
set.seed(303574)

dataset <- tibble(
  var_1 = sample.int(4, 20, replace = TRUE),
  var_2 = sample.int(7, 20, replace = TRUE)
)
```

# Histograms

```{r plot}
dataset %>% iwalk(
  ~{
    dataset %$% qplot(.x, xlab = .y, geom = "bar") %>% print()
  }
)
```

When I knit this document I get the expected result. Now, I want to create a section by adding a title for each variable, thus separating the plots in different sections (in this case, with a tab for each variable).

This is what I would expect to render the output I intend:

---
title: "Doc title"
output: html_notebook
---

```{r setup}
library(tidyverse, magrittr)

opts_knit$set(root.dir = ROOT_DIR)
opts_chunk$set(results = 'asis', warning = FALSE)
```


```{r dataset}
set.seed(303574)

dataset <- tibble(
  var_1 = sample.int(4, 20, replace = TRUE),
  var_2 = sample.int(7, 20, replace = TRUE)
)
```


# Histograms {.tabset}

```{r plot, results='asis'}
dataset %>% iwalk(
  ~{
    paste0("## ", .y) %>% cat(fill = TRUE)
    dataset %$% qplot(.x, xlab = .y, geom = "bar") %>% print()
  }
)
```

However, what is happening is that both titles are rendered before any of the plots. As a result, I have one empty tab per variable, except for the last one, where all the plots are rendered altogether (in this minimal example, one empty tab and another one with the two plots, instead of a plot per tab).

How would I force knitr to alternate the rendering of the text and the plots? I tried with a for loop, i.e.:

for (var in dataset %>% colnames()) {

  paste("##", var) %>% cat(fill = TRUE)
  qplot(dataset[[var]], xlab = var, geom = "bar") %>% print()
}

But this didn't work either.

Thank you so much!

P.S.: Please note this question is similar to this one; however, the difference is that I'm trying to add the automatically rendered titles here.

Update (2020-05-06):

As it turns out, this only happens when the output is a notebook (i.e., html_notebook); when rendered to an html_document, the plots are placed properly and it's not an issue anymore.

Mori
  • 182
  • 14
  • 1
    Could you simplify your example, and make it reproducible? We don't have `data_4AT_input`. – user2554330 May 04 '20 at 12:30
  • This answer may do what you want: https://stackoverflow.com/a/44147347/2554330 – user2554330 May 04 '20 at 13:03
  • @user2554330 thanks, I was using the wrong dataset, it should actually say `dataset`. I edited it, I think it's ok now. I can't see how it could be simpler... – Mori May 04 '20 at 18:16
  • As it turns out, this only happens when the output is a notebook (i.e., `html_notebook`); when rendered to an `html_document`, the plots are placed properly and it's not an issue anymore. I'll go with this (question updated to reflect this discovery). – Mori May 06 '20 at 10:41

1 Answers1

1

You can do it using a function from this answer: https://stackoverflow.com/a/50352019/2554330. The issue is that knitr won't output the right Markdown source to do what you want, so you need to do what it should be doing. So define this function:

encodeGraphic <- function(g) {
  png(tf1 <- tempfile(fileext = ".png"))  # Get an unused filename in the session's temporary directory, and open that file for .png structured output.
  print(g)  # Output a graphic to the file
  dev.off()  # Close the file.
  txt <- RCurl::base64Encode(readBin(tf1, "raw", file.info(tf1)[1, "size"]), "txt")  # Convert the graphic image to a base 64 encoded string.
  myImage <- htmltools::HTML(sprintf('<img src="data:image/png;base64,%s">', txt))  # Save the image as a markdown-friendly html object.
  return(myImage)
}

Then you can get the output that you want using this code. I needed to insert a few extra newlines, but otherwise it's basically just what you had, run through encodeGraphic:

```{r plot, results='asis'}
dataset %>% iwalk(
  ~{
    paste0("\n## ", .y, "\n") %>% cat()
    dataset %$% qplot(.x, xlab = .y, geom = "bar") %>%
      encodeGraphic() %>% cat()
  }
)
```
user2554330
  • 37,248
  • 4
  • 43
  • 90
  • Thanks so much. It seems a bit of a workaround but seems like it could work... I found it's not such an issue though, but I'll accept your answer as the best approach. – Mori May 06 '20 at 10:40