Table printing demo

Author

Lisa DeBruine

This code is meant to replicate (and extend) the df_print option in rmarkdown. The code for kable or paged tables is relatively simple, and I have created a more complex function that prints short tables with kableExtra::kable() and longer tables with DT::datatable(). You have to source in the file with the knit_print.data.frame() function for each page in a website or each chapter in a book.

Code

These functions should override knitr::knit_print() for data frames, but wasn’t working at all until I learned in the knit_print vignette that you have to use registerS3method().

df_print: paged

library(knitr)
# print everything as paged ----
knit_print.data.frame <- function (x, options, ...) {
  rmarkdown::paged_table(x, options) |>
    rmarkdown:::print.paged_df()
}
registerS3method("knit_print", "data.frame", knit_print.data.frame)
data.frame(x = rnorm(5), y = LETTERS[1:5])

df_print: kable

library(knitr)
# print everything as kable ----
knit_print.data.frame <- function (x, options, ...) {
  knitr::kable(x) |> knitr::knit_print(options, ...)
}
registerS3method("knit_print", "data.frame", knit_print.data.frame)
data.frame(x = rnorm(5), y = LETTERS[1:5])
x y
-0.9906570 A
0.2181923 B
1.0508325 C
-1.3864300 D
-0.6493202 E

df_print: custom

Prints tables with 10 or fewer rows using kableExtra::kable() and longer tables with DT::datatable() (unless overridden by options). Includes chunk options for:

  • digits (defaults to getOption("digits"))
  • rownames (defaults to FALSE)
  • pageLength (defaults to 10)
  • escape (defaults to TRUE)
  • table.cap
library(knitr)

# useful function for options
`%||%` <- function(l, r) {
  if (is.null(l)) r else l
}

# super-customised table printing ----
knit_print.data.frame <- function (x, options, ...) {
  # get options
  digits <- options$digits %||% getOption("digits")
  rownames <- options$rownames %||% FALSE
  pageLength <- options$pageLength %||% 10 
  escape <- options$escape %||% TRUE
  caption <- options$table.cap 
  
  # use DT for longer tables in html
  if (nrow(x) > pageLength & knitr::is_html_output()) {
    numeric_cols <- sapply(x, is.numeric) |> which() |> names()
    dt <- DT::datatable(x, 
                        rownames = rownames,
                        caption = caption,
                        escape = escape,
                        width = "100%",
                        height = "auto",
                        options = list(pageLength = pageLength),
                        selection = "none")
    if (length(numeric_cols) > 0) {
      dt <- DT::formatRound(dt, 
                            columns = numeric_cols,
                            digits = digits)
    }
    knitr::knit_print(dt, options)
  } else {
    # use kableExtra::kable for PDFs or shorter tables
    k <- kableExtra::kable(x, 
                      digits = digits, 
                      row.names = rownames, 
                      caption = caption,
                      escape = escape) |>
      kableExtra::kable_styling(
        full_width = options$full_width,
        bootstrap_options = c("striped", "hover")
      )
    
    if (knitr::is_html_output()) {
        k <- c("<div class=\"kable-table\">", k, "</div>") |>
          paste(collapse = "\n")
    }
    
    knitr::asis_output(k)
  }
}
registerS3method("knit_print", "data.frame", knit_print.data.frame)

Test custom df_print

Make data.frame and tbl_df object with 5 and 26 rows.

df5 <- data.frame(x = rnorm(5), y = LETTERS[1:5])
df26 <- data.frame(x = rnorm(26), y = LETTERS)
tbl5 <- tibble::tibble(x = rnorm(5), y = LETTERS[1:5])
tbl26 <- tibble::tibble(x = rnorm(26), y = LETTERS)

Should be displayed with kableExtra::kable().

df5
x y
-0.6516320 A
0.5748103 B
-0.2814253 C
0.4269321 D
-0.8323578 E

Should be displayed with DT::datatable().

df26

Should be displayed with kableExtra::kable()

tbl5
x y
-0.9567718 A
0.1482874 B
-0.3381620 C
-0.1308482 D
-0.8651306 E

Should be displayed with DT::datatable()

tbl26

Option Tests

Testing options in the r chunk header.

Set the number of digits to display in numeric columns. Defaults to getOption("digits").

# digits = 3
tbl5
x y
-0.957 A
0.148 B
-0.338 C
-0.131 D
-0.865 E
# digits = 4
tbl26

rownames are FALSE by default

# rownames = TRUE
tbl5
x y
1 -0.9567718 A
2 0.1482874 B
3 -0.3381620 C
4 -0.1308482 D
5 -0.8651306 E
# rownames = TRUE
tbl26

Table captions.

tbl5
This is my table caption for a tibble with 5 rows
x y
-0.9567718 A
0.1482874 B
-0.3381620 C
-0.1308482 D
-0.8651306 E
tbl26

Set the page length for DT, if the table is <= to that, will display as kable.

# pageLength = 3, so should be a DT
tbl5
# pageLength = 30, so should be a kable
tbl26
x y
-0.4356147 A
-1.3184376 B
-0.9926614 C
-0.3951119 D
0.3668848 E
2.0449062 F
1.4734182 G
1.9424873 H
1.3329930 I
0.3562878 J
1.1314351 K
1.4886727 L
1.0288225 M
-0.2596033 N
-1.2021970 O
-1.5940632 P
1.9479486 Q
-0.2073134 R
-0.2618764 S
-0.5530543 T
-0.2590854 U
0.6115439 V
1.1033557 W
-0.2893176 X
-2.2715219 Y
0.4267168 Z

escape is TRUE by default. Set to FALSE to use html or latex in tables.

# escape = FALSE
tibble::tibble(styles = c("<i>italics</i>", "<b>bold</b>"))
styles
italics
bold
# escape = FALSE
tibble::tibble(styles = rep(c("<i>italics</i>", "<b>bold</b>"), 10))

For kable only, defaults to TRUE for html and FALSE for pdf.

# full_width = TRUE
tbl5
x y
-0.9567718 A
0.1482874 B
-0.3381620 C
-0.1308482 D
-0.8651306 E
# full_width = FALSE
tbl5
x y
-0.9567718 A
0.1482874 B
-0.3381620 C
-0.1308482 D
-0.8651306 E