Site icon R-bloggers

News in htmlTable 2.0

[This article was first published on R – G-Forge, and kindly contributed to R-bloggers]. (You can report issue about the content on this page here)
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.
A short intro to the new features in htmlTable 2.0. The image is a blend based on a CC image by Ken Xu.

The htmlTable 2.0 package was just released on CRAN! It is my most downloaded package with 160 000+ downloads/month and this update is something that I have been wanting to do for a long time. For those of you that never encountered htmlTable it is a package that takes a matrix/data.frame and outputs a nicely formatted HTML table. When I created the package there weren’t that many alternatives and knitr was this new thing that everyone was excited about, magrittr with its ubiquitous %>% pipe had not even entered the scene. The current update should make it easier to streamline table look, separate layout from content and use tidyverse functionality.

Style and theming

The biggest change in how to use the htmlTable is that you have a separate function for adding style to the table. The change is implemented in a non-breaking fashion, i.e. all the old options should work just as before but the new API is encouraged as it simplifies a lot. The new API changes so that instead of all the css.* arguments we now have a separate function that applies these, addHtmlTableStyle and passes them on as an attribute to the htmlTable:

library(htmlTable)
library(magrittr)
options(table_counter = TRUE)

rbind(
  `Group A` = c(20, 5, 380, 95),
  `1` = c(11, 55, 9, 45),
  `2` = c(11, 55, 9, 45)
) %>%
  addHtmlTableStyle(css.rgroup = "-style: italic",
                    css.header = "-weight: normal") %>% 
  htmlTable(header = rep(c("No", "%"), times = 2),
            n.cgroup = list(c(2), c(2, 2)),
            cgroup = list('Super', c("First", "Second")),
            rgroup = c("", "Group B"),
            n.rgroup = 1,
            caption = "A simple htmlTable example with the core components")

As we usually want the same layout for the entire table we can accomplish the same effect for all of our tables using setHtmlTableTheme and the style will be applied to all your tables.

library(glue)
setHtmlTableTheme(css.rgroup = "-style: italic",
                  css.header = "-weight: normal",
                  pos.caption = "bottom")


rbind(
  `Group A` = c(20, 5, 380, 95),
  `1` = c(11, 55, 9, 45),
  `2` = c(11, 55, 9, 45)
) %>%
  htmlTable(header = rep(c("No", "%"), times = 2),
            n.cgroup = list(c(2), c(2, 2)),
            cgroup = list('Super', c("First", "Second")),
            rgroup = c("", "Group B"),
            n.rgroup = 1,
            caption = glue("Same as Table {last} but with general styling and caption positioned at the bottom.",
                           last = tblNoLast()))

There is an option for selecting themes with predefined layouts. In addition to the standard which has the traditional htmlTable look, you also have Google docs and blank. The Google docs is still a work in progress and any help making it as compatible as possible with Google’s Drive document when copy-pasting is much appreciated.

Using tidyverse syntax in tidyHtmlTable

In 2017, Stephen Gragg added the tidyHtmlTable to the package. Since then advances to RStudio has impacted in how we use R and it became obvious that the function should instead of strings as arguments directly accept column names just as defined by tidyselect. The tidyHtmlTable solves one of htmlTable‘s greates weaknesses, the need for calculating the rgroup, tspanner, cgroup arguments and using it with the tidyselect interface is now pure joy:

library(tidyverse)
tribble(
  ~ rowname, ~ `No (First)`, ~ `% (First)`, ~ `No (Second)`, ~ `% (Second)`,
  "Group A",             20,             5,             380,             95,
  "Group B1",            11,            55,               9,             45,
  "Group B2",            11,            55,               9,             45,
) %>%
  pivot_longer(cols = c(starts_with("No"), starts_with("%"))) %>% 
  mutate(group = str_replace(rowname, "Group ([AB]).*", "\\1"),
         rowname = str_replace(rowname, "Group ([AB12]+).*", "\\1"),
         group = if_else(group == rowname, "", group),
         header = str_replace(name, "([^ ]+).*", "\\1"),
         cgroup = str_replace(name, ".*\\(([^)]+)\\)$", "\\1")) %>% 
  tidyHtmlTable(rgroup = group,
                header = header,
                cgroup = cgroup,
                rnames = rowname,
                caption = "A version of the first tables but using the tidyHtmlTable")

A more advanced example on how tidyHtmlTable works with tidyverse we can have a look at the example in the vignette("tidyHtmlTable"):

mtcars %>%
  as_tibble(rownames = "rnames") %>% 
  pivot_longer(names_to = "per_metric", 
               cols = c(hp, mpg, qsec)) %>%
  group_by(cyl, gear, per_metric) %>% 
  summarise(Mean = round(mean(value), 1),
            SD = round(sd(value), 1),
            Min = round(min(value), 1),
            Max = round(max(value), 1),
            .groups = 'drop') %>%
  pivot_longer(names_to = "summary_stat", 
               cols = c(Mean, SD, Min, Max)) %>% 
  ungroup() %>% 
  mutate(gear = paste(gear, "Gears"),
         cyl = paste(cyl, "Cylinders")) %>% 
  arrange(per_metric, summary_stat) %>% 
  addHtmlTableStyle(align = "r") %>% 
  tidyHtmlTable(header = gear,
                cgroup = cyl,
                rnames = summary_stat,
                rgroup = per_metric,
                caption = "A full example of how to apply the tidyverse workflow to generate a table")

When using tidyHtmlTable you can decouple it from htmlTable and provide any table function by supplying the table_fn function.

Options

In htmlTable 2.0 there are plenty of options that have been added. Most of them should start with the prefix “htmlTable.”, e.g “htmlTable.css.tspanner.sep”. While the prefix is useful for reducing the risk of conflicting options between packages, options such as “table_counter” are unchanged in order to avoid unnecessary breaking changes.

NEWS for 2.0

To leave a comment for the author, please follow the link and comment on their blog: R – G-Forge.

R-bloggers.com offers daily e-mail updates about R news and tutorials about learning R and many other topics. Click here if you're looking to post or find an R/data-science job.
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.