732 lines
19 KiB
Plaintext
Raw Normal View History

2025-01-12 00:52:51 +08:00
%\VignetteIndexEntry{xtable Gallery}
%\VignetteDepends{xtable}
%\VignetteKeywords{LaTeX, HTML, table}
%\VignettePackage{xtable}
% !Rnw weave = knitr
% \VignetteEngine{knitr::knitr}
%**************************************************************************
\documentclass{article}
\usepackage[a4paper,height=24cm]{geometry} % geometry first
\usepackage{array}
\usepackage{booktabs}
\usepackage{longtable}
\usepackage{parskip}
\usepackage{rotating}
\usepackage{tabularx}
\usepackage{titlesec}
\usepackage{hyperref} % hyperref last
\titleformat\subsubsection{\bfseries\itshape}{}{0pt}{}
\newcommand\p{\vspace{2ex}}
\newcommand\code[1]{\texttt{#1}}
\newcommand\pkg[1]{\textbf{#1}}
\setcounter{tocdepth}{2}
\begin{document}
\title{The \pkg{xtable} Gallery}
\author{Jonathan Swinton and others}
\maketitle
\tableofcontents
\newpage
\section{Introduction}
This document gives a gallery of tables which can be made using the
\pkg{xtable} package to create \LaTeX\ output. It doubles as a
regression check for the package.
<<include=FALSE>>=
library(knitr)
opts_chunk$set(fig.path='figdir/fig', debug=TRUE, echo=TRUE)
set.seed(1234)
@
The first step is to load the package and set an option for this document.
<<results='asis'>>=
library(xtable)
options(xtable.floating = FALSE)
options(xtable.timestamp = "")
@
\section{Gallery}
\subsection{Data frame}
<<results='asis'>>=
data(tli)
xtable(tli[1:10, ])
@
\subsection{Matrix}
<<results='asis'>>=
design.matrix <- model.matrix(~ sex*grade, data = tli[1:10, ])
xtable(design.matrix, digits = 0)
@
\newpage
\subsection{aov}
<<results='asis'>>=
fm1 <- aov(tlimth ~ sex + ethnicty + grade + disadvg, data = tli)
xtable(fm1)
@
\subsection{lm}
<<results='asis'>>=
fm2 <- lm(tlimth ~ sex*ethnicty, data = tli)
xtable(fm2)
@
\subsubsection{Anova table (one model)}
<<results='asis'>>=
xtable(anova(fm2))
@
\subsubsection{Anova table (two models)}
<<results='asis'>>=
fm2b <- lm(tlimth ~ ethnicty, data = tli)
xtable(anova(fm2b, fm2))
@
\subsubsection{Anova list}
<<aovlist>>=
Block <- gl(8, 4)
A <- factor(c(0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,
0,1,0,1,0,1,0,1,0,1,0,1))
B <- factor(c(0,0,1,1,0,0,1,1,0,1,0,1,1,0,1,0,0,0,1,1,
0,0,1,1,0,0,1,1,0,0,1,1))
C <- factor(c(0,1,1,0,1,0,0,1,0,0,1,1,0,0,1,1,0,1,0,1,
1,0,1,0,0,0,1,1,1,1,0,0))
Yield <- c(101, 373, 398, 291, 312, 106, 265, 450, 106, 306, 324, 449,
272, 89, 407, 338, 87, 324, 279, 471, 323, 128, 423, 334,
131, 103, 445, 437, 324, 361, 302, 272)
aovdat <- data.frame(Block, A, B, C, Yield)
old <- getOption("contrasts")
options(contrasts = c("contr.helmert", "contr.poly"))
(fit <- aov(Yield ~ A*B*C + Error(Block), data = aovdat))
class(fit)
summary(fit)
options(contrasts = old)
@
\p
<<xtableaovlist, results='asis'>>=
xtable(fit)
@
\newpage
\subsection{glm}
<<results='asis'>>=
fm3 <- glm(disadvg ~ ethnicty*grade, data = tli, family = binomial)
xtable(fm3)
@
\subsubsection{Analysis of deviance}
<<results='asis'>>=
xtable(anova(fm3))
@
\subsection{prcomp}
<<results='asis'>>=
pr1 <- prcomp(USArrests)
xtable(pr1)
@
\p
<<results='asis'>>=
xtable(summary(pr1))
@
<<include=FALSE>>=
# pr2 <- princomp(USArrests)
# xtable(pr2)
@
\newpage
\subsection{Time series}
<<results='asis'>>=
temp.ts <- ts(cumsum(1 + round(rnorm(100), 0)),
start = c(1954, 7), frequency = 12)
temp.table <- xtable(temp.ts, digits = 0)
temp.table
@
\subsection{Flat tables}
\label{sec:flat-tables}
See the \textbf{Details} section of the help for \code{ftable} for a
description of these tables, which are flat versions of
multi-dimensional contingency tables. They require special methods to
enable them to be printed using \pkg{xtable}.
<<ftable>>=
data(mtcars)
mtcars$cyl <- factor(mtcars$cyl, levels = c("4","6","8"),
labels = c("four","six","eight"))
tbl <- ftable(mtcars$cyl, mtcars$vs, mtcars$am, mtcars$gear,
row.vars = c(2, 4),
dnn = c("Cylinders", "V/S", "Transmission", "Gears"))
tbl
@ %def
Here is the \LaTeX{} produced:
<<ftablecheck>>=
xftbl <- xtableFtable(tbl, method = "compact")
print.xtableFtable(xftbl, booktabs = TRUE)
@ %def
And here is a basic flat table:
<<ftable1, results = 'asis'>>=
xftbl <- xtableFtable(tbl)
print.xtableFtable(xftbl)
@ %def
This illustrates the \code{method} argument:
<<ftable2, results = 'asis'>>=
xftbl <- xtableFtable(tbl, method = "col.compact")
print.xtableFtable(xftbl, rotate.rownames = TRUE)
@ %def
Booktabs is incompatible with vertical lines in tables, so the
vertical dividing line is removed.
<<ftable3, results = 'asis'>>=
xftbl <- xtableFtable(tbl, method = "compact")
print.xtableFtable(xftbl, booktabs = TRUE)
@ %def
\p
Row and column variable names can be formatted specially using
sanitization, and row and column variable names and labels can be
rotated.
If special formatting is required for row and column labels, that can
be done as a workaround by redefining the data and associated labels.
<<ftable4, results = 'asis'>>=
italic <- function(x){
paste0('{\\emph{', x, '}}')
}
mtcars$cyl <- factor(mtcars$cyl, levels = c("four","six","eight"),
labels = c("four",italic("six"),"eight"))
large <- function(x){
paste0('{\\Large ', x, '}')
}
bold <- function(x){
paste0('{\\bfseries ', x, '}')
}
tbl <- ftable(mtcars$cyl, mtcars$vs, mtcars$am, mtcars$gear,
row.vars = c(2, 4),
dnn = c("Cylinders", "V/S", "Transmission", "Gears"))
xftbl <- xtableFtable(tbl, method = "row.compact")
print.xtableFtable(xftbl,
sanitize.rownames.function = large,
sanitize.colnames.function = bold,
rotate.colnames = TRUE,
rotate.rownames = TRUE)
@ %def
\newpage
<<include=FALSE>>=
# ## Demonstrate saving to file
# for(i in c("latex", "html")) {
# outFileName <- paste("xtable.", ifelse(i=="latex", "tex", i), sep = "")
# print(xtable(lm.D9), type = i, file = outFileName, append = TRUE,
# latex.environments = NULL)
# print(xtable(lm.D9), type = i, file = outFileName, append = TRUE,
# latex.environments = "")
# print(xtable(lm.D9), type = i, file = outFileName, append = TRUE,
# latex.environments = "center")
# print(xtable(anova(glm.D93, test = "Chisq")),
# type = i, file = outFileName,
# append = TRUE)
# print(xtable(anova(glm.D93)), hline.after = c(1),
# size = "small", type = i,
# file = outFileName, append = TRUE)
# # print(xtable(pr2), type = i, file = outFileName, append = TRUE)
# }
@
\section{Automatic formatting}
\subsection{Suggest alignment, digits, and display}
The functions \code{xalign}, \code{xdigits}, and \code{xdisplay} are
useful for formatting tables in a sensible way. Consider the output
produced by the default formatting.
<<results='asis'>>=
data(mtcars)
dat <- mtcars[1:3, 1:6]
x <- xtable(dat)
x
@
\p
Now change the default alignment, digits and display using helper functions
\code{xalign}, \code{xdigits}, and \code{xdisplay}. This produces a better
format as shown below.
<<results='asis'>>=
align(x) <- xalign(x)
digits(x) <- xdigits(x)
display(x) <- xdisplay(x)
x
@
\subsection{Shorthand notation}
For convenience, the three `autoformat' functions (\code{xalign},
\code{xdigits}, and \code{xdisplay}) can be applied together when an
\code{xtable} is created, using the \code{auto} argument:
<<results='asis'>>=
xtable(dat, auto = TRUE)
@
\p
Similarly, the \code{autoformat} function can be used to postprocess an
existing \code{xtable}:
<<results='asis'>>=
x <- xtable(dat)
autoformat(x)
@
\newpage
\subsection{Math-Style Exponents}
If you prefer $5 \times 10^5$ in your tables to 5e5, the
\code{math.style.exponents} option to \code{print.xtable} is useful:
<<results='asis'>>=
print(xtable(data.frame(text = c("foo","bar"),
googols = c(10e10,50e10),
small = c(8e-24,7e-5),
row.names = c("A","B")),
display = c("s","s","g","g")),
math.style.exponents = TRUE)
@
This option also supports the values \code{ensuremath} which uses
\code{\char`\\ensuremath} instead of \code{\$\$} and \code{UTF-8}
which uses UTF-8 to approximate the \LaTeX\ typesetting.
\section{Sanitization}
<<results='asis'>>=
insane <- data.frame(Name = c("Ampersand","Greater than","Less than",
"Underscore","Per cent","Dollar",
"Backslash","Hash","Caret","Tilde",
"Left brace","Right brace"),
Character = I(c("&",">","<","_","%","$",
"\\","#","^","~","{","}")))
colnames(insane)[2] <- paste(insane[, 2], collapse = "")
xtable(insane)
@
\p
Sometimes you might want to have your own sanitization function.
<<results='asis'>>=
wanttex <- xtable(data.frame(Column =
paste("Value_is $10^{-",1:3,"}$", sep = "")))
print(wanttex, sanitize.text.function =
function(str) gsub("_", "\\_", str, fixed = TRUE))
@
\p
Sanitization can be useful in formatting column headings and row names:
<<sanitize3>>=
dat <- mtcars[1:3, 1:6]
large <- function(x){
paste0('{\\Large{\\bfseries ', x, '}}')
}
italic <- function(x){
paste0('{\\emph{ ', x, '}}')
}
@ %def
<<sanitize4, results = 'asis'>>=
print(xtable(dat),
sanitize.rownames.function = italic,
sanitize.colnames.function = large,
booktabs = TRUE)
@ %def
\newpage
\subsection{Markup in tables}
Markup can be included in tables, including in column and row names,
by using a custom \code{sanitize.text.function}.
<<results='asis'>>=
mat <- round(matrix(c(0.9, 0.89, 200, 0.045, 2.0), c(1, 5)), 4)
rownames(mat) <- "$y_{t-1}$"
colnames(mat) <- c("$R^2$", "$\\bar{x}$", "F-stat", "S.E.E", "DW")
mat <- xtable(mat)
print(mat, sanitize.text.function = function(x) {x})
@
% By David Dahl to demonstrate contribution from David Whitting, 2007-10-09.
\p
You can also have sanitize functions that are specific to column or
row names. In the table below, the row name is not sanitized but
column names and table elements are.
<<results='asis'>>=
money <- matrix(c("$1,000","$900","$100"), ncol = 3,
dimnames = list("$\\alpha$",
c("Income (US$)","Expenses (US$)",
"Profit (US$)")))
print(xtable(money), sanitize.rownames.function = function(x) {x})
@
\section{Format examples}
\subsection{Adding a centering environment}
<<results='asis'>>=
print(xtable(anova(fm3), caption = "\\tt latex.environments = \"\""),
floating = TRUE, latex.environments = "")
print(xtable(anova(fm3), caption = "\\tt latex.environments = \"center\""),
floating = TRUE, latex.environments = "center")
@
\newpage
\subsection{Column alignment}
<<results='asis'>>=
tli.table <- xtable(tli[1:10, ])
align(tli.table) <- rep("r", 6)
tli.table
@
\subsubsection{Left aligned strings with column lines}
<<results='asis'>>=
align(tli.table) <- "|rrl|l|lr|"
tli.table
@
\subsubsection{Fixed width columns}
<<results='asis'>>=
align(tli.table) <- "|rr|lp{3cm}l|r|"
tli.table
@
\newpage
\subsection{Number of digits}
One number for all columns,
<<results='asis'>>=
display(tli.table)[c(2,6)] <- "f"
digits(tli.table) <- 3
tli.table
@
\p
or one for each column, including the row names,
<<results='asis'>>=
digits(tli.table) <- 1:(ncol(tli)+1)
tli.table
@
\p
or as a full matrix.
<<results='asis'>>=
digits(tli.table) <- matrix(0:4, nrow = 10, ncol = ncol(tli)+1)
tli.table
@
\newpage
\subsection{Suppress row/column names}
\subsubsection{Suppress row names}
<<results='asis'>>=
tli.table <- xtable(tli[1:10, ])
print(tli.table, include.rownames = FALSE)
@
\p
If you want a vertical line on the left, you need to change the \code{align}
attribute.
<<results='asis'>>=
align(tli.table) <- "|r|r|lp{3cm}l|r|"
print(tli.table, include.rownames = FALSE)
@
\p
Revert the alignment to what is was before.
<<>>=
align(tli.table) <- "|rr|lp{3cm}l|r|"
@
\newpage
\subsubsection{Suppress column names}
<<results='asis'>>=
print(tli.table, include.colnames = FALSE)
@
\p
Note the doubled header lines which can be suppressed.
<<results='asis'>>=
print(tli.table, include.colnames = FALSE,
hline.after = c(0,nrow(tli.table)))
@
\subsubsection{Suppress row and column names}
<<results='asis'>>=
print(tli.table, include.colnames = FALSE, include.rownames = FALSE)
@
\newpage
\subsection{Rotate row/column names}
The \code{rotate.rownames} and \code{rotate.colnames} arguments can be
used to rotate the row and/or column names. This requires
\verb|\usepackage{rotating}| in the \LaTeX\ preamble.
<<results='asis'>>=
print(tli.table, rotate.rownames = TRUE, rotate.colnames = TRUE)
@
\newpage
\subsection{Horizontal lines}
\subsubsection{Line locations}
Use the \code{hline.after} argument to specify the position of the
horizontal lines.
<<results='asis'>>=
print(xtable(anova(fm3)), hline.after = c(1))
@
\subsubsection{Line styles}
Specifying \code{booktabs = TRUE} will generate three line types. By
default, when no value is given for \code{hline.after}, a
\verb|\toprule| will be drawn above the table, a \verb|\midrule| after
the table headings and a \verb|\bottomrule| below the table. This
requires \verb|\usepackage{booktabs}| in the \LaTeX\ preamble.
\p
The top and bottom rules are slightly thicker than the mid rule. The
thickness of the lines can be set via the \LaTeX\ lengths
\verb|\heavyrulewidth| and \verb|\lightrulewidth|.
<<results='asis'>>=
tli.table <- xtable(tli[1:10, ])
print(tli.table, include.rownames = FALSE, booktabs = TRUE)
@
\p
If \code{hline.after} includes \code{-1}, a \verb|\toprule| will be
drawn above the table. If \code{hline.after} includes the number of
rows in the table, a \verb|\bottomrule| will be drawn below the
table. For any other values specified in \code{hline.after}, a
\verb|\midrule| will be drawn after that line of the table.
\p
The following table has more than one \verb|\midrule|.
<<results='asis'>>=
bktbs <- xtable(matrix(1:10, ncol = 2))
hlines <- c(-1, 0, 1, nrow(bktbs))
print(bktbs, booktabs = TRUE, hline.after = hlines)
@
\subsection{Table level commands}
<<results='asis'>>=
print(xtable(anova(fm3)), size = "large")
@
\p
<<results='asis'>>=
print(xtable(anova(fm3)), size = "\\setlength{\\tabcolsep}{12pt}")
@
\subsection{Long tables}
Requires \verb|\usepackage{longtable}| in the \LaTeX\ preamble.
<<results='asis'>>=
x <- matrix(rnorm(1000), ncol = 10)
x.big <- xtable(x, caption = "A \\code{longtable} spanning several pages")
print(x.big, hline.after=c(-1, 0), tabular.environment = "longtable")
@
Extra features of the \pkg{longtable} \LaTeX{} package can typically
be activated using \code{add.to.row}, as shown below.
<<results='asis'>>=
add.to.row <- list(pos = list(0), command = NULL)
command <- paste0("\\hline\n\\endhead\n",
"\\hline\n",
"\\multicolumn{", dim(x)[2] + 1, "}{l}",
"{\\footnotesize Continued on next page}\n",
"\\endfoot\n",
"\\endlastfoot\n")
add.to.row$command <- command
print(x.big, hline.after=c(-1), add.to.row = add.to.row,
tabular.environment = "longtable")
@
\newpage
\subsection{Use of \code{add.to.row} argument}
The following frequency table has outer dimnames: \code{Grade3} and
\code{Grade6}.
<<>>=
Grade3 <- c("A","B","B","A","B","C","C","D","A","B",
"C","C","C","D","B","B","D","C","C","D")
Grade6 <- c("A","A","A","B","B","B","B","B","C","C",
"A","C","C","C","D","D","D","D","D","D")
Cohort <- table(Grade3, Grade6)
Cohort
@
\p
The default behavior of \code{print.xtable} is to strip outer dimnames.
<<results='asis'>>=
xtable(Cohort)
@
\p
The desired column labels can be created using \code{add.to.row}, in this case
applying two commands to ``row number zero'' while suppressing the basic column
names.
<<results='asis'>>=
addtorow <- list()
addtorow$pos <- list(0, 0)
addtorow$command <- c("& \\multicolumn{4}{c}{Grade 6} \\\\\n",
"Grade 3 & A & B & C & D \\\\\n")
print(xtable(Cohort), add.to.row = addtorow, include.colnames = FALSE)
@
\subsection{Sideways tables}
Requires \verb|\usepackage{rotating}| in the \LaTeX\
preamble. Sideways tables can't be forced in place with the \code{[H]}
specifier, but you can use the \verb|\clearpage| command to get them
fairly nearby.
<<results='asis'>>=
x <- x[1:30, ]
x.side <- xtable(x, caption = "A sideways table")
print(x.side, floating = TRUE, floating.environment = "sidewaystable")
@
\clearpage
\subsection{Rescaled tables}
Specify a \code{scalebox} value to rescale the table.
<<results='asis'>>=
x <- x[1:20, ]
x.rescale <- xtable(x)
print(x.rescale, scalebox = 0.7)
@
\subsection{Aligning fixed width columns}
Note that using specifications such as \verb|p{2cm}| always
produces a \textbf{left aligned} column. What if some other alignment
is desired?
This is not really a problem with \pkg{xtable} but with the formatting
of tables with fixed width columns and different alignments using
standard \LaTeX.
One solution is to use the \verb|array| package, defining new
column formats.
\begin{verbatim}
\newcolumntype{L}[1]{>{\raggedright\let\newline\\
\arraybackslash\hspace{0pt}}m{#1}}
\newcolumntype{C}[1]{>{\centering\let\newline\\
\arraybackslash\hspace{0pt}}m{#1}}
\newcolumntype{R}[1]{>{\raggedleft\let\newline\\
\arraybackslash\hspace{0pt}}m{#1}}
\newcolumntype{P}[1]{>{\raggedright\tabularxbackslash}p{#1}}
\end{verbatim}
These allow for very sophisticated cell formatting, namely
left-aligned, centred, or right-aligned text, with recognition of line
breaks for the first three new column types. If these lines are
included along with \verb|\usepackage{array}|, then the following is
possible.
\newcolumntype{L}[1]{>{\raggedright\let\newline\\
\arraybackslash\hspace{0pt}}m{#1}}
\newcolumntype{C}[1]{>{\centering\let\newline\\
\arraybackslash\hspace{0pt}}m{#1}}
\newcolumntype{R}[1]{>{\raggedleft\let\newline\\
\arraybackslash\hspace{0pt}}m{#1}}
\newcolumntype{P}[1]{>{\raggedright\tabularxbackslash}p{#1}}
<<results='asis'>>=
df <- data.frame(name = c("A","B"), right = c(1.4, 34.6),
left = c(1.4, 34.6), text = c("txt1","txt2"))
print(xtable(df, align = c("l", "|c", "|R{3cm}", "|L{3cm}", "| p{3cm}|")),
floating = FALSE, include.rownames = FALSE)
@
\newpage
\subsection{Table width}
The \code{tabularx} environment is for typesetting tables whose
overall width is fixed. The column alignment code \code{X} denotes
columns that will be stretched to achieve the desired table
width. Requires \verb|\usepackage{tabularx}| in the \LaTeX\ preamble.
<<results='asis'>>=
df.width <- data.frame(One = c("item 1", "A"), Two = c("item 2", "B"),
Three = c("item 3", "C"), Four = c("item 4", "D"))
x.width <- xtable(df.width)
align(x.width) <- "|l|X|l|l|l|"
print(x.width, tabular.environment = "tabularx", width = "\\textwidth")
@
\section{Suppressing printing}
By default the \code{print} method will print the \LaTeX\ or HTML to
standard output and also return the character strings invisibly. The
printing to standard output can be suppressed by specifying
\code{print.results = FALSE}.
<<>>=
x.out <- print(tli.table, print.results = FALSE)
@
Formatted output can also be captured without printing with the
\code{toLatex} method. This function returns an object of class
\code{"Latex"}.
<<>>=
x.ltx <- toLatex(tli.table)
class(x.ltx)
x.ltx
@
\newpage
\section{Acknowledgements}
Most of the examples in this gallery are taken from the \pkg{xtable}
documentation. Two examples (\code{add.to.row} and `Aligning fixed width
columns') are from Stack Exchange.
\section{Session information}
<<results='asis'>>=
toLatex(sessionInfo())
@
\end{document}