knitr kable horizontal line not appearing in second last line pdf - r

library(knitr)
library(kableExtra)
df <- data.frame("r1" = c(1,2,3,4), "r2"=c(4,5,6,6), "r3"=c(7,8,9,8), "r4"=c(11,12,13,89))
kable(df, format = "latex", booktabs = T, linesep = c('','','\\hline'))
actually this code should get a horizontal line at the second last line
But, i am not getting it. Is this a bug in kable or anything else?
I am trying to get a line above the last line for total. I am using Knitr Kable for this and knitting to pdf. Please Help

As far as I know, this is not how linesep works for kable. Instead you could use xtable:
library(xtable)
df <- data.frame("r1" = c(1,2,3,4), "r2"=c(4,5,6,6), "r3"=c(7,8,9,8), "r4"=c(11,12,13,89))
print(xtable(df), hline.after = c(0,3))
Why it does not work
This is the internal code in kable that produces the linesep:
linesep = if (nrow(x) > 1) {
c(rep(linesep, length.out = nrow(x) - 2), linesep[[1L]], '')
} else rep('', nrow(x))
linesep = ifelse(linesep == "", linesep, paste0('\n', linesep))
In line 2 you can see that your linesep argument is going to be repeated nrow(x)-2 times. So if you pass linesep = c("", "", "\\hline") to kable and you only have 4 rows, then this vector will be repeated 2 times. But since the vectors length is greater than 2, it only uses the first 2 elements which are empty. At the end of the snippet you have an empty character vector with 4 elements and therefore no horizontal ruler appears.

Related

Pasting within a function used to print with kableExtra

I use kableExtra for producing several tables and I'd like to use a function instead of repeating all the code. But with my limited knowledge of R, I am not able to.
Below is a simplified example (so simple it doesn't show why I want to collapse all the code into a function). First code without any added convenience function.
library(kableExtra)
library(glue)
library(tidyverse)
data <- mtcars[1:10, ] |> select(mpg, cyl, am, carb)
# KableExtra, without added convenience function
kbl(data, booktabs = T, linesep = "", digits = 2,
caption = "Ordinary kbl()") |>
add_header_above(c(" ", "Engine" = 2 , "Other" = 2))
)
Trying to make the same, now with a function where different calls can use different arguments for caption and added headers. The caption part works fine, it's the added headers I'm struggling with.
# Call kableExtra with a function
print_kable <- function(df, caption, header) {
kbl(data, booktabs = T, linesep = "", digits = 2,
# Caption works fine
caption = caption) |>
# I'm unable to develop code that uses a string argument here
add_header_above(c(header)) # 1 col instead of 5
# add_header_above(c({header})) # Same here
# add_header_above(c({{header}})) # and here
# add_header_above(c("{header}")) # and here
# add_header_above(c("{{header}}")) # and here
# add_header_above(c(glue({header}))) # and here
# add_header_above(c(paste(header))) # and here
}
Kable should print with the code below
print_kable(mtcars, caption = "kbl() called with a function",
header = ' " ", "Engine" = 2 , "Other" = 2 ')
Here is a related question:
How to evaluate a glue expression in a nested function?
Placing the function c() in the function call rather than in the function itself works fine. Is this what you're looking for?
print_kable <- function(df, caption, header) {
kbl(data, booktabs = T, linesep = "", digits = 2,
caption = caption) |>
add_header_above(header)
}
print_kable(mtcars, caption = "kbl() called with a function",
header = c(" ", "Engine" = 2 , "Other" = 2))

LyX: kableExtra problem (perhaps a bug) in column_spec

