Row indentation with add_indent() in 2nd column in kableExtra - r

I try to indent cells of the 2nd column of a dataframe using the kableExtra-package for RMarkdown. It seems add_indent() only works for the first column, therefore does not change anything in my table of the reprex below:
Reprex with dummy data:
---
output: pdf_document
---
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE)
library(tidyverse)
library(kableExtra)
group <- c(1, NA, NA, 2, NA, NA)
quest <- c("How is your mood today?", "good or very good", "bad or very bad",
"What colour is your hair?", "brown", "other")
percent <- c(NA, 80, 20, NA, 50, 50)
df <- tibble(group, quest, percent)
```
## Reprex
```{r, echo=TRUE}
# output without add_indent()
kable(df, booktabs = T, escape = T) %>%
add_header_above(header = c("Group" = 1,
"Question & answer options" = 1,
" %Agreement" = 1)) %>%
gsub("NA", " ", .)
```
```{r with indent, echo=TRUE}
# output with add_indent()
kable(df, booktabs = T, escape = T) %>%
add_header_above(header = c("Group" = 1,
"Question & answer options" = 1,
" %Agreement" = 1)) %>%
gsub("NA", " ", .) %>%
add_indent(positions = c(2,3,5,6))
Desired output: I would like to indent the rows 2, 3, 5, 6 of the 2nd column (that the answer options are intended below the questions and ideally also in italics). Italics could also be covered with cell_spec() but that works just column wise I think.
Is my desired output possible? (I guess it does not make sense to mix questions & answer options, but to keep up the format of an earlier report we would like to try it that way?)

Here are two possible ways.
Use kableExtra::group_rows isntead of an extra group column.
Add the indentation (kableExtra adds 1em) manually using cell_spec.
Option 1
```{r, echo = F}
df <- data.frame(quest, percent)
df %>%
mutate(quest = cell_spec(quest, italic = ifelse(row_number() %in% c(2,3,5,6), T, F))) %>%
kable(booktabs = T, escape = F) %>%
add_indent(c(2,3,5,6)) %>%
group_rows("Group 1", 1, 3) %>%
group_rows("Group 2", 4, 6) %>%
gsub("NA", " ", .)
```
Option 2
```{r, echo = F}
df <- data.frame(group, quest, percent)
df %>%
mutate(quest = cell_spec(quest, italic = ifelse(row_number() %in% c(2,3,5,6), T, F)),
quest = ifelse(row_number() %in% c(2,3,5,6), paste0("\\hspace{1em}", quest), quest)) %>%
kable(booktabs = T, escape = F) %>%
gsub("NA", " ", .)
```

Related

RMarkdown: Color largest percentage in each row of Kable?

How can RMarkdown correctly color the largest percentage in each row of Kable? The code below incorrectly colors the cell based on the descend order from the 1st digit of the percentages. Thank you in advance!
Code:
---
title: "Color Max Percentage"
output:
html_document: default
pdf_document: default
---
```{r setup, include = F}
library(tidyverse)
library(knitr)
library(kableExtra)
options(knitr.table.format = "html")
df = data.frame(
x = c(1, 2, 3, 4, 5),
a = c("12.7%", "14.0%", "49.2%", "20.4%", "23.2%"),
b = c("35.6%", "19.0%", "9.1%", "25.5%", "11.2%"),
c = c("6.9%", "54.1%", "31.3%", "15.4%", "17.5%")
)
df <- df %>%
# adorn_totals('row') %>%
rowwise() %>%
mutate(across(a:c, ~cell_spec(.x, format = "html",
color = ifelse(.x == max(c_across(a:c)), "red", "blue"))))
df %>%
kable(escape = F) %>%
kable_styling()
```
(Incorrect) output:
You are trying to take the maximum of character vectors (i.e. c("12.7%", "35.6%", "6.9%")) and in R,
max(c("12.7%", "35.6%", "6.9%"))
#> [1] "6.9%"
and from ?max and ?comparison,
Character versions are sorted lexicographically, and this depends on the collating sequence of the locale in use: the help for ‘Comparison’ gives details.
Character strings can be compared with different marked encodings (see Encoding): they are translated to UTF-8 before comparison.
sort(c("12.7%", "35.6%", "6.9%"), decreasing = TRUE)
#> [1] "6.9%" "35.6%" "12.7%"
So, we need to convert them to numbers before comparing using readr::parse_number() and to print the cell values with percent format we can use formattable::percent() function.
---
title: "Color Max Percentage"
output:
html_document: default
pdf_document: default
---
```{r setup, include = F}
library(tidyverse)
library(knitr)
library(kableExtra)
options(knitr.table.format = "html")
df = data.frame(
x = c(1, 2, 3, 4, 5),
a = c("12.7%", "14.0%", "49.2%", "20.4%", "23.2%"),
b = c("35.6%", "19.0%", "9.1%", "25.5%", "11.2%"),
c = c("6.9%", "54.1%", "31.3%", "15.4%", "17.5%")
)
df <- df %>%
# adorn_totals('row') %>%
mutate(across(a:c, ~ readr::parse_number(.x) / 100)) %>%
rowwise() %>%
mutate(across(
a:c,
~ cell_spec(
formattable::percent(.x, digits = 1),
format = "html",
color = ifelse(.x == max(c_across(a:c)), "red", "blue")
)
))
df %>%
kable(escape = F) %>%
kable_styling()
```

