# HTML Tables

#### Duncan Murdoch

#### January 17, 2016

This short R Markdown document illustrates how to use `tables` in HTML.

## Initializing

First, you need to load `tables`. Packages that it uses print banner messages, so you’ll usually want to set a chunk option of `message=FALSE`.

    library(tables)

The table is now constructed in the usual way.

    X <- rnorm(125, sd=100)
    Group <- factor(sample(letters[1:5], 125, rep=TRUE))
    tab <- tabular( Group ~ (N=1)+Format(digits=2)*X*((Mean=mean) + Heading("Std Dev")*sd) )

In an R Markdown document, you don’t want each table to output the HTML document header, so turn off those options:

    table_options(htmloptions(head=FALSE))

## Inserting a Table

There are two ways to insert a table into a knitr/rmarkdown document. Since tables version 0.8.4, you can just print the object, and it will be automatically formatted according to the current `table_options()`:

    tab

|  | X
--- | --- | ---
Group | N | Mean | Std Dev
a | 21 | 45.0 | 97.7
b | 28 | -24.6 | 121.5
c | 29 | 57.0 | 93.7
d | 28 | 22.1 | 111.7
e | 19 | 4.9 | 59.3

The previous behaviour required an explicit call to the `toHTML()` function, and knitr option `results = 'asis'` for the chunk. To require the older method, use `table_options(knit_print = FALSE)`:

    table_options(knit_print = FALSE)
    tab        # This chunk uses the default results = 'markup'

    ##
    ##           X
    ##  Group N  Mean  Std Dev
    ##  a     21  45.0  97.7
    ##  b     28 -24.6 121.5
    ##  c     29  57.0  93.7
    ##  d     28  22.1 111.7
    ##  e     19   4.9  59.3

    toHTML(tab)  # This chunk uses results = 'asis'

|  | X
--- | --- | ---
Group | N | Mean | Std Dev
a | 21 | 45.0 | 97.7
b | 28 | -24.6 | 121.5
c | 29 | 57.0 | 93.7
d | 28 | 22.1 | 111.7
e | 19 | 4.9 | 59.3

In either case, some styling information needs to be included in the document. Ideally this should be in the header, but it can be inserted anywhere by calling `writeCSS` with `results = 'asis'`:

    writeCSS()

## Improving the Look

The default justification makes the columns of numbers look messy. You can set the justification to the right, but the headers look wrong:

    table_options(htmloptions(head = FALSE, justification = "r", knit_print = TRUE))
    tab

|  | X
--- | --- | ---
Group | N | Mean | Std Dev
a | 21 | 45.0 | 97.7
b | 28 | -24.6 | 121.5
c | 29 | 57.0 | 93.7
d | 28 | 22.1 | 111.7
e | 19 | 4.9 | 59.3

The best look comes with the `pad = TRUE` option. This adds nonbreaking spaces around the numbers so that centering looks good. It also changes the hyphens to proper minus signs:

    table_options(htmloptions(head = FALSE, justification = "c", pad = TRUE))
    tab

|  | X
--- | --- | ---
Group | N | Mean | Std Dev
a | 21 | 45.0 | 97.7
b | 28 | −24.6 | 121.5
c | 29 | 57.0 | 93.7
d | 28 | 22.1 | 111.7
e | 19 | 4.9 | 59.3

Unfortunately, if you cut this table and paste it into a spreadsheet, the spaces and minus signs probably won’t be understood. I don’t know how to get everything we want :-(.

## Fine tuning

This document uses the default CSS from `table_options()$CSS`. If you are producing an `html_document`, it should be okay. It does not look quite right in a `slidy_presentation`, and is no good at all in an `ioslides_presentation`. Furthermore, you might not agree with my design choices.

In any of these cases, you should substitute your own CSS. You will need to modify the default one, and can use it as the `CSS` argument to `writeCSS()`, or set it as a new default in `table_options()`.

Here is the default setting:

    <style>
    #ID .Rtable thead, .Rtable .even {
      background-color: inherit;
    }
    #ID .left   { text-align:left; }
    #ID .center { text-align:center; }
    #ID .right  { text-align:right; }
    #ID .Rtable, #ID .Rtable thead {
      border-collapse: collapse;
      border-style: solid;
      border-width: medium 0;
      border-color: inherit;
    }
    #ID .Rtable th, #ID .Rtable td {
      padding-left: 0.5em;
      padding-right: 0.5em;
      border-width: 0;
    }
    </style>

Note that the `#ID` values will be replaced with the `id` string given in `writeCSS()`, and `toHTML()` has a corresponding argument to allow you to make changes for one specific table. If you are using the newer form of display with `table_options(knit_print = TRUE)`, you can get customized display for one table by also using `table_options(doCSS = TRUE)`. For example,

    table_options(CSS =
    "<style>
    #ID .center {
      text-align:center;
      background-color: aliceblue;
    }
    </style>", doCSS = TRUE)
    tab

|  | X
--- | --- | ---
Group | N | Mean | Std Dev
a | 21 | 45.0 | 97.7
b | 28 | −24.6 | 121.5
c | 29 | 57.0 | 93.7
d | 28 | 22.1 | 111.7
e | 19 | 4.9 | 59.3

    table_options(doCSS = FALSE)
    tab

|  | X
--- | --- | ---
Group | N | Mean | Std Dev
a | 21 | 45.0 | 97.7
b | 28 | −24.6 | 121.5
c | 29 | 57.0 | 93.7
d | 28 | 22.1 | 111.7
e | 19 | 4.9 | 59.3

## kableExtra support

The kableExtra package contains a large number of functions to customize the look of tables generated by the `knitr::kable()` function. These can also be made to work with tables from this package, using the `toKable()` function. For example,

    library(magrittr)
    library(kableExtra)
    toKable(tab, format="html") %>%
      kable_styling("striped", position = "float_right", full_width = FALSE) %>%
      add_header_above(c("Row Label" = 1, "Statistics" = 3)) %>%
      column_spec(4, color = "red") %>%
      row_spec(1, color = "blue") %>%
      group_rows("Subgroup", 3, 5)

Row Label | Statistics
--- | ---
|  | X
Group | N | Mean | Std Dev
a | 21 | 45.0 | 97.7
b | 28 | −24.6 | 121.5
Subgroup
c | 29 | 57.0 | 93.7
d | 28 | 22.1 | 111.7
e | 19 | 4.9 | 59.3

There are conflicts between the styling options from `kableExtra` and the ones specified in `table_options()$CSS`; some modifications might be needed to make everything work. For instance, the code above requests striping, but that did not show up. Experimentation may be needed!