R package xtable, how to create a latextable with

2019-01-21 17:40发布

问题:

My goal is to create latextable with multirow/multicolumn features from R. The latextable I want should look like this:

               colLabel  |  colLabel2
                         |
                 a1  a2  |   a3    a4  
 -------------------------------------
             b1  1    2  |   5     6
 rowLabel1               |
             b2  3    4  |   7     8
 --------------------------------------
             b3  9   10  |   13    14
 rowLabel2               |
             b4  11  12  |   15    16
 --------------------------------------

I am currently using xtable but I cannot figure out how to create multirow using this package. Could anyone tell me how to create such table?

Thank you in advance

回答1:

You will have to be more specific about what exactly you are trying to tabulate, but I guess tabular function from the tables package might be helpful.

Here's an example of tabulating means of a variable according to 4 binary factor variables:

mydf <- data.frame(rowFactor1 = sample(letters[1:2], 100, replace = TRUE), 
                colFactor1 = sample(LETTERS[1:2], 100, replace = TRUE), 
                x = rnorm(100), 
                rowFactor2 = sample(1:2, 100, replace = TRUE), 
                colFactor2 = sample(1:2, 100, replace = TRUE))

tab1 <- tabular(Heading()*RowFactor(rowFactor2, spacing = 1, 
                        levelnames = c("rowLabel1", "rowLabel2"))*
                Heading()*RowFactor(rowFactor1, 
                        levelnames = c("b1", "b2")) ~ 
                Heading()*Factor(colFactor2, 
                        levelnames = c("colLabel1", "colLabel2") )*
                Heading()*Factor(colFactor1, 
                        levelnames = c("a1", "a2"))*
                Heading()*(x)*Heading()*(mean), 
        data = mydf)

which gives you something like this, but nicely formated when using the latex output

                                                                colLabel1         colLabel2        
                                                                a1        a2      a1        a2     
 \\nopagebreak rowLabel1                       \\nopagebreak b1 -0.1450    0.2633  0.91454   0.1222
                                               \\nopagebreak b2 -0.1499   -0.4290 -0.09706  -0.6977
 \\rule{0pt}{1.7\\normalbaselineskip}rowLabel2 \\nopagebreak b1  0.6976   -0.4888 -0.68492   1.6764
                                               \\nopagebreak b2 -0.2369   -0.1428 -0.66405   0.9469

Finally latex(tab1) gives you the latex code:

\begin{tabular}{llcccc}
\hline
& & \multicolumn{2}{c}{colLabel1} & \multicolumn{2}{c}{colLabel2} \\ 
 &  & a1 & a2 & a1 & \multicolumn{1}{c}{a2} \\ 
\hline
\nopagebreak rowLabel1 & \nopagebreak b1  & $-0.1450$ & $\phantom{-}0.2633$ & $\phantom{-}0.91454$ & $\phantom{-}0.1222$ \\
 & \nopagebreak b2  & $-0.1499$ & $-0.4290$ & $-0.09706$ & $-0.6977$ \\
\rule{0pt}{1.7\normalbaselineskip}rowLabel2 & \nopagebreak b1  & $\phantom{-}0.6976$ & $-0.4888$ & $-0.68492$ & $\phantom{-}1.6764$ \\
 & \nopagebreak b2  & $-0.2369$ & $-0.1428$ & $-0.66405$ & $\phantom{-}0.9469$ \\
\hline 
\end{tabular}


回答2:

I just would like to point at a combination of Christoph's block entry (here) and Gabor's answer in the R mail list (here) working with the xtable package. Furthermore, this solution is capable of merging cells in the \multirow manner.

Here comes a MWE:

require(xtable)

# set up data frame
df <- data.frame(c(replicate(2, c("L1")), replicate(2, c("L2"))),
                 replicate(4, "b"),
                 replicate(4, runif(4, 1, 10)) )

# only needed if first column consists of numbers
df[[1]] <- as.character(df[[1]])

rle.lengths <- rle(df[[1]])$lengths
first <- !duplicated(df[[1]])
df[[1]][!first] <- ""

# define appearance of \multirow
df[[1]][first] <-
   paste0("\\midrule\\multirow{", rle.lengths, "}{*}{\\textbf{", df[[1]][first], "}}")

strCaption <- paste0("\\textbf{Table Whatever} This table is just produced with some ",
                     "random data and does not mean anything. Just to show you how ",
                     "things work.")

