wrap text in knitr::kable table cell using "\n" - r

How can I wrap a cell in a knitr::kable table cell using \n?
I want to generate a .rmd file containing some tables where one column needs text wrapping. The places where the wrapping should occur are marked with \n. I tried (this is a standalone .rmd document):
---
output: pdf_document
---
## A Table with text wrap
```{r cars}
knitr::kable(data.frame(col1 = c("a", "b"), col2 = c("one\ntwo", "three\nfour")))
```
..but this doesn't work. Instead of staying in col2, the wrapped part lives on the next line of col1.
Expected output is:
col1 | col2
-------------
a | one
| two
b | three
| four
Solutions using other packages than knitr are welcome as long as they allow to print (nearly) as nice.

A fire-and-forget solution for flexible dual HTML/PDF of standard tables. It incorporates kableExtra's linebreak function outlined by #snoram.
Assumption: You use <br> as your line break indicator.
```{r}
knit_table(df1)
```
Code
library(dplyr)
library(knitr)
library(kableExtra)
knit_table <- function(df){
if (is_html_output()) {
df %>%
kable("html", escape = F) %>%
kable_styling()
} else {
df <- data.frame(lapply(df, function(x) {gsub("<br>", "\n", x)}), stringsAsFactors = F)
df %>%
mutate_all(linebreak) %>%
kable("latex", booktabs = T, escape = F)
}
}
Data
df1 <- data.frame(col1 = c("a", "b"),
col2 = c("one<br>two", "three<br>four"))

If you don't mind using kableExtra you can definitely achieve this, here is one example:
library(kableExtra)
knitr::kable(data.frame(col1 = c("a", "b"), col2 = linebreak(c("one\ntwo", "three\nfour"))),
escape = FALSE)
More details here.

Related

How to handle the overlay of kable output with page number?

I use kbl() function, in a rnw file that I compile in a pdf with knitr, to make a table starting from a dataframe. I use kableExtra option scale_down to adapt the table size to page size. It works fine but the table overlay with the page number of my pdf output. I'd like to know what's the best way to handle this type of problem. Thanks in advance for the help.
You could add some Latex code that puts the tabular environment into a box and resizes the content. Below is an example using \resizebox
Here's tab, a LaTex table with Gaussian random numbers generated by kable:
```{r, message = F, warning=F}
library(knitr)
library(tidyverse)
library(kableExtra)
ncol <- 10
nrow <- 30
df <- map_dfc(1:ncol, ~ data.frame(round(rnorm(nrow), 2))) %>%
set_names(letters[1:ncol])
tab <- kbl(df, format = "latex")
```
And here's how to resize it by text height/width using resizebox (see this post on tex.stackexchange for details on how the scaling works)
```{r, results='asis'}
cat(
"\\begin{table}
\\centering
\\resizebox*{\\textwidth}{\\dimexpr\\textheight-2\\baselineskip\\relax}{%",
tab,
"\n}
\\end{table}"
)
```
Result for the 30x10 table
Let's double rows and columns (ncol <- 20; nrow <- 60)
Result for 60x20 table.
I have three suggestions. The first one is maybe set your table to the next page using \newpage in your Rmarkdown code which is latex code. The second option is maybe set latex_options="HOLD_position" in your Kable_styling function. This will set the table at a certain place which maybe could help your problem. The third option is using 'longtable = TRUE` which means that the table continues on the next page. Here is the code for option one and two with:
```{r}
library(knitr)
library(tidyverse)
library(kableExtra)
df <- data.frame(x = 1:10, y = 11:20)
kable(df) %>%
kable_styling(latex_options = "HOLD_position")
```
\newpage
```{r}
kable(df) %>%
kable_styling(latex_options = "HOLD_position")
```
Which looks like this:
Here is the code for option three:
```{r}
library(tidyverse)
library(knitr)
library(kableExtra)
df <- data.frame(x = 1:50, y = 11:60)
kable(df, "latex", longtable = T, booktabs = T) %>%
kable_styling(latex_options = c("repeat_header"), font_size = 7)
```
Looks like this:

Mathematical Symbols in r [duplicate]

