rewrapping kable latex table to different tabular environment - r

I would like to keep just the "inside" lines of a latex table created by kable. I only know cumbersome and ugly ways to do so...attempts at cleaner versions failed. here is one clean flunk:
kable.rewrap <- function( df, newname= "mytable" ) {
kt <- kable( df, "latex", booktabs=T )
notop <- strsplit(kt, "\\midrule")[[1]][2]
nosur <- strsplit(notop, "\\bottomrule" )[[1]][1] ## fails: doesn't like "\\"!
newkt <- paste0("\\begin{", newname, "}", nosur, "\n\\end{",newname,"}\n")
## attr(newkt, "format") <- chr "latex" # wrong
newkt
}
print(kable.rewrap( data.frame( x=1:3, y=1:3 ), "mytable" ))
should produce
\begin{mytable}
\toprule
x & y\\
\midrule
1 & 1\\
2 & 2\\
3 & 3\\
\bottomrule
\end{mytable}
obviously, my latex code should define an environment mytable now. I am also puzzled by "bottomrule" in the nosur line works, but "\\bottomrule" fails.
(another alternative is to forego kable altogether and just work with the data frame, separating each line by a \ and each column by a &.)
advice appreciated.

1) The kable.envir argument will add the mytable part but that still causes tabulars to be generated which we remove using gsub:
kable(test_data, "latex", booktabs = TRUE, table.envir = "mytable") %>%
gsub(".(begin|end){tabular.*}", "", ., perl = TRUE)
giving:
\begin{mytable}
\toprule
x & y\\
\midrule
1 & 1\\
2 & 2\\
3 & 3\\
\bottomrule
\end{mytable}
2) Another possibility is to define your own mytabular environment and then use:
kable(test_data, "latex", booktabs = TRUE, table.envir = "mytable") %>%
kable_styling(latex_table_env = "mytabular")
which gives:
\begin{mytable}
\begin{mytabular}{rr}
\toprule
x & y\\
\midrule
1 & 1\\
2 & 2\\
3 & 3\\
\bottomrule
\end{mytabular}
\end{mytable}
Added
In (2) rather than defining a do-nothing environment to replace tabular tex/latex actually makes one available already, namely #empty.
kable(test_data, "latex", booktabs = TRUE, table.envir = "mytable") %>%
kable_styling(latex_table_env = "#empty")
Note
We named the data frame shown in the question as follows:
test_data <- data.frame(x = 1:3, y = 1:3)

Related

Is there any possibility to save kable table in .tex or .markdown?

Let's consider very simple kable table for reproducible example:
df <- data.frame("X_1" = c(1, 2), "X_2" =c(3,4))
df <- kable(df, format = 'latex')
df
\begin{tabular}{r|r}
\hline
X\_1 & X\_2\\
\hline
1 & 3\\
\hline
2 & 4\\
\hline
\end{tabular}
Is there any possibility to have this file saved as .tex or .markdown ? I looked for function save_kable but it seems that it only supports .png, .pdf or .jpeg formats.
knitr::kable() returns a character vector, which you can definitely write to a file, e.g.,
df <- data.frame("X_1" = c(1, 2), "X_2" =c(3,4))
df <- knitr::kable(df, format = 'latex')
writeLines(df, 'df.tex')
i am using save_kable and specifying tex with no problems e.g. %>% save_kable(paste(resultspath,"DescTableStroops.tex"),float = FALSE)

Why am I unable to print the proper output produced using the kable function from the knitr package?