# set up xtable output
print(xtable(df, digits = c(0, 0, 0, 3, 1, 0, 6), # first zero "represents" row numbers which we skip later
             align = "lllrr|rr",  # align and put a vertical line (first "l" again represents column of row numbers)
             caption = strCaption, label = "testTable"),
      size = "footnotesize", #Change size; useful for bigger tables "normalsize" "footnotesize"
      include.rownames = FALSE, #Don't print rownames
      include.colnames = FALSE, #We create them ourselves
      caption.placement = "top", #"top", NULL
      hline.after=NULL, #We don't need hline; we use booktabs
      floating=TRUE, # whether \begin{Table} should be created (TRUE) or not (FALSE)
      sanitize.text.function = force, # Important to treat content of first column as latex function
      add.to.row = list(pos = list(-1,
                                   2,
                                   nrow(df)),
                        command = c(paste("\\toprule \n",  # NEW row
                                          "\\multicolumn{2}{c}{} & \\multicolumn{2}{c}{\\textbf{colLabel1}} & \\multicolumn{2}{c}{colLabel2} \\\\\n",
                                          "\\cmidrule(l){3-4} \\cmidrule(l){5-6}\n",
                                          " & & a1 & a2 & a3 & a4 \\\\\n", # NEW row 
                                          "\\midrule \n"
                                          ),
                                    paste("\\cmidrule(l){3-4} \\cmidrule(l){5-6}\n" # we may also use 'pos' and 'command' to add a midrule
                                          ),
                                    paste("\\bottomrule \n"  # paste is used as it is more flexible regarding adding lines
                                          )
                                    )
                        )
      )

Which knits the following table in LaTeX:



回答3:

Consider the kableExtra package.

\documentclass{article}
\usepackage{booktabs}
\usepackage{multirow}
\usepackage[table]{xcolor}
\begin{document}

<<setup, include=FALSE>>=
library(knitr)
opts_chunk$set(echo=FALSE)
library(kableExtra)
options(knitr.table.format = "latex")
dat <- data.frame(
  group = c("rowLabel1", "rowLabel1", "rowLabel2", "rowLabel2"),
  a1 = c(1, 3, 9, 11),
  a2 = c(2, 4, 10, 12), 
  a3 = c(5, 7, 13, 15),
  a4 = c(6, 8, 14, 16)
)
@

<<results='asis'>>=
kable(dat, booktabs = TRUE, caption = "My  table", escape = FALSE) %>% 
  add_header_above(c(" ", "colLabel1"=2, "colLabel2"=2)) %>% 
  kable_styling(latex_options = "hold_position") %>%
  column_spec(1, bold=TRUE) %>%
  collapse_rows(columns = 1)
@

\end{document}



回答4:

I can't help with the column headers, but for multi row values in the past I've cheated. The function below will set the second and subsequent sets of the same value to NA, and xtable then doesn't display them so you get something that looks vaguely like a multi row value (with top justification)

cleanf <- function(x){     
    oldx <- c(FALSE, x[-1]==x[-length(x)])  
    # is the value equal to the previous?    
    res <- x
    res[oldx] <- NA
    return(res)} 


回答5:

Here is a way to do this with the huxtable package (I am the author):

library(huxtable)
mydf <- data.frame(rowFactor1 = sample(letters[1:2], 100, replace = TRUE), 
  colFactor1 = sample(LETTERS[1:2], 100, replace = TRUE), 
  x = rnorm(100), 
  rowFactor2 = sample(1:2, 100, replace = TRUE), 
  colFactor2 = sample(1:2, 100, replace = TRUE))

tbl <- ftable(colFactor1 + colFactor2  ~ rowFactor1 + rowFactor2, data = mydf)
ht <- as_hux(tbl)

rowspan(ht)[c(4, 6), "V1"] <- 2 # these cells span 2 rows
colspan(ht)[1, c(4, 6)] <- 2    # these cells span 2 columns

ht[3, 1:2] <- '' # clean up some extraneous colum names
ht[1:2, 3] <- ''

right_border(ht)[,3] <- 1
bottom_border(ht)[c(2, 5, 7), ] <- 1
bottom_border(ht)[c(4,6), 1] <- 1
ht

When printed to LaTeX this looks like:



标签: r latex