I am creating presentation using R Markdown with PDF (Beamer) as output. I am using library kableExtra for some formatting.
The following code gives me the expected result
library(knitr)
# library(kableExtra)
# create data frame
df <- data.frame(mean = c(1,2,3), beta = c(5,6,7))
# print data frame to slide
knitr::kable(df,
col.names = c("mean", "$\\beta_t$"))
However, when I use library(kableExtra) as in code below, the printed PDF show $\beta_t$ instead of the Greek letter beta.
library(knitr)
library(kableExtra)
# create data frame
df <- data.frame(mean = c(1,2,3), beta = c(5,6,7))
# print data frame to slide
knitr::kable(df,
col.names = c("mean", "$\\beta_t$"))
Is there any good way to rename the column name to Greek letter while using library(kableExtra)?
Use escape = FALSE in the call to kable():
# print data frame to slide
knitr::kable(df,
col.names = c("mean", "$\\beta_t$"),
escape = FALSE)
This produces
It looks a little nicer using booktabs = TRUE:
but you'll need to add
header-includes:
- \usepackage{booktabs}
to the document YAML since you're using beamer.

changing text colour in kable, in Rmarkdown, in latex with % label leads to unwanted "\" proceeding % label when knit

I'm trying to knit a table in a large Rmarkdown document. The table represent disease levels on a farm and thus some are expressed as percentages percentages. When the disease levels are above target I would like to highlight by changing the color of the font to red. This works fine when text does not have a % label, but when I escape the % label the % label in the PDF document is always proceeded by an unwanted "". I'm a vet not a data scientist I have spent many hours on this but can't find an answer.
The original document is extremely complex pulling data from many sources to generate the current disease levels and targets using shiny input to determine various options so not possible to use code from the original document. But I have produced a very minimal reproducible example below
require(kableExtra)
require(scales)
library(knitr)
require(tidyverse)
knitr::opts_chunk$set(echo = TRUE)
MDF = data.frame(a = label_percent()(.07),b = label_percent()(.05))
MDF$a = as.character(MDF$a)
MDF$b = as.character(MDF$b)
MDF[1,] = apply(MDF[1,],2,function(f) gsub("%", "\\\\%", f))
MDF = MDF %>% mutate(a = cell_spec(a, color = ifelse(a > 6,"red","black")))
kable(MDF, "latex", escape = F, booktabs = T)
As far as I get it the issue is that the percent sign in the conditionally formatted cell gets escaped twice, once via the gsub and once via kable itself so that you end up with an additional \textbackslash() inserted in you latex code. Hence, one option to solve your issue would be to manually escape only the percent signs in the column to which you don't apply the conditional formatting:
---
title: "Untitled"
output: pdf_document
---
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE)
```
```{r}
require(kableExtra)
require(scales)
library(knitr)
require(tidyverse)
MDF = data.frame(a = .07, b = .05) %>%
mutate(across(c(a, b), percent)) %>%
# Escape percent sign in column b only
mutate(across(c(b), ~ gsub("%", "\\\\%", .x))) %>%
mutate(a = cell_spec(a, color = ifelse(a > 6,"red","black")))
kable(MDF, "latex", escape = F, booktabs = T)
```

table with long text, bullet points and specific table width

I want a table to have bullet points in one column and to have a specific table width (in order to be placed on one page when rendered to PDF).
How can I achieve this in rmarkdown using one of the many packages out there?
What I have tried and have so far:
---
output: pdf_document
---
```{r, include = FALSE}
df <- data.frame(col1 = "Some really long text here. I mean some reeeeeaaly loooong text. So long, it should be wrapped. Really.",
col2 = "* bullet point 1\n * bullet point 2", col3 = "Yes, there is still another column.")
```
# Attempt 1: kableExtra
```{r, echo = FALSE, warning = FALSE}
library(kableExtra)
df1 <- df
df1$col2 <- linebreak(df1$col2)
knitr::kable(df1, escape = FALSE) %>% column_spec(1, width = "15em")
```
# Attempt 2: pander
```{r, echo = FALSE}
pander::pander(df, keep.line.breaks = TRUE, style = 'grid', justify = 'left')
```
This renders to:
As you can see both options have caveats. The kableExtra version does have a specific table width that fits on one page but does not show bullet points nicely. Whereas the pander solution renders the bullet points nicely but spans multiple pages, because I don't know how to specifiy the table width in pander.
Is there a solution that can do both?
Related questions are for example here and there.
An alternative solution based on kableExtra (optional: with footnotes)
This approach allows to add a caption, to manually add footnotes within the table, and to fix column widths.
To create the bullet point list:
"thicker" \cdots from LaTex are employed as bullets (alternatives see here)
linebreaks are forced with \n (indentation is therefore not as nice as with the pander approach from #daroczig).
MWE
library(stringi); library(kableExtra); library(dplyr)
string_short <- "Descriptor"
string_long <- substr(stri_rand_lipsum(1), 1, 50)
# add footnotes manually within table
string_bulletlist <- "$\\boldsymbol{\\cdot}$ bullet point 1: foo$^{a}$ \n $\\boldsymbol{\\cdot}$ bullet point 2: bar$^{b}$"
df <- data.frame(col1 = c(string_short, string_short),
col2 = c(string_bulletlist, string_bulletlist),
col3 = c(string_long, string_long)
)
col_names <- c("Descriptor", "Description with list", "Some comment")
# header: bold column names
colnames(df) <- paste0("\\textbf{", col_names,"}")
# add footnote with kableExtra commands
names(df)[1] <- paste0(names(df)[1], footnote_marker_symbol(1))
df %>%
mutate_all(linebreak) %>% # required for linebreaks to work
kable(
"latex",
escape = F,
booktabs=TRUE,
align = "l",
caption = 'kableTable with bullet list and footnote') %>%
# kable_styling(full_width = F) %>% # makes no difference here
footnote(general = "General comment of the table.",
alphabet = c("Footnote A;", "Footnote B;"),
symbol = c("Footnote Symbol 1")) %>%
column_spec(1, width = "5em") %>% # fix width column 1
column_spec(2, width = "10em") %>% # fix width column 2
column_spec(3, width = "15em") # fix width column 3
To [improve line spacing[(https://stackoverflow.com/questions/53794142/increase-line-row-spacing-with-kableextra), one can add the following before & after code chunk in the Rmd:
\renewcommand{\arraystretch}{1.5} <!-- increase line spacing for the table -->
RMD CHUNK HERE
\renewcommand{\arraystretch}{1} <!-- reset row hight/line spacing -->
Comment:
I also tried the pander approach from #daroczig and made the following experiences:
Pro: nice line spacing plus a "real bullet list" (compared to the $\boldsymbol{\cdot}$-workaround in the kableExtra approach).
Con: a large blank space is included after the bullet list
In addition, when using the pander approach in an Rmd file using the huskydown thesis template the footnotes greatly messed up the table alignment.
Use the split.table parameter of pandoc.table (that is being called by pander in the background) or disable the table splitting in general via panderOptions's table.split.table, eg
pander::pander(df, keep.line.breaks = TRUE, style = 'grid', justify = 'left', split.table = Inf)
or
library(pander)
panderOptions('table.style', 'grid')
panderOptions('table.alignment.default', 'left')
panderOptions('table.split.table', Inf)
panderOptions('keep.line.breaks', TRUE)
pander(df)

R, Latex and RMarkdown: table() input for xtable() missing column and row labels?

I am trying to create a pretty LaTeX table where the names of the row and column variables of a table are included when using the xtable library.
MWE:
```{r results="asis"}
test <- data.frame(Apples=c(1,2,3), Oranges=c(4,5,6), Watermelons=c(7,8,9))
testxtab <- xtable(with(test,table(Apples,Oranges)))
print(testxtab, comment=FALSE)
```
The result is a LaTeX table that is missing the "Apples" and "Oranges" labels. How do I include them?
I'm sure you could adapt this to xtable, but here's one approach you can take using pixiedust. (It isn't a very elegant solution, but given the structure of the table object, I'm not sure elegant is an option).
library(pixiedust)
obj <- with(test, table(Apples, Oranges))
dimnames <- names(attr(obj, "dimnames"))
head <-
rbind(c("", dimnames[2], rep("", ncol(obj) - 1)),
c(dimnames[1], colnames(obj))) %>%
as.data.frame(stringsAsFactors = FALSE)
body <- cbind(rownames(obj), obj) %>%
as.data.frame(stringsAsFactor = FALSE)
dust(body) %>%
redust(head, part = "head") %>%
sprinkle(rows = 1,
cols = 2:4,
merge = TRUE,
part = "head") %>%
medley_bw() %>%
sprinkle_print_method("latex")

Resources