11

I am working on creating a dynamic rmarkdown document. The end result should create a tab for each 'classification' in the data. Each tab should have a datatable, from the DT package, with the data printed to it. Below is the code I have been using:

---
output: html_document
---

# Setup{.tabset}
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = FALSE)
library(knitr)
library(DT)
```

```{r data.setup}
set.seed = 1242
rows = 64
data.1 = runif(rows, 25, 75)
data.2 = runif(rows, .01, 1)
data.3 = runif(rows, 1, 10)
classification = c("A", "B", "C", "D")
df = data.frame(cbind(data.1 = data.1, data.2 = data.2, data.3 = data.3, classification = classification))
df$data.1 = as.numeric(df$data.1)
df$data.2 = as.numeric(df$data.2)
df$data.3 = as.numeric(df$data.3)
```

```{r results= 'asis'}
for(j in levels(df$classification)){
        df.j = df[df$classification == j, ]
        cat(paste("\n\n## Classification: ", j, "##\n"))
        w = datatable(df.j)
        #datatable(df.j)
        print(w)
}
```

Notice I have commented out straight calls to the datatable function, those were not printing to rmarkdown. The results of the call as written generate an html document with the correct tabs, but no datatables in them. Additionally, the datatables actually display in my RStudio session with the correct subsetting. As a test, I tried achieving the goal using the kable function from knitr, and the tables were printed in their appropriate tabs, unfortunately, kable does not have all the functionality required.

Richard Lusch
  • 1,050
  • 10
  • 19

2 Answers2

13

This is not a complete answer as some of this is still puzzling me, but at least this is good enough to get you going while I try to understand some more.

---
output: html_document
---

# Setup{.tabset}
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = FALSE)
library(knitr)
library(DT)
```

```{r data.setup}
set.seed <- 1242
rows <- 64
data.1 <- runif(rows, 25, 75)
data.2 <- runif(rows, .01, 1)
data.3 <- runif(rows, 1, 10)
classification <- c("A", "B", "C", "D")
df <- data.frame(cbind(data.1 = data.1, data.2 = data.2, data.3 = data.3, classification = classification))
df$data.1 <- as.numeric(df$data.1)
df$data.2 <- as.numeric(df$data.2)
df$data.3 <- as.numeric(df$data.3)
```

```{r include = FALSE}
# Why, oh why do I need this chunk?
datatable(df)
```

```{r results = 'asis'}
for(j in unique(df$classification)){ # You were using level() here, so your for-loop never got off the ground
        df.j <- df[df$classification == j, ]
        cat(paste("\n\n## Classification: ", j, "##\n"))
        print( htmltools::tagList(datatable(df.j)) )
}

The third chunk is required for this to work, I'm not yet sure why.

Chrisss
  • 3,211
  • 1
  • 16
  • 13
  • 1
    +1 I've been searching far and wide for a simple solution and this was it. Note that in the third chunk you can type `datatable(df[1,])` and it will still work! I wonder if @yihui knows why this is necessary – bouncyball Oct 27 '17 at 15:07
  • 1
    I think I know why the first call is required: this is to ensure the inclusion/embedding of DT required javascript to work (which is not the case/done when only including tags). You can just call `datatable(NULL)` (works for me) – Eric Lecoutre Jun 06 '19 at 08:27
  • This third chunk within for loop works for me only when my next chunk have a datatable to print. Or else its showing blank space. What could be the problem? – sksahu Jun 20 '19 at 06:33
  • Also worked for me, many thanks. Also seeing the third chunk being required for this to work, very odd this solution also seems to work for me without the weird requirement of the third chunk: https://github.com/rstudio/DT/issues/67#issuecomment-426329442 – Ricky Nov 14 '21 at 13:08
  • I used datatable(NULL) and it SORT OF worked on mine too (im using a cluster version of R). This is so confusing. I have no idea why added this one chunk will make the datatable output DISPLAY in html, but the DISPLAYed datatale is of different appearance to my rmarkdown (which has the correct bottons etc) – ML33M Jul 31 '22 at 11:32
5

Reaching here by googling the same question. This has worked for me: https://gist.github.com/ReportMort/9ccb544a337fd1778179.

Basically, generate a list of rendered tibbles and manually call knit.

Here is a working Rmd based on your example, using the technique found in the above link:

---
output: html_document
---

# Setup{.tabset}
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = FALSE)
library(knitr)
library(DT)
```

```{r data.setup}
set.seed <- 1242
rows <- 64
data.1 <- runif(rows, 25, 75)
data.2 <- runif(rows, .01, 1)
data.3 <- runif(rows, 1, 10)
classification <- c("A", "B", "C", "D")
df <- data.frame(cbind(data.1 = data.1, data.2 = data.2, data.3 = data.3, classification = classification))
df$data.1 <- as.numeric(df$data.1)
df$data.2 <- as.numeric(df$data.2)
df$data.3 <- as.numeric(df$data.3)
```

```{r include = FALSE}
# prepare a list of 4 sub-dataframes, each corresponding to one classification
df_list <- split(df, df$classification)
```

```{r create-markdown-chunks-dynamically, include=FALSE}

out = NULL
for (c in names(df_list)) {
  knit_expanded <- paste0("\n\n## Classification: ", c, "##\n\n```{r results='asis', echo=FALSE}\n\ndatatable(df_list[['", c, "']])\n\n```")
  out = c(out, knit_expanded)
}

```

<!--- knit those table chunk statements --> 
`r paste(knit(text = out), collapse = '\n')`
Yue Jiang
  • 1,271
  • 10
  • 15
  • 1
    In order to avoid duplicated chunks errors, I had to add code to automatically name the new chunks. So the knit_expanded line became: knit_expanded <- paste0("\n\n## ", c, "##\n\n```{r ", c, ", results='asis', echo=FALSE}\n\nDT::datatable(df_list[['", c, "']])\n\n```") – Gorka Apr 12 '18 at 15:46