I have been trying to print a data dictionary using the kable function. Here is my code:
dict<-build_dict(my.data = tweets_train,linker=linker,option_description = NULL, prompt_varopts = T)
kable(dict,format="latex",caption="Data dictionary for the Training dataset") %>%
kable_styling(position = "center")
And this is the output:
> kable(dict,format="latex",caption="Data dictionary for the Training dataset") %>%
+ kable_styling(position = "center")
\begin{table}
\caption{\label{tab:}Data dictionary for the Training dataset}
\centering
\begin{tabular}[t]{l|l|l|l}
\hline
variable name & variable description & variable options & notes\\
\hline
sentiment & Sentiment Score 0 for Negative sentences and 4 for Positive sentences & 0 to 4 & The polarity of the tweet (0 = negative, 2 = neutral, 4 = positive)\\
\hline
text & The tweets collected & '' oh u can take me to the game with u mor to zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz so tired good night hokies & The dataset Sentiment 140 that originated from Stanford University for the purpose of Training\\
\hline
\end{tabular}
\end{table}
How do I rectify this. Using knitr for the first time as I had to create a data dictionary. Any suggestions would be highly appreciated. Thanks in advance.
This is how to shift your code as mentionned by #Marius
You need to put it in a markdown file as below:
paste this in the r chunk
dict<-build_dict(my.data = tweets_train,linker=linker,
option_description = NULL, prompt_varopts = T)
knitr::kable(dict,format="latex",caption="Data dictionary for the Training dataset") %>%
knitr::kable_styling(position = "center")
like that and put knitr before kable to call the library itself (or call it before library(knitr)) :
Then save and knit :)
Hope that helps

Simple example of using tables + knitr for latex

I'm struggling with a tables package, all the examples in the packable docs are so complex and none of them works for me with knitr and latex. Could somebody help be out and display a simple table with some formulas and multiline labels in the header? 
Something like this:
df <- data.frame(matrix(1:9, nrow = 3))
colnames(df) <- c("first column", "second \\frac{1}{2}", "third column first line \\ second line")
Thank you in advance
It is possible to create multi-line headers for tables in LaTeX using the xtable package. These can be compiled from either .Rmd or .Rnw files. Building on the example by mattw and using add.to.row in the print method for xtable:
df <- data.frame(matrix(1:50, nrow = 10))
print(
xtable(df),
include.rownames = FALSE,
include.colnames = FALSE,
add.to.row = list(
pos = list(0),
command = c(
"& \\multicolumn{4}{c}{4 column header} \\\\
\\cline{2-5}
col1 & col2 & col3 & col4 & col5 \\\\ "
)
)
)
Note that add.to.row requires a list with two elements: pos and command. The first must be a list, the second a character string or vector, see ?print.xtable. pos gives the row number for the LaTeX insertion, and command is the insertion. Be a bit careful with formatting this, as it is will run directly into the next cell of the first column if you don't put in spaces or \n.
There are lots of options for customisation, allowing you to create quite complex tables with a bit of tweaking.
print(
xtable(df),
include.rownames = FALSE,
include.colnames = FALSE,
hline.after = c(-1,0),
add.to.row = list(
pos = list(0,5,10),
command = c(
"& \\multicolumn{4}{c}{4 column header} \\\\
\\cline{2-5}
col1 & col2 & col3 & col4 & col5 \\\\ ",
"\\hline \\multicolumn{5}{l}{Separator in table.} \\\\ \\hline",
"\\hline \\multicolumn{5}{l}{Notes at end of table.} \\\\ "
)
)
)
In this example I change the default settings for where xtable puts \hline, allowing me to add the last \hline above the notes - useful for explaining superscripts in the table.
Note also the use of \cline{2-5} giving me a line over columns 2 - 5.
See gist for fully reproducible example.
I don't think that this is possible with RMarkdown if you want the table to be in LaTeX style. However, you can easily do this with the xtable package when you write your code in an .Rnw file:
\documentclass{article}
\begin{document}
<<>>=
library("xtable")
df <- data.frame(matrix(1:9, nrow = 3))
colnames(df) <- c("first column", "second $\\frac{1}{2}$",
"third column")
#
<<xtable, results = "asis">>=
print(xtable(df), floating = TRUE,
sanitize.colnames.function = identity, type = "latex")
#
\end{document}

possible to create latex multicolumns in xtable?

