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.
Related
Let's say I have the following rmd:
---
title: "Table won't work"
author: "Exhausted student"
date: "2022/01/28"
output:
bookdown::word_document2
---
```{r table, echo=F, warning=F, message=F}
library(tidyverse)
a <- tibble(
constants = c("c", "NA", "h", "e", "H2O"),
values = c(2.998e8, 6.022e23, 6.626e-34, -1.602e-19, 18.02)
)
knitr::kable(a, digits = 35)
```
which produces this table in Word.
The Problem
I need the scientific format to use superscripts and multiply sign (i.e. 2.998 × 108), and some cells requires subscript (e.g. NA and H2O).
The final table should look like this. How can I do that?
What I've tried/would never try
huxtable package and its markdown() function: I managed to format some contents as H~2~O, then enable markdown across table by huxtable(a) %>% `markdown<-`(TRUE). Which did not recognize the syntax, and apparently would not work in forseeable future according to the author.
flextable and as_sub(): Produces right format. I pass the lables to flextable::compose(), where the labels were something like as_paragraph(list_values = list("H", as_sub("2"), "O"). The code is obviously too lengthy; plus i have to manipulate cells one-by-one. Technically still doable, but I do have tables with 100+ cells needed formatting.
Output first, format in Word later: Again, needed manipulation one-by-one. Would be an option if it would work everything out automatically.
Convincing the school bureaucrats to accept html/pdf/latex as output: this is forever an impossible option.
Format outside word then export formatted table as image: strictly forbidden in the reports.
Edit: the table works now! Great thanks to Maël's answer, but please check my own findings to see my final result:
You can use tildes (~) to put in subscript and carets (^) for superscripts; and use sprintf to get the expected digit format:
---
title: "Table won't work"
author: "Exhausted student"
date: "2022/01/28"
output:
bookdown::word_document2
---
```{r table, echo=F, warning=F, message=F}
library(tidyverse)
expSup <- function(x, digits=3) {
sprintf(paste0("%05.", digits, "f x 10^%d^"), x/10^floor(log10(abs(x))), floor(log10(abs(x))))
}
a <- tibble(
constants = c("c", "N~A~", "h", "e", "H~2~0"),
values = expSup(c(2.998e8, 6.022e-23, 6.626e-34, -1.602e-19, 18.02))
)
knitr::kable(a)
```
An option that probably falls in the no-go zone for this open issue:
Create a html document,
Insert html tags for subscripts,
Open the html file (not the viewer),
ctrl+c, then ctrl+v in your word file.
---
output: html_document
---
```{r table, echo=F, warning=F, message=F}
library(tidyverse)
library(gt)
a <- tibble(
constants = c("c", "N<sub>A</sub>", "h","e","H<sub>2</sub>O"),
values = c(2.998e8, 6.022e23, 6.626e-34, -1.602e-19, 18.02)
)
a %>%
mutate(constants = map(constants, html)) %>%
gt() %>%
fmt_scientific(values)
The expSup() function in Maël's answer converted the scientific formats into markdown format. For my script, I modified the function a little:
exp_sup <- function(x, digits = 3) {
sprintf(paste0("%05.", digits, "f $\\times$ 10^%d^"), x / 10^floor(log10(abs(x))), floor(log10(abs(x))))
}
I changed "f x 10^%d^" to "f $\\times$ 10^%d^", so that it displays proper multiply symbol (×).
Using the format in flextable
The format works great in Kable. However, a large portion of my workflow requires flextable to make caption/cross reference/publication style/etc. Unfortunately, although the expSup function automatically formats scientific notations into markdowns, it cannot make markdown syntax work in flextable.
However, ftExtra::colformat_md() can. Hence, by combining the modified exp_sup() function with ftExtra, I was finally able to produce an academic-looking table:
Below is the code for my final output; if you are also trying to produce reproducible academic reports with lots of tables in Word format, hope this helps!
---
title: "The tables work!"
author: "Satisfied Student"
date: "2022/01/28"
output:
bookdown::word_document2:
reference_docx: styleRef.docx
---
```{r setup, include = F}
library(easypackages)
packages(
"tidyverse",
"flextable", # This works best for my workflow
"ftExtra", # For markdown formatting work in flextable
"officer" # You can customize appearance/format/etc. of caption *prefixes*
)
knitr::opts_chunk$set(
warning = FALSE,
message = FALSE,
echo = FALSE,
# Make the table caption format definable in reference_docx styles
tab.cap.style = "Table Caption",
# Make "Table 1:" prefixes not bold
tab.cap.fp_text = fp_text_lite(bold = FALSE)
# The tab.cap settings MUST be in a separate chunk from tables
)
# Converts scientific format to markdown
exp_sup <- function(x, digits = 3) {
sprintf(paste0("%05.", digits, "f $\\times$ 10^%d^"), x / 10^floor(log10(abs(x))), floor(log10(abs(x))))
}
# The $\\times$ makes proper multiply symbols
```
```{r table}
a <- tibble(
constants = c("c", "N~A~", "h", "e", "H~2~O"),
values = c(2.998e8, 6.022e23, 6.626e-34, -1.602e-19, 18.02)
)
a %>%
mutate(values = exp_sup(values)) %>%
flextable() %>%
set_caption(
caption = "(ref:foo)", # Produces formatted caption text
style = "Table Caption"
) %>%
colformat_md() %>% # Subscript/superscript works in flextable now!
theme_booktabs() %>% # The 3-part-table used in academics
align(align = "center", part = "all") %>% #Align everything to center
set_table_properties(layout = "autofit") # Comfortable width/height every cell
```
(ref:foo) A scientifically formatted `flextable` with ^superscripts^ and ~subscripts~
Your code should look like this:
```
{r table, echo=F, warning=F, message=F}
library(tidyverse)
a <- tibble(
constants = c("c", "NA", "h", "e", "$H_2O$"),
values = c("$2.998 * {10^{8}}$", "$6.022 * {10^{-23}}$", "$6.626 * {10^{-34}}$", "$-1.602 * {10 ^{-19}}$", "$1.802 * {10^{1}}$")
)
knitr::kable(format = "html", a, digits = 35)
```
Which will give you the output like this:
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.
I want to print stargazer table using kable.
When I am running the code in markdown, I get the stargazer table but with multiple lines with the sign | between those lines before the table.
I also get a warning message at the beginning:
Warning in kable_markdown(x = structure(c("", "<table style=\"text-
align:center\"><caption><strong>Crude models: OR for mRS at discharge >3
with 95% CI</strong></caption>", : The table should have a header (column
names)
my output looks like this:
This is my code for the table (with some changes):
mod.example1 <- glm(bad_outcome~x1+x2+x3+x4, family = "binomial", data = dat0)
mod.example2 <- glm(bad_outcome~x1+x2+x3+x4, family = "binomial", data = dat1)
CI.list <- list(exp(confint(mod.example1)),exp(confint(mod.example2)))
my.stg <- stargazer(
title = "my models: OR for bad outcome",
mod.example1
mod.example2,
type="html",
digits = 2,
t.auto = FALSE,
model.numbers = F,
keep.stat = "n",
report = c("vc*sp"),
omit = "Constant",
star.cutoffs = c(0.05,0.01,0.001),
no.space = FALSE,
single.row = F,
dep.var.labels = c("***bad outcome***"),
covariate.labels = c("x1","x2","x3","x4"),
column.labels = c("-**dat0**-", "-**dat1**-"),
ci= T,
ci.custom = CI.list,
apply.coef=exp)
and in a new chunk:
kable(my.stg)
The table is printed but only after the multiple lines / rectangles.
I also ran the code from other computers and then the problem did not happen.
What could cause this?
Update : after a lot of research, i recognized that the problem occurred only after updating my R version from 3.4.0 to 3.4.1.
After updating to the new version, it also made me update knitr package from 1.16 to 1.17 and only that version gives the mentioned error.
So, i downgraded knitr from 1.17 to 1.16 and that solved the problem.
You do not need to use kable() function for generating stargrazer tables in markdown. Just add {r results='asis'} to the beginning of the chunk which includes stargrazer().
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"))```
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.