---
title: "Design Principles, Comparisons and Limitations"
author: "David Hugh-Jones"
date: '`r Sys.Date()`'
output:
  html_document: default
vignette: >
  %\VignetteIndexEntry{Design Principles, Comparisons and Limitations}  
  %\VignetteEncoding{UTF-8}
  %\VignetteEngine{knitr::rmarkdown}  
---


This document briefly describes the design of [huxtable](https://hughjonesd.github.io/huxtable/), 
and compares it with other R packages for
creating tables. A current version is on the web in
[HTML](https://hughjonesd.github.io/huxtable/design-principles.html) or
[PDF](https://hughjonesd.github.io/huxtable/design-principles.pdf) formats.

## Design principles

I wrote this package because I wanted a simple way to create tables in my LaTeX
documents. At the same time, I wanted to be able to output HTML or Markdown for
use in RStudio. And, I wanted to be able to edit tables intuitively using
standard R features. My typical use case is creating tables of regression
outputs, but I also wanted to be able to represent arbitrary data, like a table
of descriptive statistics or of plain text.

The idea behind huxtable is to store data in a normal data frame, along with
properties that describe how to display the data, at cell, column, row or table
level. Operations on the data frame work as normal, and they also affect the
display properties. Then, the data can be output in an appropriate format. At
the moment, those formats are LaTeX, HTML, Markdown, Word/Excel/Powerpoint, RTF
and on-screen pretty printing. More could be added.

Another design choice was to have separate functions per feature. Many existing
packages use a single function with a large number of options. For instance,
`print.xtable` in the `xtable` package has 34 options, and `texreg` in the
`texreg` package has 41. Having one function per feature should make life easier
for the end user. It should also lead to clearer code: each function starts with
a valid huxtable, changes one thing, and returns a valid huxtable.

The output formats are very different, and decisions have to be made as to what
any package will support. My background is more in HTML. This is reflected in
some of the huxtable properties, like per-cell borders and padding. The package
tries to keep output reasonably similar between LaTeX and HTML, but there are
inevitably some differences and limitations. For Markdown and on-screen output,
obviously, only a few basic properties are supported.

The package makes no attempt to output beautiful HTML or LaTeX source code. In
fact, in the case of LaTeX, it's pretty ugly. The approach is "do what it takes
to get the job done".

## Comparing Huxtable With Other Packages

When I first wrote this vignette there were many competing packages to create
LaTeX and HTML tables. There still are, but in my opinion, the field of sensible
modern choices has narrowed down to four:

* huxtable;
* [flextable](https://davidgohel.github.io/flextable/index.html);
* [gt](https://gt.rstudio.com/);
* [kableExtra](https://haozhu233.github.io/kableExtra/).

Here's what I think of these:

* `huxtable` has the widest range of outputs, including HTML, LaTeX, RTF, markdown
  and Word (via flextable). It is very customizable. Its model
  is drawn from HTML, which can be tricky when outputting LaTeX. It aims
  to give you fine-grained control over formatting, at cell level wherever possible.
* David Gohel's `flextable` package started off as a way of producing Word and
  Powerpoint tables. It can also output markdown tables for use in rmarkdown
  documents. Recently it gained the ability to create PDFs using the 
  [pagedown](https://github.com/rstudio/pagedown) package. Rather than 
  outputting LaTeX, this uses paged HTML. In my view this is a fabulous idea, 
  since LaTeX is a 1980s leftover that needs to die. But, if you need LaTeX, 
  then it won't help. On the other hand, `huxtable` uses `flextable` to produce 
  Word output, so if you only need Word, you might as well go to the source.
* RStudio's `gt` package is powerful and has a big name behind it. As yet it
  only produces HTML, but PDFs are on the agenda. It aims for more convenience
  than control, with included functions for many standard formatting options.
* `kableExtra` is a simple set of tweaks for the `knitr::kable()` function. I am
  not a huge fan of the internal design, but it produces nice output and has
  a helpful website.

The original table of competing packages is below for historical reference, but 
it has not been updated.

```{r, echo = FALSE}

suppressPackageStartupMessages(library(huxtable))
is_latex <- guess_knitr_output_format() == 'latex'

comp <- read.csv('comparison.csv', stringsAsFactors = FALSE, header = FALSE)

ch <- as_hux(comp, add_colnames = FALSE)
bold(ch)[1,] <- TRUE
bottom_border(ch)[1,] <- 1
subsections <- ch[[1]] %in% c('HTML output', 'LaTeX output', 'Other features', 'Other formats', 'Notes')
top_border(ch)[subsections, ] <- 1
bold(ch)[subsections, 1] <- TRUE
italic(ch)[subsections, 1] <- TRUE
background_color(ch)[, seq(3, ncol(ch), 2)] <- grey(.95)
background_color(ch)[, 2] <- 'lightpink'
rotation(ch)[1,] <- 270
valign(ch)[1,] <- 'middle'
align(ch)[-1, -1] <- 'center'
ch <- set_all_padding(ch, -1, everywhere, 0)

ch <- rbind(ch, rep('', ncol(ch)))
last <- nrow(ch)
ch[last, 1] <- 'A (Y) means that there is limited support for the feature. 
                    For example, multirow cells may only be supported in headers, or only horizontal
                    border lines may work.'
font_size(ch)[last, 1] <- 10
colspan(ch)[last, 1]   <- ncol(ch)
bold(ch)[last, 1]      <- FALSE
italic(ch)[last, 1]    <- FALSE
bottom_border(ch)[last, 1] <- 2
wrap(ch) <- TRUE

if (is_latex) {
  row_height(ch) <- c('20pt', rep('10pt', nrow(ch) - 1))
  col_width(ch) <- c('120pt', rep('36pt', ncol(ch) - 1))
  height(ch) <- 0.95 
  position(ch) <- 'left'
  font_size(ch) <- 10
  font_size(ch)[c(last - 1, last), 1] <- 8
  ch1 <- ch[, 1:8]
  ch2 <- ch[, c(1, 9:ncol(ch))]
  width(ch1) <- 1
  width(ch2) <- 1
  caption(ch1) <- 'Comparison table, part 1'
  caption(ch2) <- 'Comparison table, part 2'
} else {
  width(ch) <- '700pt'
  row_height(ch) <- c('80pt', rep('14pt', nrow(ch) - 1))
  col_width(ch) <- c('60pt', rep('30pt', ncol(ch) - 1))
}

if (! is_latex) ch
if (is_latex) ch1
if (is_latex) ch2

```