I am using xtable with R Markdown and knitr to produce .tex files that I call with \input{}. Works great, but I have not figured out how to create multicolumns like the one shown here. Does anyone know how to to this?
So far I am using:
tbl <- xtable(data, align="l r r r r r")
colnames(tbl) <- c("Variable",
"Mean", "Std Dev",
"Mean", "Std Dev",
"Difference")
caption(tbl) <- c("Table Title")
print(tbl,
include.rownames=FALSE,
caption.placement="top",
booktabs=TRUE,
type="latex",
file="output.tex")
I'd like to have a different grouping header over each "Mean" and "Std Dev" ("Treatment" and "Control").
Alternatively, is there a better method for using R Markdown/knitr to automatically generate tables? I don't want to manually edit the tables because the report needs to generate automatically.
UPDATE:
#agstudy: I'm new to latex, but I think this is the output I am looking to produce automatically with xtable (or something like xtable):
\begin{tabular}{lrrrrr}
\toprule
& \multicolumn{2}{c}{Treatment} & \multicolumn{2}{c}{Control} & \\
\cmidrule(lr){2-3} \cmidrule(lr){4-5}
Variable & Mean & Std Dev & Mean & Std Dev & Difference \\
\midrule
var1 & 1 & 2 & 3 & 4 & 5 \\
\bottomrule
\end{tabular}
UPDATE 2:
#Jonathan: it took me a few reads to understand what you were suggesting. I took your recommendation, and it worked.
In the R markdown chunk I now use:
tbl <- xtable(data)
print(tbl,
only.contents=TRUE,
include.rownames=FALSE,
type="latex",
digits(tbl) <- c(0,1,1,1,1,1),
file="output/tblout.tex")
Then in the text, I use:
\begin{tabular}{lddddd}
\toprule
& \multicolumn{2}{c}{Treatment} & \multicolumn{2}{c}{Control} & \\
\cmidrule(lr){2-3} \cmidrule(lr){4-5}
Variable & \multicolumn{1}{r}{Mean} & \multicolumn{1}{r}{Std Dev} & \multicolumn{1}{r}{Mean} & \multicolumn{1}{r}{Std Dev} & \multicolumn{1}{r}{Difference} \\
\midrule
\input{../output/tblout}
\bottomrule
\end{tabular}
I'll see if anyone has any other suggestions for a native xtable (or other package) solution. Otherwise, I will accept your answer. Thanks!
I think the add.to.row option in xtable achieves this perfectly.
Example code here:
require(xtable)
age <- sample(c('30-50', '50-70', '70+'), 200, replace=T)
sex <- sample(c('Male', 'Female'), 200, replace=T)
val <- table(age, sex)
val <- rbind(val, formatC(prop.table(val)*100, format='f', digits=1))
val <- structure(val, dim=c(3, 4))
val <- rbind(c('n', '%'), val)
rownames(val) <- c('', sort(unique(age)))
val <- xtable(val)
addtorow <- list()
addtorow$pos <- list(0)
addtorow$command <- paste0(paste0('& \\multicolumn{2}{c}{', sort(unique(sex)), '}', collapse=''), '\\\\')
print(val, add.to.row=addtorow, include.colnames=F)
Assuming the form of the table is the same across runs (i.e., only the numbers are changing), my suggestion would be to use the only.contents argument to print.xtable and code the multi-column headers in by hand. To the best of my knowledge xtable is not capable of doing multi-column cells itself.
Consider using the tables package.
This is a child's game with the kableExtra package.
\documentclass{article}
\usepackage{booktabs}
\begin{document}
<<setup, include=FALSE>>=
library(knitr)
opts_chunk$set(echo=FALSE)
library(kableExtra)
options(knitr.table.format = "latex")
mx <- matrix(1:6, ncol=3)
rownames(mx) <- LETTERS[1:NROW(mx)]
colnames(mx) <- sprintf("Col %s", LETTERS[1:NCOL(mx)])
#
<<results='asis'>>=
kable(mx, booktabs = TRUE, caption = "My table", align = "c") %>%
add_header_above(c(" ", "First"=2, "Second"=1)) %>%
kable_styling(latex_options = "hold_position")
#
<<results='asis'>>=
kable(mx, booktabs = TRUE, caption = "My other table", align = "c") %>%
add_header_above(c(" ", "First"=2, "Second"=1)) %>%
kable_styling(latex_options = "hold_position") %>%
group_rows("Nice!", 1, 2)
#
\end{document}
Usually I am doing something like this:
tableLines <- print (xtable (mymatrix)) ## no file
multicolumns <- "& \\\\multicolumn{3}{c}{A} & \\\\multicolumn{3}{c}{B} \\\\\\\\"
tableLines <- sub ("\\\\toprule\\n", paste0 ("\\\\toprule\n", multicolumns, "\n"), tableLines) ## booktabs = TRUE
tableLines <- sub ("\\\\hline\\n", paste0 ("\\\\hline\n", multicolumns, "\n"), tableLines) ## booktabs = FALSE
writeLines (tableLines, con = "myfile")
Pay attention to the many \\\\ needed. Backslashes are lost in the sub and paste commands.
A little bit late to the game here is my answer, which is similar to ashkan, but more general and allows for different parameters.
First of all, why a new answer? Well, I needed an output without a table-environment (I want to write my captions etc inside my tex-document not inside my r-code) which kableExtra does not seem to provide (correct me if I am wrong).
But I also wanted flexibility with the inputs (i.e., with and without line, different spans etc).
The result is a function construct_header() that constructs the header for us.
First a short example:
library(xtable)
set.seed(123)
df <- matrix(round(rnorm(16), 2), ncol = 4)
df <- cbind(paste("Var", 1:4), df)
colnames(df) <- c("Var", rep(c("X", "Y"), 2))
df
# Var X Y X Y
# [1,] "Var 1" "-0.56" "0.13" "-0.69" "0.4"
# [2,] "Var 2" "-0.23" "1.72" "-0.45" "0.11"
# [3,] "Var 3" "1.56" "0.46" "1.22" "-0.56"
# [4,] "Var 4" "0.07" "-1.27" "0.36" "1.79"
a_header <- construct_header(
# the data.frame or matrix that should be plotted
df,
# the labels of the groups that we want to insert
grp_names = c("", "Group A", "Group B"),
# the number of columns each group spans
span = c(1, 2, 2),
# the alignment of each group, can be a single character (lcr) or a vector
align = "c"
)
print(xtable(df), add.to.row = a_header, include.rownames = F, hline.after = F)
# % latex table generated in R 3.4.2 by xtable 1.8-2 package
# % Fri Oct 27 16:39:44 2017
# \begin{table}[ht]
# \centering
# \begin{tabular}{lllll}
# \hline
# \multicolumn{1}{c}{} & \multicolumn{2}{c}{Group A} & \multicolumn{2}{c}{Group B} \\ \cmidrule(lr){2-3} \cmidrule(lr){4-5}
# Var & X & Y & X & Y \\
# \hline
# Var 1 & -0.56 & 0.13 & -0.69 & 0.4 \\
# Var 2 & -0.23 & 1.72 & -0.45 & 0.11 \\
# Var 3 & 1.56 & 0.46 & 1.22 & -0.56 \\
# Var 4 & 0.07 & -1.27 & 0.36 & 1.79 \\
# \hline
# \end{tabular}
# \end{table}
Note that we have to specify hline.after = FALSE (important for me, but omitted here is the possibility to specify floating = FALSE).
Which results in this table (note that this approach needs the booktabs package to be loaded in LaTeX):
You can specify to omit the lines construct_header(..., draw_line = FALSE), align the groups, and have them span in different ways, i.e.,
ugly_header <- construct_header(df, c("One", "Two", "Three"), c(2, 1, 2), c("l", "c", "r"))
print(xtable(df), add.to.row = ugly_header, include.rownames = F, hline.after = F)
which results in this:
The code for the function is this:
#' Constructs a header i.e., groups for an xtable
#'
#' #param df a data.frame or matrix
#' #param grp_names the names of the groups
#' #param span where the groups span
#' #param align the alignment of the groups, defaults to center
#' #param draw_line if the group-names should be underlined
#'
#' #return a list that can be given to the \code{add.to.row} argument of the of \code{print.xtable}
#' #export
#'
#' #examples
#' library(xtable)
#' mx <- matrix(rnorm(16), ncol = 4)
#' mx <- cbind(paste("Var", 1:4), mx)
#' colnames(mx) <- c("Var", rep(c("X", "Y"), 2))
#'
#' addtorow <- construct_header(mx, c("", "Group A", "Group B"), span = c(1, 2, 2), "c")
#' print(xtable(mx), add.to.row = addtorow, include.rownames = F, hline.after = F)
construct_header <- function(df, grp_names, span, align = "c", draw_line = T) {
if (length(align) == 1) align <- rep(align, length(grp_names))
if (!all.equal(length(grp_names), length(span), length(align)))
stop("grp_names and span have to have the same length!")
if (ncol(df) < sum(span)) stop("Span has to be less or equal to the number of columns of df")
header <- mapply(function(s, a, grp) sprintf("\\multicolumn{%i}{%s}{%s}", s, a, grp),
span, align, grp_names)
header <- paste(header, collapse = " & ")
header <- paste0(header, " \\\\")
if (draw_line) {
# where do we span the lines:
min_vals <- c(1, 1 + cumsum(span)[1:(length(span) - 1)])
max_vals <- cumsum(span)
line <- ifelse(grp_names == "", "",
sprintf("\\cmidrule(lr){%i-%i}", min_vals, max_vals))
line <- paste(line[line != ""], collapse = " ")
header <- paste0(header, " ", line, "\n ")
}
addtorow <- list(pos = list(-1, -1, nrow(df)),
command = c("\\hline\n ", header, "\\hline\n "))
return(addtorow)
}