Allow duplicated names in binded tables

UPDATE for why I changed my votes.
This code has the table displayed but R doesn't knit pdf.
all_jt %>%
kbl(longtable = T, booktabs = T,
caption = "table") %>%
remove_column(7) %>%
add_header_above(c(" " = 2, "Year 1" = 4, "Year 2" = 4)) %>%
kable_styling(latex_options = c("repeat_header"))
Quitting from lines 13-37 (test_table.Rmd)
Error in remove_column(., 7) :
Removing columns was not implemented for latex kables yet
switching to select(-7) as in here Remove_Column from a kable table which will be output as latex/pdf doesn't work because R doesn't like duplicated column names.
I have two ANOVA tables, jt_1 and jt_2 below, that I want to merge and keep 1 column for the model term only. As I remove the duplicated column, R added .1 to the tail of columns' 7, 8, 9 and 10 names.
library(emmeans)
library(stringr)
warp.lm <- lm(breaks ~ wool * tension, data = warpbreaks)
jt_1 <- print(joint_tests(warp.lm), export = T) %>% as.data.frame()
jt_2 <- jt_1
all_jt <- cbind(jt_1, jt_2) %>%
setNames(gsub("summary.", "", colnames(.)))
all_jt[,-6]%>% #to remove the duplicated column for model term
data.frame(check.names = F) %>%
kbl(longtable = T, booktabs = T,
caption = "table") %>%
add_header_above(c(" " = 2, "Year 1" = 4, "Year 2" = 4)) %>%
kable_styling(latex_options = c("repeat_header"))
Here is a brief idea of what I need.
Many thanks in advance.
You can use remove_column function from kableExtra to remove a column instead of all_jt[,-6] which makes the column name unique.
library(knitr)
library(kableExtra)
all_jt %>%
kbl(longtable = T, booktabs = T,
caption = "table") %>%
remove_column(7) %>%
add_header_above(c(" " = 2, "Year 1" = 4, "Year 2" = 4)) %>%
kable_styling(latex_options = c("repeat_header"))
R does not like duplicate column names in data.frames. If you step through your last code block line by line you will notice that all_jt[, -6] makes column names unique by adding the ".1" suffix.
The/a solution is to provide column names to kbl directly, e.g.
all_jt[,-6] %>%
kbl(longtable = T, booktabs = T,
col.names = gsub("\\.\\d", "", names(.)),
caption = "table") %>%
add_header_above(c(" " = 2, "Year 1" = 4, "Year 2" = 4)) %>%
kable_styling(latex_options = c("repeat_header"))
This produces

How can I get rid of the back-tic inside a table generated by `kableExtra` in `xaringan` slides?

How can I get rid of the back-tic inside this table generated by kableExtra in xaringan slides?
library(knitr)
library(kableExtra)
text_tbl <- data.frame(
a= c("1", "2","...","L",""),
b= c("$O_{11}$","$O_{21}$","...","$O_{L1}$","$n_{.1}$"),
c= c("$O_{11}$","$O_{22}$","...","$O_{L2}$","$n_{.2}$"),
d= c("...","...","...","...","..."),
e= c("$O_{C1}$","$O_{C2}$","...","$O_{LC}$","$n_{.C}$"),
f= c("$n_{1.}$","$n_{2.}$","...","$n_{L.}$","$N$"))
kable(text_tbl, "html", booktabs = T, col.names = c("","1","2","...","C"," "), escape=F) %>%
kable_styling(full_width = F,bootstrap_options = "striped") %>%
add_header_above(c(" Variável A", "Variável B" = 4, " ")) %>%
column_spec(1, bold = T) %>%
column_spec(2)
I inspected the HTML code generated, and I didn't see any back-tics.
You can replace the maths $ with \\( or \\). E.g. $O_{11}$ with \\(O_{11}\\) instead.
library(knitr)
library(kableExtra)
text_tbl <- data.frame(
a= c("1", "2","...","L",""),
b= c("\\(O_{11}\\)","\\(O_{21}\\)","...","\\(O_{L1}\\)","\\(n_{.1}\\)"),
c= c("\\(O_{11}\\)","\\(O_{22}\\)","...","\\(O_{L2}\\)","\\(n_{.2}\\)"),
d= c("...","...","...","...","..."),
e= c("\\(O_{C1}\\)","\\(O_{C2}\\)","...","\\(O_{LC}\\)","\\(n_{.C}\\)"),
f= c("\\(n_{1.}\\)","\\(n_{2.}\\)","...","\\(n_{L.}\\)","\\(N\\)"))
kable(text_tbl, "html", booktabs = T, col.names = c("","1","2","...","C"," "), escape=F) %>%
kable_styling(full_width = F,bootstrap_options = "striped") %>%
add_header_above(c(" Variável A", "Variável B" = 4, " ")) %>%
column_spec(1, bold = T) %>%
column_spec(2)

