69

How can I manually and simply format a table in RMarkdown that will look good when converted to HTML (using the knitr and markdown packages), PDF (using pandoc and miktex) and docx (using pandoc)?

I want to be able to write small tables in RMarkdown that are not a result of R functions that look good in the three formats I use most often. So far I've found a format that looks good in 2 of the 3 formats, is 3/3 possible?

One. This looks good after Knit HTML but not good in the PDF or docx

<table>
<tr>
<td>Eggs</td>
<td>Ham</td>
</tr>
<tr>
<td>Basil</td>
<td>Tomato</td>
</tr>
</table>

Two. This one looks good after Knit HTML but not good in the PDF or docx

| Tables        | Are           | Cool  |
| ------------- |:-------------:| -----:|
| col 3 is      | right-aligned | $1600 |
| col 2 is      | centered      |   $12 |
| zebra stripes | are neat      |    $1 |

Three. This one does not look good after Knit HTML but is good in the PDF and docx (best option so far)

V1         Tweedledee       Tweedledum
--------   --------------   ----------------
Age        14               14
Height     3'2"             3'2"
Politics   Conservative     Conservative
Religion   "New Age"        Syrian Orthodox
---------  --------------   ----------------

Four. This looks good after Knit HTML and make PDF and docx (winner!) but is not the manual formatting I'm after.

```{r table1, echo=FALSE, message=FALSE, warnings=FALSE, results='asis'}
require(pander)
panderOptions('table.split.table', Inf)
set.caption("Data on cars")
pander(mtcars, style = 'rmarkdown')
```

This is how I'm making the PDF and docx files:

filen <- "table" # name of my RMarkdown file without suffix
knit(paste0(filen,".Rmd"))

# make PDF
system(paste0("pandoc -s ", paste0(filen,".md"), " -t latex -o ", paste0(filen,".pdf"), " --highlight-style=tango  -S"))

# make docx
system(paste0("pandoc -s ", paste0(filen,".md"), " -o ", paste0(filen,".docx"), " --highlight-style=tango  -S"))
Ben
  • 41,615
  • 18
  • 132
  • 227
  • 2
    What's the problem with the `pander` solution? I mean you can also reproduce the same table syntax, it's simply a function that translates R objects to Pandoc'x [pipe syntax](http://johnmacfarlane.net/pandoc/README.html#pipe-tables). – daroczig Nov 15 '13 at 10:32
  • 2
    @daroczig `pander` produces excellent tables from R objects, but I'm looking to see if I can get an excellent table *without* an R object. For example, very simple tables of text. I can't see a way, so maybe making a data frame of my simple table and then using `pander` is the best option. – Ben Nov 15 '13 at 16:18
  • 1
    I see, thank you @Ben for your comment. And for sure you can create such tables by hand (without `pander`), just read the manual at the URL I linked above about the syntax. Or just run `pander(mtcars, style = 'rmarkdown')` and compare with your solution to see the difference. – daroczig Nov 15 '13 at 16:33

2 Answers2

59

Inspired by daroczig's comments, especially the clue that pander translates to pandoc's pipe syntax, I took a closer look at the pander documentation and found reference to cat. After some experimentation, I found the winner:

```{r table2, echo=FALSE, message=FALSE, warnings=FALSE, results='asis'}
tabl <- "
| Tables        | Are           | Cool  |
|---------------|:-------------:|------:|
| col 3 is      | right-aligned | $1600 |
| col 2 is      | centered      |   $12 |
| zebra stripes | are neat      |    $1 |
"
cat(tabl) # output the table in a format good for HTML/PDF/docx conversion
```

This produces uniformly good looking tables in HTML, PDF and docx in my tests. Now I'm off to upvote daroczig on some other questions to thank him for getting me to the solution.

If you need a caption for your table... then you'll need to do it a bit differently. Note that the caption will only be visible in the PDF, not in the HTML:

```{r table-simple, echo=FALSE, message=FALSE, warnings=FALSE, results='asis'}
require(pander)
panderOptions('table.split.table', Inf)
set.caption("My great data")
my.data <- " # replace the text below with your table data
  Tables        | Are           | Cool
  col 3 is      | right-aligned | $1600 
  col 2 is      | centered      |   $12 
  zebra stripes | are neat      |    $1"
df <- read.delim(textConnection(my.data),header=FALSE,sep="|",strip.white=TRUE,stringsAsFactors=FALSE)
names(df) <- unname(as.list(df[1,])) # put headers on
df <- df[-1,] # remove first row
row.names(df)<-NULL
pander(df, style = 'rmarkdown')
```
James Ko
  • 32,215
  • 30
  • 128
  • 239
Ben
  • 41,615
  • 18
  • 132
  • 227
  • 17
    I found that your comment (# simple table creation here) interferes with pandoc. The line before the table must be empty for it to render on my machine. – Wesley Jul 30 '14 at 20:26
  • 2
    The author of the packages `knitr` and `bookdown` suggests `knitr::kable` as the most appropriate solution for multi-format output from R Markdown, particularly if you want tables with captions and automatic labels for internal reference+link. See [here](https://bookdown.org/yihui/bookdown/tables.html) – FairMiles Oct 31 '17 at 18:34
  • 1
    @FairMiles the problem with kable is that it's very hard to have multiple types of data or formats in a column. It works nice for something that can be placed in a data frame, but it's also limited to something that can be placed in a data frame. So no option in this case I'm afraid, unless you manually format everything and convert to character before even touching kable. – Joris Meys Jun 17 '19 at 15:32
  • I'm using a dark theme. Is there any way to make the background of this table lighter (to change the color or the background)? – Nova Jul 23 '19 at 13:28
  • How to place this table on the left side of the document. It always is placed on the center of the document – SID Nov 02 '20 at 06:48
3

There are many better answers to this question today as R Markdown table libraries continue to advance. Comparisons done just a few months ago are often unhelpful or misleading. So I often need to prototype a quick comparison of several options for tabular report layouts of varying complexity.

Here is a simple approach and toolset for evaluating alternative table libraries and output formats with your own data:

  1. Create a TableTester.Rmd file with code below. (Note: You can use your own df to experiment with package-specific formatting.)
  2. Generate html, pdf and docx output with TestRunner.R script (code below)

R Markdown Code - TableTester.Rmd

---
title: "Table-Evaluation"
output: 
  pdf_document: 
    latex_engine: xelatex
  html_document:
    theme: cosmo
  word_document: default
---

```{r setup-data-test, include=FALSE}

library(reactable)
library(kableExtra)
library(flextable)

df <- tibble(
  food = c("eggs", "ham", "squash", "rhubarb"),
  color = c("green", "green", "yellow", "purple"),
  class = c("imaginary", "imaginary", "real", "real")
)

```
```{r, test}
reactable(df)

kbl(df)

flextable(df)

```

R Script - TestRunner.R

for (i in c("html_document", "pdf_document", "word_document")) {
  rmarkdown::render(
    input = "TableTester.Rmd",
    output_format = i)
}
GGAnderson
  • 1,993
  • 1
  • 14
  • 25
  • Hi, this works for me. How could i include a citation inside the table? Also how can i include a space in the header? (ie. food consumed = c("@Author2020", "ham", "squash", "rhubarb"), thanks! – vagvaf Jan 27 '22 at 09:43
  • 1
    After reading tibble's documentation I found out that you can do the second part of the question like so: tibble( \`crazy name\` = 1)) https://tibble.tidyverse.org/articles/tibble.html – vagvaf Jan 28 '22 at 10:58