xtable header manipulation

I am using xtable in R to get LaTeX code for tables. I want to modify the first element of the "header" (first row in LaTeX table) but I only saw an option to add text to the end of a line (using add.to.row in xtable).
The following example should clarify what I want.
Running
xtable(matrix(c(1,0.25,3,0.75),nrow=2,dimnames=list(c('absolute','relative'),c('GNU','Leo'))))
gives the output
% latex table generated in R 2.13.0 by xtable 1.5-6 package
% Tue Jun 19 22:39:49 2012
\begin{table}[ht]
\begin{center}
\begin{tabular}{rrr}
\hline
& GNU & Leo \\
\hline
absolute & 1.00 & 3.00 \\
relative & 0.25 & 0.75 \\
\hline
\end{tabular}
\end{center}
\end{table}
I would like to get the line
frequency & GNU & Leo \\
instead of the line
& GNU & Leo \\
but I was unable to accomplish this using xtable. Let me know if you have an idea how to do this. Also, I apologize in advance if this is in the wrong place to ask or if I overlooked an answer or an obvious solution.
Another option is to use the latex function from Hmisc:
library(Hmisc)
m <- matrix(c(1,0.25,3,0.75),nrow=2,dimnames=list(c('absolute','relative'),c('GNU','Leo')))
latex(m,file = "",rowlabel = "frequency")
One possibility:
dat1 <- data.frame(matrix(c(1,0.25,3,0.75),nrow=2,dimnames=list(c('absolute','relative'),c('GNU','Leo'))))
dat <- data.frame(Freq = rownames(dat1), dat1)
print(
xtable(
x = dat
, caption = "Your Caption"
, label = "tab:dat"
, align = paste(paste("l|", paste(rep("r", ncol(dat)-1), collapse=''), sep = ""), "|r", sep = "")
, digits = c(0, rep(3, ncol(dat)))
)
, table.placement = "H"
, caption.placement = "top"
, include.rownames = FALSE
, include.colnames = TRUE
, size = "normalsize"
, hline.after = c(-1, 0, nrow(dat))
)

Resources