funcion - xtable r
¿Es posible crear multicolumnas de látex en xtable? (6)
Estoy usando xtable con R Markdown y knitr para producir archivos .tex a los que llamo con / input {}. Funciona muy bien, pero no he descubierto cómo crear columnas múltiples como la que se muestra here . ¿Alguien sabe cómo hacer esto?
Hasta ahora estoy usando:
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")
Me gustaría tener un encabezado de agrupación diferente sobre cada "Mean" y "Std Dev" ("Tratamiento" y "Control").
Alternativamente, ¿existe un método mejor para usar R Markdown / knitr para generar tablas automáticamente? No quiero editar manualmente las tablas porque el informe debe generar automáticamente.
ACTUALIZACIÓN: @agstudy: Soy nuevo en el látex, pero creo que esta es la salida que estoy buscando para producir automáticamente con xtable (o algo así como 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}
ACTUALIZACIÓN 2: @Jonathan: me tomó un par de lecturas para entender lo que sugieres. Tomé su recomendación, y funcionó.
En el trozo de markdown R ahora uso:
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")
Luego en el texto, uso:
/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}
Veré si alguien tiene alguna otra sugerencia para una solución nativa de xtable (u otro paquete). De lo contrario, aceptaré tu respuesta. ¡Gracias!
Considere usar el paquete de tables .
Creo que la opción add.to.row en xtable logra esto perfectamente.
Código de ejemplo aquí:
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)
Este es un juego de niños con el paquete kableExtra
.
/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}
Por lo general estoy haciendo algo como esto:
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")
Preste atención a las muchas necesidades. Las barras invertidas se pierden en los comandos de sub
y paste
.
Suponiendo que la forma de la tabla es la misma en todas las ejecuciones (es decir, solo cambian los números), mi sugerencia sería usar el argumento print.xtable
para print.xtable
y codificar los encabezados de varias columnas manualmente. Según mi conocimiento, xtable
no es capaz de hacer celdas de varias columnas.
Un poco tarde para el juego aquí es mi respuesta, que es similar a ashkan, pero más general y permite diferentes parámetros.
En primer lugar, ¿por qué una nueva respuesta? Bueno, necesitaba una salida sin un entorno de tabla (quiero escribir mis títulos, etc. dentro de mi documento de texto, no dentro de mi código r) que kableExtra
no parece proporcionar ( kableExtra
si me equivoco). Pero también quería flexibilidad con las entradas (es decir, con y sin línea, diferentes tramos, etc.).
El resultado es una función construct_header()
que construye el encabezado para nosotros.
Primero un breve ejemplo:
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}
Tenga en cuenta que tenemos que especificar hline.after = FALSE
(importante para mí, pero omitido aquí es la posibilidad de especificar floating = FALSE
).
Puede especificar omitir las líneas construct_header(..., draw_line = FALSE)
, alinear los grupos y hacer que se extiendan de diferentes maneras, es decir,
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)
El código para la función es este:
#'' 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)
}