I create a table in LyX 2.3.6 / TeX Live 2020 as per the following minimal example:
<<results = "asis",echo = F, warning = FALSE, tidy=FALSE>>=
library(dplyr)
library(kableExtra)
df <- data.frame(Female = c(1.52, -0.03), Male = c(1.34, -0.02) )
rownames(df) <- c("Apples", "Bananas")
kable(df, format = "latex", booktabs = T, linesep = "", row.names = TRUE,
align = c("l", "r", "r"), escape = FALSE) %>%
kable_styling("striped", full_width = F, font_size = 10 )
#
This prints perfectly (it is centered on the page), but gives me no control over the column width. If I add a single line with a column_spec statement, I get an error that I don't understand. If the chunk is extend to read
<<results = "asis",echo = F, warning = FALSE, tidy=FALSE>>=
library(dplyr)
library(kableExtra)
df <- data.frame(Female = c(1.52, -0.03), Male = c(1.34, -0.02) )
rownames(df) <- c("Apples", "Bananas")
kable(df, format = "latex", booktabs = T, linesep = "", row.names = TRUE,
align = c("l", "r", "r"), escape = FALSE) %>%
kable_styling("striped", full_width = F, font_size = 10 ) %>%
column_spec(1, width = "6 em")
#
The table is now left justified, not centered on the page, all columns are centered instead of left and right justified, the letter "c" is printed above the table, and the error log shows the following message:
! Undefined control sequence.
<argument> >{\raggedright \arraybackslash
}p{6em}lr
l.149 ...}{>{\raggedright\arraybackslash}p{6em}lr}
The control sequence at the end of the top line
of your error message was never \def'ed. If you have
misspelled it (e.g., `\hobx'), type `I' and the correct
spelling (e.g., `I\hbox'). Otherwise just continue,
and I'll forget about whatever was undefined.
! LaTeX Error: Illegal character in array arg.
See the LaTeX manual or LaTeX Companion for explanation.
Type H <return> for immediate help.
...
l.149 ...}{>{\raggedright\arraybackslash}p{6em}lr}
You're in trouble here. Try typing <return> to proceed.
If that doesn't work, type X <return> to quit.
! LaTeX Error: Illegal character in array arg.
See the LaTeX manual or LaTeX Companion for explanation.
Type H <return> for immediate help.
...
l.149 ...}{>{\raggedright\arraybackslash}p{6em}lr}
You're in trouble here. Try typing <return> to proceed.
If that doesn't work, type X <return> to quit.
[2] (./Kable_Explorations.aux)
Package rerunfilecheck Info: File `Kable_Explorations.out' has not changed.
(rerunfilecheck) Checksum: D41D8CD98F00B204E9800998ECF8427E;0.
)
I'd be very appreciative for any help and guidance on the root cause of the problem and how it can be fixed.
Sincerely
Thomas Philips
The creator of the package provided the solution: he made some changes to column_spec to add conditional formatting support and to allow the insertion of images into columns (see https://haozhu233.github.io/kableExtra/awesome_table_in_html.html#Insert_Images_into_Columns), and column_spec() requires the latex array package to be loaded in the preamble. Updating my Latex preamble as follows solves the problem completely:
\usepackage{array}
\usepackage{booktabs}
\usepackage{threeparttablex}
In fact, he suggested that a user might want to load all the latex packages mentioned on this page (https://haozhu233.github.io/kableExtra/awesome_table_in_pdf.pdf#page=4) but I found the 3 mentioned above to be more than adequate for my relatively simple purposes.

Kable footnotes with math equation and alphabetic notes

I'm having trouble with kable and R Markdown. I would like to create a table with footnotes:
1. a bit of math formula (),
2. with alphabetical notes,
3. and I would like the notes a and b to also show up next to var_a and var_b in superscript.
I can make the table, but the moment I add the footnotes I get an error msg.
var_a <- rep(0, 3)
var_b <- rep(1,3)
var_c <- rep(2, 3)
df <- data.frame(var_a=var_a, var_b=var_b, var_c=var_c)
kable(df, "latex", caption = "title", booktabs = T) %>%
kable_styling() %>%
add_footnote("Standard errors in parenthesis. P-values in brackets.", "P-values from Wald-test for $H_0$ Hazard Ratio = 1.",
footnote_order = c("alphabet", "alphabet"))
EDIT:
This is the error msg I get:
Error in add_footnote(., "Standard errors in parenthesis. P-values in brackets.", :
unused argument (footnote_order = c("alphabet", "alphabet"))
To begin with, I'm not a big fan of the pipe operator, when you make complex functions you tend to miss some tiny issues, like putting your footnotes in a vector:
mytable <- kable(df, "latex", caption = "title", booktabs = T)
mytable <- kable_styling(mytable)
add_footnote(mytable,c("Standard errors in parenthesis. P-values in brackets.",
"P-values from Wald-test for $H_0$ Hazard Ratio = 1.") )
I delete footnote_order I don't understand why you use it? And I'm not able to make it work...
I you want footnote to generate $H_0$ instead of \$H\_0\$, you have to write:
add_footnote(mytable,c("Standard errors in parenthesis. P-values in brackets.",
"P-values from Wald-test for $H_0$ Hazard Ratio = 1."), escape = FALSE )

How can I subscript names in a table from kable()?

Given a data.frame A, how can I use subscripted rows and columns names? Eventually I want produce a table through kable() in rmarkdown (output: word document).
A <- data.frame(round(replicate(3, runif(2)),2))
rownames(A) <- c("Hola123", "Hola234")
A
X1 X2 X3
Hola123 0.47 0.55 0.66
Hola234 0.89 0.45 0.20
How could I make all numbers from row and column names subscripted when creating a table through kable(A)?
I have tried:
rownames(A) <- c(expression(Hola["123"]), expression(Hola["234"]))
names(A) <- c(expression(X["1"]), expression(X["2"]), expression(X["3"]))
But it does not appears subscripted when creating the table through kable() in the .rmd file.
To add subscripts in a rmarkdown document, you can embed your text between two tilde: text~sub~.
When using function kable, any text in the table is recognized as markdown syntax. So that your rmarkdown code should be:
```{r}
A <- data.frame(round(replicate(3, runif(2)),2))
rownames(A) <- c("Hola~123~", "Hola~234~")
names(A) <- c("X~1~", "X~2~", "X~3~")
knitr::kable(A)
```
Just one note about bamphe's response is that the correct code is misspelled. It should be \\textsubscript{}. It is missing the second "t".
And completing the answer, you might choose to use the arguments row.names and col.names inside kable, in this way:
A <- data.frame(round(replicate(3, runif(2)),2))
rownames(A) <- c("Hola\\textsubscript{123}", "Hola\\textsubscript{234}")
knitr::kable(A,
row.names = T,
col.names = c("X\\textsubscript{1}", "X\\textsubscript{2}", "X\\textsubscript{3}"),
escape = F)
I, too, was looking for a method that would allow for subscript and superscript in both html and pdf formats in markdown tables with kable. After a bit of searching, I finally found the text reference method explained here by #yihui-xie : bookdownguide
(ref:foo) H~2~O where foo is the reference and H~2~O the text.
My code example shows how the text reference can be used. Make sure to follow the cardinal rules:
The reference needs to be unique throughout the document
The reference should not have a white space following the "to be inserted stuff"
The reference needs to be in its own paragraph and have an empty line both above and below it
Note that only the referenced "foo" and "fo" will give the subscripts while the ~[]~ method will only work in html but not pdf.
(ref:foo) CO~2~/CO~2~
(ref:fo) CO~2~
```{r chunk-to-show-the-text-reference-method, echo = FALSE }
library(dplyr)
library(knitr)
library(kableExtra)
# Make lists
dtmin_name <- c("ref/ref","refrigerant/CO2","(ref:foo)",paste0("ground/","(ref:fo)"),"ground/water","air/refrigerant","water/refrigerant","water/CO2")
temp_diff <- c( 2.3, 1.4, 0.8, 6.8, 14, 6, 4, 3.46)
# Make dataframe and column names
dtmin_df <- data.frame(dtmin_name,temp_diff, stringsAsFactors = FALSE)
colnames <- data.frame("Interface Type ", "dT~min~ Interval [K]", stringsAsFactors = FALSE)
colnames(dtmin_df) <- colnames
# Make Table
kable(dtmin_df, caption = "Typical dT~min~ Temperature Intervals", booktabs = TRUE, format.args = list(big.mark = ",")) %>%
kable_styling(bootstrap_options = c("striped", "hover"),latex_options = c("striped","scale_down"))```

knitr xtable highlight and add horizontal lines for the same row,

I am using knitr and xtable to automate my reporting procedure. I want to highlight a few rows of a table and have a horizontal line right above each row highlighted. The .Rnw file I am using reads as below:
\usepackage{colortbl, xcolor}
\usepackage{longtable}
\begin{document}
<<do_table, results = "asis">>=
library(xtable)
mydf <- data.frame(id = 1:10, var1 = rnorm(10), var2 = runif(10))
print(xtable(mydf), add.to.row = list(pos = list(0,2), command = rep("\\rowcolor[gray]{0.75}",2)),hline.after=c(0,2))
#
\end{document}
This works just fine, however, the table I am working with should be a longtable, if I adjust the last line of code to
print(xtable(mydf), add.to.row = list(pos = list(0,2), command = rep("\\rowcolor[gray]{0.75}",2)),hline.after=c(0,2),tabular.environment="longtable",floating=FALSE)
the output is quite ugly, and the rows are not highlighted as expected. Anyone might know an answer to this question?
thanks,
David
Sorry, slightly offtopic, but demonstrating a markdown-only solution for highlighting cells/rows easily:
> mydf <- data.frame(id = 1:10, var1 = rnorm(10), var2 = runif(10))
> library(pander)
> emphasize.strong.rows(c(1, 3))
> pander(mydf)
---------------------------
id var1 var2
----- ---------- ----------
**1** **0.7194** **0.6199**
2 0.8094 0.1392
**3** **-1.254** **0.5308**
4 0.4505 0.8235
5 -0.3779 0.7534
6 -0.3518 0.3055
7 1.759 0.5366
8 0.9822 0.9938
9 1.549 0.3589
10 -1.077 0.5153
---------------------------
That can be converted to LaTeX or pdf directly.
You are on the right track, but I am a bit confused: do you want the selected rows highlighted by hline and rowcolor? In my experience, rowcolor alone looks better, so I will assume that in my answer below (but you could easily use both, just append the \\hline command).
As a bonus, all code below assumes you use the LaTeX booktabs package, which gives correctly weighted rules (unlike hline). To be honest, I always work with booktabs, and I couldn't bother to adjust the code to use hline -- but if you prefer hline, replace all \toprule, \midrule and \bottomrule macros with \hline.
You seem to have missed that LaTeX longtables require a special header, and we need to supply that too as an element to the command vector of the add.to.row list (this may be the reason your typeset table looks bad).
longtable.xheader <-
paste("\\caption{Set your table caption.}",
"\\label{tab:setyourlabel}\\\\ ",
"\\toprule ",
attr(xtable(mydf), "names")[1],
paste(" &", attr(xtable(mydf), "names")[2:length(attr(xtable(mydf), "names"))], collapse = ""),
"\\\\\\midrule ",
"\\endfirsthead ",
paste0("\\multicolumn{", ncol(xtable(mydf)), "}{c}{{\\tablename\\ \\thetable{} -- continued from previous page}}\\\\ "),
"\\toprule ",
attr(xtable(mydf), "names")[1],
paste("&", attr(xtable(mydf), "names")[2:length(attr(xtable(mydf), "names"))], collapse = ""),
"\\\\\\midrule ",
"\\endhead ",
"\\midrule ",
paste0("\\multicolumn{", as.character(ncol(xtable(mydf))), "}{r}{{Continued on next page}}\\\\ "),
"\\bottomrule \\endfoot ",
"\\bottomrule \\endlastfoot ",
collapse = "")
With that taken care of, go ahead and print the xtable:
print(xtable(mydf),
floating = FALSE, % since longtable never floats
hline.after = NULL, % hline off since I use booktabs
add.to.row = list(pos = list(-1,
c(0, 2),
nrow(xtable(mydf))),
command = c(longtable.xheader,
"\\rowcolor[gray]{0.75}\n",
"%")), % comments out a spurious \hline by xtable
include.rownames = FALSE, % depends on your preference
include.colnames = FALSE, % depends on your preference
type = "latex",
tabular.environment = "longtable",
% xtable tries to escape TeX special chars, can be annoying sometimes
sanitize.text.function = function(x){x},
% not all dashes are meant to be math negative sign, set according to your data
math.style.negative = FALSE)
I hope my use of booktabs in the answer did not confuse you too much.
Keep knitting!
You might have more luck posting this on a latex forum. You should note that xcolor/longtable are not compatible: http://www.ukern.de/tex/xcolor.html.

Resources