---
title: "Introduction to Huxtable"
author: "David Hugh-Jones"
date: '`r Sys.Date()`'
output:
  pdf_document:
    includes:
      in_header: placeins-header.tex
    toc: yes
    toc_depth: 2
  html_document:
    toc: yes
    toc_depth: 2
vignette: >
  %\VignetteIndexEntry{Introduction to Huxtable}   
  %\VignetteEncoding{UTF-8}
  %\VignetteEngine{knitr::rmarkdown}   
---


```{r setup, echo = FALSE, warning = FALSE, message = FALSE}

library(knitr)
library(dplyr)
library(huxtable)

is_latex <- guess_knitr_output_format() == 'latex'
# is_latex <- TRUE
knitr::knit_hooks$set(
  barrier = function(before, options, envir) {
    if (! before && is_latex) knitr::asis_output('\\FloatBarrier')
  }
)

if (is_latex) knitr::opts_chunk$set(barrier = TRUE)

```


```{r, echo = FALSE}
huxtable::hux_logo(latex = is_latex)
```


```{r, eval = FALSE, echo = FALSE}
# PLAN
# Make single document work in notebook format (maybe with minimal changes)
# Installation
# Dplyr examples
# Examples with where and friends
# Different kinds of output
# Cookbook?
# Limitations

```


# Introduction

## About this document

