26

I have a rmarkdown document where I want to use a list of data.tables and include them in a PDF/HTML/MS Word document. Each component of the list contains one data.table.

What I'm trying to achieve is to use kable to add all tables in a document with captions.

When I index the data.tables one by one like this

```{r}
 kable(list.of.dts[[1]], caption = paste0("Frequency table for the '", colnames(list.of.dts[[1]])[2], "' variable."))
```

everything is fine and the table is nicely formatted as on the screenshot below.

enter image description here

However, if I try to use lapply to kable all the data.tables in the list like this

```{r}
lapply(X = list.of.dts, FUN = function(i) {
  kable(x = i, caption = paste0("Frequency table for the '", colnames(i)[2], "' variable."))
})
```

to process all data.tables and include them in the document, I get quite basic and crude output like on the screenshot below.

enter image description here

Further, if I just pass the list of data.tables to kable like this

```{r}
kable(list.of.dts)
```

I get all the tables with a better formatting (although not as in the first example), but stacked on top of each other, centered in the middle of the page and I can't add captions:

enter image description here

Does anyone know why is this happening and how can I overcome this issue?

EDIT1:

I have put result="asis" in the chunk of the first example and saved the output to an object, then returned the object and it did the trick:

```{r, echo = FALSE, results='asis'}
my.list2 <- lapply(X = list.of.dts, FUN = function(i) {
  kable(x = i, caption = paste0("Frequency table for the '", colnames(i)[2], "' variable."))
})
my.list2
```

If I don't save the output to a new object and then return it, then I get a blank document. The above works (see the screenshot below). The only problems are that I see the names of the list components in between the tables and the tables and their captions are aligned in the middle of the page:

enter image description here

EDIT2:

As user20650 (thank you) noted, explicit loop would work better because none of the list components' names will be shown. Besides that, there is no need to assign the results to a new object and then return it. Here is how it looks:

```{r, echo = FALSE, results='asis'}
for(i in list.of.dts) {
  print(kable(x = i, caption = paste0("Frequency table for the '", colnames(i)[2], "' variable.")))
}
```

enter image description here

The only remaining issue is that the tables are still centered in the page.

EDIT3

The last issue (see above) was to align tables and their captions to the left. user20650 made a suggestion that worked for the captions. After I found this email thread, I modified the yaml header as follow, adding these LaTeX options to the header-includes: section:

---
title: "My report"
author: "John Doe"
output: pdf_document
toc: true
header-includes:
  - \usepackage{caption}
  - \captionsetup{justification=raggedright,singlelinecheck=false}
  - \usepackage[margins=raggedright]{floatrow}
---

The first two lines of header-includes: (load the caption package and define the cations' settings) fix the captions' position to left. The last line loads the floatrow package and and fixes the margins.

Case closed.

panman
  • 1,179
  • 1
  • 13
  • 33
  • 2
    try with a `for` loop (as you are not returning anything, just printing) – user20650 Apr 24 '18 at 16:08
  • I have a feeling it is due to multiple tables in one expression, if you output the lapply into an object (say `x`) and do `x[[1]]`, `x[[2]]` in the same chunk it outputs both tables separately. Putting in a for loop gives your first result. – Ashley Baldry Apr 24 '18 at 16:30
  • @user20650: Yes, I tried this, following this post: https://stackoverflow.com/questions/31317373/r-rmarkdown-render-list-of-dataframes. Does not work even after explicitly wrapping the call to `kable` in `print`, returns the same things as in my second example. – panman Apr 24 '18 at 16:39
  • 2
    @panman ; using the example from the link you show: using `for(i in l_df) print( kable(i) )` works for me (also using `results='asis'`). If oyu can't get it to work, can you add a samll reproducible example to your question please. – user20650 Apr 24 '18 at 17:04
  • @user20650: Thank you! Before I saw your new comment I have update the question. `results='asis'` works with `lapply` too. – panman Apr 24 '18 at 17:22
  • 2
    Good stuff. re your edit, if you use an explicit loop, you wont have the list names (that are produced when using lapply) – user20650 Apr 24 '18 at 17:22
  • @user20650: Thank you for your time and patience! You really helped me a lot, I edited the post again and added the changes. Still, the tables and the captions are centered... – panman Apr 24 '18 at 17:37
  • 2
    I take it you are outputting to pdf? if so, see https://tex.stackexchange.com/questions/275131/align-caption-to-the-left. So add `header-includes: - \usepackage{caption} - \captionsetup{justification=raggedright,singlelinecheck=false}` (with correct spacing) – user20650 Apr 24 '18 at 18:10
  • @user20650: Yes, it is about PDF. Thank you for the suggested code, but it moves only the caption to the left, the tables still remain centered. – panman Apr 24 '18 at 19:57
  • OK, I fixed it and edited the question to leave a paper-trail. – panman Apr 24 '18 at 20:31
  • tl/dr: use `lapply` or `map` with `kable` and add `results='asis'` to chunk options. – moodymudskipper Apr 02 '19 at 12:56
  • 1
    Are you averse to using `pander`? That's how I approach PDF tabular output. Also, can we post the solution in the Answer? – Ben Apr 19 '22 at 13:24
  • 1
    I second @Ben - please post the solution in the Answer section. It will make it better for future users. – Caddisfly Apr 04 '23 at 21:03

0 Answers0