LaTex table in knitr with complex structure (rotating multirow text, removing column separators)

I need to create a latex table in RStudio for pdf output with the following structure:
This table was created for html output with the following code:
mat <- data.frame(a = c("column header","column header"),
rowx=c("row1","row2"),b = c("a","b"),
c = c("x","y"))
kable(mat, align = "c",col.names = c("","","v1","v2")) %>%
kable_styling(bootstrap_options = "striped", full_width = F,
position = "left",font_size = 12) %>%
column_spec(1, bold = T,width="2em",extra_css="transform: rotate(-90deg);") %>%
collapse_rows(columns = 1, valign = "middle") %>%
add_header_above(c(" " = 2, "row header" = 2))
I need to create a similar structure with LaTeX tables.
His is how far I got:
mat <- data.frame(a = c("column header","column header"),
rowx=c("row1","row2"),b = c("a","b"),c = c("x","y"))
kable(mat, align = "c",col.names = c("","","v1","v2")) %>%
kable_styling(bootstrap_options = "striped", full_width = F, position = "left",font_size = 12) %>%
collapse_rows(columns = 1, latex_hline = "none") %>%
add_header_above(c(" " = 2, "rows" = 2))
So I still need at least 2 more things:
rotate the label in the very first column
remove the spurious leftmost column separator in the second row.
Can this be achieved with kableExtra commands and parameters?
Here's a shot with huxtable (my package):
as_hux(mat, add_colnames = TRUE) %>%
insert_row(c("", "", "rows", "")) %>%
merge_cells(3:4, 1) %>%
merge_cells(1, 3:4) %>%
merge_cells(1:2, 1:2) %>%
set_rotation(3, 1, 90) %>%
set_bottom_border(0.4) %>%
set_bold(1:2, everywhere, TRUE) %>%
set_wrap(3, 1, TRUE) %>%
set_bottom_padding(4, -1, 48) %>%
set_bottom_padding(3, -1, 30) %>%
set_row_height(c("1em", "1em", "1.5em", "1.5em")) %>%
quick_pdf()
I have to admit, this took a lot of tweaking. TeX tables are hard to understand....

Set col names and headers (above) to weird characters for tables with knitr, kableExtra and Latex in R markdown

I'm trying to create a table in Rmarkdown (for pdf) based on the diamonds data set and I want to change some column names and headers above the column names, I would like to know how I can set some headers in italic or bold and some headers should be a symbol (like the one for partial eta squared) or a complete formula. I've included my R code (and I have installed Latex) with the table as a picture (not adjusted yet).
```{r setup, include=FALSE}
setwd("~/Desktop/Tables")
knitr::opts_chunk$set(echo = FALSE)
# global options
options(knitr.table.format = "latex")
# show space instead of NA in tables
options(knitr.kable.NA = '')
library(tidyverse)
library(knitr)
library(kableExtra)
df = diamonds
```
```{r message=FALSE, warning=FALSE}
df_table = df %>%
summarise(avg = round(mean(price), 2),
sd = round(sd(price), 2),
n = n(),
range = round(max(price), 2)) %>%
mutate(grouping = "Total") %>%
select(grouping, avg, sd, n, range) %>%
bind_rows(df %>%
group_by(cut) %>%
summarise(avg = round(mean(price), 2),
sd = round(sd(price), 2),
n = n(),
range = round(max(price), 2)) %>%
mutate(grouping = as.character(cut)) %>%
select(grouping, avg, sd, n, range))
kable(df_table,
booktabs = TRUE,
linesep = "",
col.names = c("Grouping", "M in italic", "SD in italic", "N not
italic", "some weird formula for the range" )) %>%
kable_styling(latex_options = c("HOLD_position", "scale_down")) %>%
add_header_above(c(" " = 1, "the formula for the variance" = 4))
```
Set escape = FALSE in your call to kable and add_header_above and use LaTeX in your column headings. I should admit that it's a mystery to me exactly how many backslashes should be added to get the desired result.
kable(df_table,
booktabs = TRUE,
linesep = "",
col.names = c("Grouping", "$M$", "$SD$", "N", "$\\eta$"), escape = FALSE) %>%
kable_styling(latex_options = c("HOLD_position", "scale_down")) %>%
add_header_above(c(" " = 1, "$\\\\operatorname{Var}[X]$" = 4), escape = FALSE)

Resources