This is the introductory vignette for the R package 'huxtable', version `r packageVersion('huxtable')`. A current
version is available on the web in [HTML](https://hughjonesd.github.io/huxtable/huxtable.html) or 
[PDF](https://hughjonesd.github.io/huxtable/huxtable.pdf) format.

## Huxtable

Huxtable is a package for creating *text tables*. It is powerful, but easy to use. It is meant to be a
replacement for packages like xtable, which is useful but not always very user-friendly. Huxtable's features
include:

* Export to LaTeX, HTML, Word and Markdown
* Easy integration with knitr and rmarkdown documents
* Multirow and multicolumn cells
* Fine-grained control over cell background, spacing, alignment, size and borders
* Control over text font, style, size, colour, alignment, number format and rotation
* Table manipulation using standard R subsetting, or dplyr functions like `filter` and `select`
* Easy conditional formatting based on table contents
* Quick table themes
* Automatic creation of regression output tables with the `huxreg` function

We will cover all of these features below.

## Installation

If you haven't already installed huxtable, you can do so from the R command line:

```{r, eval = FALSE}
install.packages('huxtable')
```


## Getting started

A huxtable is a way of representing a table of text data in R. You already know that R can represent a
table of data in a data frame. For example, if `mydata` is a data frame, then `mydata[1, 2]` represents the
the data in row 1, column 2, and `mydata$start_time` is all the data in the column called `start_time`.

A huxtable is just a data frame with some extra properties. So, if `myhux` is a huxtable, then `myhux[1, 2]`
represents the data in row 1 column 2, as before. But this cell will also have some other properties - for
example, the font size of the text, or the colour of the cell border.

To create a table with huxtable, use the function `huxtable`, or `hux` for short. This works very much like
`data.frame`.

```{r}
library(huxtable)
ht <- hux(
        Employee     = c('John Smith', 'Jane Doe', 'David Hugh-Jones'), 
        Salary       = c(50000, 50000, 40000),
        add_colnames = TRUE
      )
```


If you already have your data in a data frame, you can convert it to a huxtable with `as_hux`.

```{r}
data(mtcars)
car_ht <- as_hux(mtcars)
```


If you look at a huxtable in R, it will print out a simple representation of the data. Notice that we've added the
column names to the data frame itself, using the `add_colnames` argument to `hux`. We're going to print them out, so they need to be part of the actual table. **NB:** This means that row 1 of your data will be row 2 of the huxtable, and the
column names of your data will be the new row 1.

```{r, results = 'markup'}
print_screen(ht)
```

To print a huxtable out using LaTeX or HTML, just call `print_latex` or `print_html`. In knitr documents, like this one,
you can simply evaluate the hux. It will know what format to print itself in.

```{r}
ht
```


# Changing the look and feel

## Huxtable properties

The default output is a very plain table. Let's make it a bit smarter. We'll make the table headings bold, draw a line under the header row, right-align the second column, and add some horizontal space to the cells. 

To do this, we need to set cell level properties. You set properties by assigning to the property name, just as you assign `names(x) <- new_names` in base R. The following commands assign the value 10 to the `right_padding` and
`left_padding` properties, for all cells in `ht`:

```{r}
right_padding(ht) <- 10
left_padding(ht)  <- 10
```

Similarly, we can set the `number_format` property to change how numbers are displayed in 
cells:

```{r}
number_format(ht) <- 2    # 2 decimal places
```

To assign properties to just some cells, you use subsetting, just as in base R. So, to make the first row of the
table **bold** and give it a bottom border, we do:

```{r}
bold(ht)[1,]          <- TRUE
bottom_border(ht)[1,] <- 1
```


And to right-align the second column, we do:

```{r}
align(ht)[,2] <- 'right'
```


We can also specify a column by name:

```{r}
align(ht)[,'Salary'] <- 'right'
```


After these changes, our table looks smarter:

```{r}
ht
```


So far, all these properties have been set at cell level. Different cells can have different alignment, text formatting
and so on. By contrast, `caption` is a table-level property. It only takes one value, which sets a table caption.

```{r}

caption(ht) <- 'Employee table'
ht

```


As well as cell properties and table properties, there is also one row property, row heights, and one column
property, column widths.

The table below shows a complete list of properties. Most properties work the same for LaTeX and HTML, though there are
some exceptions. 

```{r, echo = FALSE}
sides <- c('left_', 'right_', 'top_', 'bottom_')
props <- list()
props[['Cell_Text']] <- sort(c('font', 'text_color', 'wrap', 'bold', 'italic', 'font', 'font_size', 'na_string', 'pad_decimal', 'escape_contents', 'number_format', 'rotation'))

props[['Cell']] <- sort(c('align', 'valign', 'rowspan', 'colspan', 'background_color', paste0(sides, 'border'),
      paste0(sides, 'border_color'), paste0(sides, 'padding')))
props[['Row']]    <- 'row_height'
props[['Column']] <- 'col_width'
props[['Table']]  <- sort(c('width', 'height', 'position', 'caption', 'caption_pos', 'tabular_environment', 'label', 'latex_float'))

maxl <- max(sapply(props, length))
props <- lapply(props, function(x) c(x, rep('', maxl - length(x))))

ss_font <- if (guess_knitr_output_format() == 'latex') 'cmhv' else 'arial'

prop_hux <- hux(as.data.frame(props))                     %>% 
      add_colnames                                        %>% 
      {foo <- .; foo[1,] <- gsub('_', ' ', foo[1,]); foo} %>% 
      set_font(-1, everywhere, ss_font)                   %>% 
      set_bold(1, everywhere, TRUE)                       %>% 
      set_width(0.9)                                      %>% 
      set_background_color(everywhere, evens, grey(.9))   %>% 
      set_left_border(everywhere, 1, 1)                   %>% 
      set_right_border(everywhere, final(), 1)            %>% 
      set_top_border(1, everywhere, 1)                    %>% 
      set_bottom_border(1, everywhere, 1)                 %>% 
      set_bottom_border(final(), everywhere, 1)           %>% 
      set_top_padding(2)                                  %>% 
      set_bottom_padding(4)                               %>% 
      set_caption('Huxtable properties')                  %>% 
      set_position('left') %>% 
      set_col_width(c(.2, .25, .15, .15, .25))

prop_hux
```


## Pipe style syntax

If you prefer to use the `magrittr` pipe operator (`%>%`), then you can use `set_*` functions. These have the same
name as the property, with `set_` prepended. They return the modified huxtable, so you can chain them together like 
this:

```{r}

library(dplyr)
hux(
        Employee     = c('John Smith', 'Jane Doe', 'David Hugh-Jones'), 
        Salary       = c(50000, 50000, 40000),
        add_colnames = TRUE
      )                               %>% 
      set_bold(1, 1:2, TRUE)          %>% 
      set_bottom_border(1, 1:2, 1)    %>%
      set_align(1:4, 2, 'right')      %>%
      set_right_padding(10)           %>%
      set_left_padding(10)            %>% 
      set_caption('Employee table')
  

```


`set_*` functions for cell properties are called like this: `set_xxx(ht, row, col, value)` or like this: 
`set_xxx(ht, value)`. If you use the second form, then the value is set for all cells. 
`set_*` functions for table properties are always called like `set_xxx(ht, value)`. We'll learn more about this interface in a moment.

There are also four useful convenience functions:

* `set_all_borders` sets left, right, top and bottom borders for selected cells;
* `set_all_border_colors` sets left, right, top and bottom border colors;
* `set_all_padding` sets left, right, top and bottom padding (the amount of space between the content and the border);
* `set_outer_borders` sets the outer borders of a square group of cells.

## Getting properties

To get the current properties of a huxtable, just use the properties function without the left arrow:

```{r, results = 'markup'}
italic(ht)
position(ht)
```


As before, you can use subsetting to get particular rows or columns:

```{r, results = 'markup'}
bottom_border(ht)[1:2,]
bold(ht)[,'Salary']
```



# Editing content

## Standard subsetting

You can subset, sort and generally data-wrangle a huxtable just like a normal data frame. Cell and 
table properties will be carried over into subsets.

```{r}
# Select columns by name:
cars_mpg <- car_ht[, c('mpg', 'cyl', 'am')] 
# Order by number of cylinders:
cars_mpg <- cars_mpg[order(cars_mpg$cyl),]

cars_mpg <- cars_mpg                          %>% 
      huxtable::add_rownames(colname = 'Car') %>% 
      huxtable::add_colnames()

cars_mpg[1:5,]
```


## Using dplyr with huxtable

You can also use `dplyr` functions:


```{r}
car_ht <- car_ht                                          %>%
      huxtable::add_rownames(colname = 'Car')             %>%
      slice(1:10)                                         %>% 
      select(Car, mpg, cyl, hp)                           %>% 
      arrange(hp)                                         %>% 
      filter(cyl > 4)                                     %>% 
      rename(MPG = mpg, Cylinders = cyl, Horsepower = hp) %>% 
      mutate(kml = MPG/2.82)                               


car_ht <- car_ht                               %>% 
      set_number_format(1:7, 'kml', 2)         %>% 
      set_col_width(c(.35, .15, .15, .15, .2)) %>% 
      set_width(.6)                            %>% 
      huxtable::add_colnames() 

car_ht
```


In general it is a good idea to prepare your data first, before styling it. For example, it was easier to sort the `cars_mpg` data by cylinder, before adding column names to the data frame itself.

## Functions to insert rows, columns and footnotes

Huxtable has three convenience functions for adding a row or column to your table: `insert_row`, `insert_column`
and `add_footnote`. 

`insert_row` and `insert_column` let you add a single row or column. The `after` parameter specifies where in the table
to do the insertion, i.e. after what row or column number.

`add_footnote` adds a single row at the bottom, which spans the whole table and has a border above.

```{r}
ht <- insert_row(ht, 'Hadley Wickham', '100000', after = 3)
ht <- add_footnote(ht, 'DHJ deserves a pay rise')
ht
```

# More formatting 


## Number format

You can change how huxtable formats numbers using `number_format`. Set `number_format` to a number of decimal places 
(for more advanced options, see the help files). This affects all numbers, or number-like substrings within your cells.

```{r}
pointy_ht <- hux(c('Do not pad this.', 11.003, 300, 12.02, '12.1 **'))
pointy_ht <- set_all_borders(pointy_ht, 1)
width(pointy_ht) <- .2

number_format(pointy_ht) <- 3
pointy_ht
```

You can also align columns by decimal places. If you want to do this for a cell, just set the `pad_decimal` property
to '.' (or whatever you use for a decimal point). 

```{r}
pad_decimal(pointy_ht)[2:5, ] <- '.' # not the first row
align(pointy_ht) <- 'right'
pointy_ht
```

There is currently no true way to align cells by the decimal point in HTML, and only limited possibilities in TeX, so `pad_decimal` works by right-padding cells with spaces. The output may look better if you use a fixed width font.

## Escaping HTML or LaTeX

By default, HTML or LaTeX code will be escaped:

```{r}
code_ht <- if (is_latex) hux(c('Some maths', '$a^b$')) else 
      hux(c('Copyright symbol', '&copy;'))
code_ht
```

To avoid this, set the `escape_contents` property to `FALSE`.

```{r}
escape_contents(code_ht)[2, 1] <- FALSE
code_ht
```


## Width and cell wrapping

You can set table widths using the `width` property, and column widths using the `col_width` property. If you use
numbers for these, they will be interpreted as proportions of the table width (or for `width`, a proportion of the
width of the surrounding text). If you use character vectors, they must be valid CSS or LaTeX widths. The only
unit both systems have in common is `pt` for points. 

```{r}
width(ht) <- 0.35
col_width(ht) <- c(.7, .3)
ht
```


It is best to set table width explicitly, then set column widths as proportions.

By default, if a cell contains long contents, it will be stretched. Use the `wrap` property to allow cell contents
to wrap over multiple lines:

```{r}
ht_wrapped <- ht
ht_wrapped[5, 1] <- 'David Arthur Shrimpton Hugh-Jones'
wrap(ht_wrapped) <- TRUE
ht_wrapped
```


## Adding row and column names

Just like data frames, huxtables can have row and column names. Often, we want to add these to the final table.
You can do this using either the `add_colnames`/`add_rownames` arguments to `as_huxtable`, or the
`add_colnames()`/`add_rownames()` functions. (Note that earlier versions of `dplyr` used to have functions with the
same name.)

```{r}
as_hux(mtcars[1:4, 1:4])                           %>% 
      huxtable::add_rownames(colname = 'Car name') %>% 
      huxtable::add_colnames()
```


## Column and row spans

Huxtable cells can span multiple rows or columns, using the `colspan` and `rowspan` properties.

```{r}
cars_mpg <- cbind(car_type = rep("", nrow(cars_mpg)), cars_mpg)
cars_mpg$car_type[1] <- 'Four cylinders'
cars_mpg$car_type[13] <- 'Six cylinders'
cars_mpg$car_type[20] <- 'Eight cylinders'
rowspan(cars_mpg)[1, 1] <- 12
rowspan(cars_mpg)[13, 1] <- 7
rowspan(cars_mpg)[20, 1] <- 14

cars_mpg <- rbind(c('', 'List of cars', '', '', ''), cars_mpg)
colspan(cars_mpg)[1, 2] <- 4
align(cars_mpg)[1, 2] <- 'center'

# a little more formatting:

cars_mpg <- set_all_padding(cars_mpg, 2)
cars_mpg <- set_all_borders(cars_mpg, 1)
valign(cars_mpg)[1,] <- 'top'
col_width(cars_mpg) <- c(.4 , .3 , .1, .1, .1)
number_format(cars_mpg)[, 4:5] <- 0
bold(cars_mpg)[1:2, ] <- TRUE
bold(cars_mpg)[, 1] <- TRUE
if (is_latex) font_size(cars_mpg) <- 10
cars_mpg
```


## Quick themes

Huxtable comes with some predefined themes for formatting.

```{r}
theme_striped(cars_mpg[14:20,], stripe = 'bisque1', header_col = FALSE, header_row = FALSE)
```


# Selecting rows, columns and cells


## Row and column functions

If you use the `set_*` style functions, huxtable has some convenience functions for selecting rows and columns.

To select all rows, or all columns, use `everywhere` in the row or column specification. To select just even or odd-numbered rows or columns, use `evens` or `odds`. To select the last `n` rows or columns, use `final(n)`.
To select every *n*th row, use `every(n)` and to do this starting from row *m* use `every(n, from = m)`.

With these functions it is easy to add striped backgrounds to tables:

```{r}
car_ht                                                 %>% 
      set_background_color(evens, everywhere, 'wheat') %>% 
      set_background_color(odds, everywhere, grey(.9)) %>% 
      set_bold(1, everywhere, TRUE)
```


Of course you could also just do `1:nrow(car_ht)`, but, in the middle of a dplyr pipe, you may not know exactly
how many rows or columns you have. Also, these functions make your code easy to read.

You can also use `dplyr` functions like `starts_with()`, `contains()`, and `matches()` to specify columns by column 
name. For a full list of these functions, see `?select_helpers`.

```{r}
car_ht %>% set_background_color(everywhere, starts_with('C'), 'orange')
car_ht %>% set_italic(everywhere, matches('[aeiou]'), TRUE)
```

Note that unlike in `dplyr`'s `select` function, you have to specify rows as well as columns.

Lastly, remember that you can set a property for every cell by simply omitting the `row` and `col` arguments, like this:
`set_background_color(ht, 'orange')`.


## Conditional formatting

You may want to apply conditional formatting to cells, based on their contents. Suppose we want to display a table of correlations, and to highlight ones which are significant. We can use the `where()` function to select those cells.

```{r}
library(psych)
data(attitude)
att_corr <- corr.test(as.matrix(attitude))

att_hux <- as_hux(att_corr$r)                                           %>% 
      # selects cells with p < 0.05:
      set_background_color(where(att_corr$p < 0.05), 'yellow')          %>% 
      # selects cells with p < 0.01:
      set_background_color(where(att_corr$p < 0.01), 'orange')          %>% 
      set_text_color(where(row(att_corr$r) == col(att_corr$r)), 'grey') 


att_hux <- att_hux                                                      %>% 
      huxtable::add_rownames()                                          %>% 
      huxtable::add_colnames()                                          %>%
      set_caption('Correlations in attitudes among 30 departments')     %>% 
      set_bold(1, everywhere, TRUE)                                     %>% 
      set_bold(everywhere, 1, TRUE)                                     %>% 
      set_all_borders(1)                                                %>%
      set_number_format(2)                                              %>% 
      set_position('left')

att_hux

```

We have now seen three ways to call `set_*` functions in huxtable:

* With four arguments, like `set_property(hux_object, rows, cols, value)`;
* With two arguments, like `set_property(hux_object, value)` to set a property everywhere;
* With three arguments, like `set_property(hux_object, where(condition), value)` to set a property for specific cells.

The second argument of the three-argument version must return a 2-column matrix. Each row of the matrix gives one cell.
`where()` does this for you: it takes a logical matrix argument and returns the rows and columns where a condition is
`TRUE`. It's easiest to show this with an example:

```{r}
m <- matrix(c('dog', 'cat', 'dog', 'dog', 'cat', 'cat', 'cat', 'dog'), 4, 2)
m
where(m == 'dog') # m is equal to 'dog' in cells (1, 1), (3, 1), (4, 1) and (4, 2):
```

`set_*` functions have one more optional argument, the `byrow` argument, which is `FALSE` by default. If you set a
single pattern for many cells, you may want the pattern to fill the matrix by column or by row. The default fills the
pattern in going down columns. If you set `byrow = TRUE`, the pattern goes across rows instead. (This is a bit
confusing: typically, `byrow = TRUE` means that the *columns* will all look the same. But it works the same way as the
`byrow` argument to `matrix()`.)

```{r}

color_demo <- matrix('text', 7, 7)
rainbow <- c('red', 'orange', 'yellow', 'green', 'blue', 'turquoise', 'violet')
color_demo <- as_hux(color_demo)                  %>% 
      set_text_color(rainbow)                     %>% # text rainbow down columns
      set_background_color(rainbow, byrow = TRUE) %>% # background color rainbow along rows
      set_all_borders(1)                          %>% 
      set_all_border_colors('white')
color_demo

```



# Creating a regression table

A common task for scientists is to create a table of regressions. The function `huxreg` does this for you. Here's a quick example:

```{r}
data(diamonds, package = 'ggplot2')

lm1 <- lm(price ~ carat, diamonds)
lm2 <- lm(price ~ depth, diamonds)
lm3 <- lm(price ~ carat + depth, diamonds)

huxreg(lm1, lm2, lm3)
```

For more information see the `huxreg` vignette, available online in
[HTML](https://hughjonesd.github.io/huxtable/huxreg.html) or [PDF](https://hughjonesd.github.io/huxtable/huxreg.pdf) or
in R via `vignette('huxreg')`.

# Output to different formats

If you use knitr and rmarkdown in RStudio, huxtable objects should automatically display in the appropriate format 
(HTML or LaTeX). You need to have some LaTeX packages installed for huxtable to work. To find out what these are,
you can call `report_latex_dependencies()`. This will print out and/or return a set of `usepackage{...}` statements.
If you use Sweave or knitr without rmarkdown, you can use this function in your LaTeX preamble to load the packages
you need.

Rmarkdown exports to Word via Markdown. You can use huxtable to do this, but since Markdown tables are rather basic,
a lot of formatting will be lost. If you want to create Word or Powerpoint documents directly, install the 
[flextable package](https://cran.r-project.org/package=flextable) from CRAN. You can then convert your huxtable objects
to `flextable` objects and include them in Word or Powerpoint documents. Almost all formatting should work. See the `flextable` and `officer` documentation and `?as_flextable` for more details. 

Similarly, to create formatted reports in Excel, install the 
[openxlsx package](https://cran.r-project.org/package=openxlsx). You can then use `as_Workbook` to convert your 
huxtables to Workbook objects, and save them using `openxlsx::saveWorkbook`.

Sometimes you may want to select how huxtable objects are printed by default. For example, in an RStudio notebook
(a .Rmd document with `output_format = html_notebook`), huxtable can't automatically work out what format to use, as of
the time of writing. You can set it manually using `options(huxtable.print = print_notebook)` which prints out
HTML in an appropriate format. 

Lastly, you can print a huxtable on screen using `print_screen`. Borders, column and row spans and cell alignment are
shown. If the [crayon](https://cran.r-project.org/package=crayon) package is installed, and your terminal or R
IDE supports it, border, text and background colours are also displayed.

```{r, results = 'markup'}
print_screen(ht)
```


If you need to output to another format, file an [issue request](https://github.com/hughjonesd/huxtable) on Github. 

## Quick output commands

Sometimes you quickly want to get your data into a Word, HTML or PDF document. To do this you can use the `quick_docx`,
`quick_html`, `quick_pdf` and `quick_xlsx` functions. These are called with one or more huxtable objects, or objects
which can be turned into a huxtable such as data frames. A new document of the appropriate type will be created. By
default the file will be in the current directory under the name e.g. `huxtable-output.pdf`. If the file already exists,
you'll be asked to confirm the overwrite. For non-interactive use, you must specify a filename yourself explicitly --
this keeps you from accidentally trashing your files.

```{r, eval = FALSE}
quick_pdf(mtcars) 
quick_pdf(mtcars, file = 'motorcars data.pdf')
```

# End matter

For more information, see the [website](https://hughjonesd.github.io/huxtable) or 
[github](https://github.com/hughjonesd/huxtable).
