R Kable: Rotating Text in Column Grouping - r

I would like to wrap and rotate column HEADER headings in a kable-latex table. I can control the width of the column using column spec, but I need to group columns in my table with a header, and it is the names in the header that I want to rotate and wrap. A very basic example of my table is below.
example <- data.frame(name="testname", score1=3, score2=2, score3=0)
table <- kable(example, format="latex", escape = F) %>%
column_spec(1:4, width = "5em") %>%
add_header_above(c(" " = 1, "Rhyme Product" = 2, "Sound ID Middle" = 1)) %>% add_header_above(c(" " = 1, "Exploring Words" = 2, "Early Skills" = 1), bold = T)
I would like to flip the first set of column groupings (Rhyme Product and Sound ID Middle) on their side (angle = -45) and wrap the text on two separate lines taking up a lot less space. Is this possible?

This one is a pretty simple fix. I'm surprised no one has answered it over the years. One possibility is that the setting did not exist when this question was answered.
To add the line breaks, add a \n to the column names where you would like the breaks to be. To rotate, add angle = "-45" to the add_header_above line you would like to modify. See the code below.
library(tidyverse)
library(kableExtra)
example <- data.frame(name="testname", score1=3, score2=2, score3=0)
table <- kable(example, format="latex", escape = F) %>%
column_spec(1:4, width = "5em") %>%
add_header_above(c(" " = 1, "Rhyme \nProduct" = 2, "Sound ID \nMiddle" = 1), angle = "-45") %>%
add_header_above(c(" " = 1, "Exploring Words" = 2, "Early Skills" = 1), bold = T)
table
Table output
Interestingly enough, the align argument accepts a vector of angles (i.e align = c("-45", "90")) to apply to each column. This is also true for row_spec. I have not seen anyone talking about this, nor is it anywhere in the documentation. It is really useful, however.

Related

is it possible to hide the footnote number reference in flextable footer section and replace with own text

I have a flextable:
df = data.frame(col1 = c(123,234,54,5), col2 = c(NA,1,2,3), col3 = 5:8)
df %>%
flextable() %>%
footnote(i = 1, j = 1,
value = as_paragraph('this is a footnote'),
ref_symbols = "1",
part = "body") %>%
footnote(i = 1, j = 1,
value = as_paragraph(as_b("Note (2):"),"This is another foonote"),
ref_symbols = "2",
part = "body")
that shows
What I would like to do is keep the flextable and footnotes, but remove the little 1 and 2 that appear in the footer section.
You can use add_footer_lines() to add any content in a new line and append_chunks() to append any content in existing cells/rows/columns (prepend_chunks() can sometimes be useful)
library(flextable)
df <- data.frame(col1 = c(123,234,54,5), col2 = c(NA,1,2,3), col3 = 5:8)
df |>
flextable() |>
add_footer_lines("Here is a foonote") |>
add_footer_lines(as_paragraph(as_b("Note (2):"),"This is another foonote")) |>
append_chunks(i = 1, j = 1, as_sup("12")) |>
append_chunks(i = 2, j = 1, as_sup("‡"))
The David Gohel's previous answer is fine for not getting this behavior of adding the symbol in the cell and in the footnote, but this previous answer will not add "1" or "2" in the cells of the table. In this case, you have to add these symbols by yourself in the cells, since the footnote func' require a "value" parameter (or you get Error in mapply(function(x, y) { : argument "value" is missing, with no default).
In order to add ¹, ², etc. in the cells of the table, I suggest to use a superscript generator (e.g., here), and a paste0 func' to modify the cells and add the symbol ¹ to the data; then use the add_footer_lines func' to create the footnote that you want, without the symbol at the beginning of the footnote (see David Gohel's previous answer).
PS: for a good readability of the "ref_symbols", I prefer to use letters when the symbol appears next to a number (e.g., I use "† ", "‡ ", "A" or "B") and I add number-footnote-symbol when it come next to a text (e.g., ¹ or ²).

KableExtra: colortbl's \cellcolor not filling entire cell when used in combination with \makecell

I'm looking for a workaround solution for a known issue where \cellcolor from the colortbl package does not work properly with \makecell. As mentioned, there probably already exists a workaround in Latex, but I'm hoping for a solution in terms of the R package kableExtra when producing pdfs using rmarkdown. Here's a screenshot; as can be seen, some cells are not filled entirely.
Here's a minimally reproducible example in rmarkdown:
library(kableExtra)
library(tidyverse)
# Data --------------------------------------------------------------------
df <- tribble(
~col1, ~col2,
"really long text that needs to be broken into multiple lines so it can fit", 4,
"really long text that needs to be broken", 4,
"really long text that needs a fix", 4,
) %>%
modify_at(
.x = .,
.at = 1,
.f = stringr::str_wrap,
width = 25
)
# Table -------------------------------------------------------------------
df %>%
mutate(across(.cols = 1, .fns = linebreak, align = "l")) %>%
kbl(x = ., escape = FALSE) %>%
row_spec(row = 1:3, background = "#e5e5e5")
One possible fix is to specify keep_tex: true in the YAML and fix the issue in the .tex file manually before using pandoc. But I'm generating many tables and this can't possibly be efficient. Any suggestion of a potential workaround would be greatly appreciated.
Why not use column_spec to force the line wrap rather than using makecell and linewrap?...
library(tibble)
library(dplyr) #for the pipe
library(kableExtra)
df <- tribble(
~col1, ~col2,
"really long text that needs to be broken into multiple lines so it can fit", 4,
"really long text that needs to be broken", 4,
"really long text that needs a fix", 4,
)
kbl(df) %>%
column_spec(1, width = "30mm") %>%
row_spec(row = 1:3, background = "#e5e5e5")
Another solution that worked for my use case (where column_spec(width) fails), is based on leandriis's comment in this post. Specifically, we wrap the \colorbox command around the \makecell command to have a completely colored cell. For example \colorbox[HTML]{hexcode}{\makecell{text}}. This requires that we create our own custom linebreak function, which not only wraps our text in \makecell but also wraps that latex code in a \colorbox.
# Custom linebreak --------------------------------------------------------
linebreak_custom <- function(x, align = "l", linebreaker = "\n") {
ifelse(
# If '\n' is detected in a string, TRUE, or else FALSE
test = str_detect(x, linebreaker),
# For TRUE's, wrap text in \makecell and then in \colorbox
yes = paste0(
"\\cellcolor[HTML]{e5e5e5}{\\colorbox[HTML]{e5e5e5}{\\makecell[", align, "]{",
str_replace_all(x, linebreaker, "\\\\\\\\"), "}}}"
),
# Return as is if no '\n' detected
no = x
)
}
# Data --------------------------------------------------------------------
df <- tribble(
~col1, ~col2,
"really long text that needs to be broken into multiple lines so it can fit", 4,
"really long text that needs to be broken", 4,
"really long text that needs a fix", 4,
) %>%
modify_at(
.x = .,
.at = 1,
.f = stringr::str_wrap,
width = 25
)
# Table -------------------------------------------------------------------
df %>%
mutate(across(.cols = 1, .fns = linebreak_custom, align = "l")) %>%
kbl(x = ., escape = FALSE) %>%
row_spec(row = 1:3, background = "#e5e5e5")
This produces the desired output:
As noted, this solution may not be robust to future versions of kableExtra (as it involves, quite frankly, "hacking" the source code), and the solution suggested by Peter above should still be better in many use cases. I've created an issue via Github to bring this to their attention, so perhaps there could be an official fix in their code in the future.

How to have multiple font sizes in flextable header?

I have a flextable() where I want to make the header have two font sizes. One size for the main text (say, 20 pt font), and a smaller for the parenthetical text (12 pt font). Here's code that makes the entire header 20 pt.
Note: In the final solution, I'd prefer not to make the parenthetical text an entirely new row unless it can be as near to the original text as the below example shows.
library(flextable)
library(dplyr)
set_flextable_defaults(font.size = 20) #Works but makes all header size 20
flextable(test) %>%
set_header_labels(values = list(name = "Name", med_score = "Score (Median)", mean_score = "Score (Mean)")) %>%
align(align = "center", part = "header")
EDIT: Pictures added
Here's what it looks like currently:
And here's what I want it to look like:
Note: I made this goal table in PowerPoint. It looks different in many ways from the original one because I haven't formatted the original. The only difference that I'm trying to replicate is having (median) and (mean) being smaller than Score as well as them being in the same header cell.
You could use compose, as_paragraph and as_chunk to achieve it.
For reference: https://ardata-fr.github.io/flextable-book/cell-content-1.html#multi-content
library(flextable)
ft <- flextable(airquality[ sample.int(10),])
compose(
ft,
j = "Ozone",
part = "header",
value = as_paragraph(
"Ozone ",
as_chunk(
" (Median)",
props = fp_text_default(color = "#006699", font.size = 5)
)
)
)

keeping same height of row for DT table in output

I want to set the height of row constant or fixed for DT table output. for the table below you can see difference in height of rows.
so the scenario is when the number of character increases for eg second row in this case in first col then height should get adjust as same for all rows.
df <- data.frame(`quote` = c("the trader belongs to","trader have long ralationship withthe same market with my opinion on thaw its implemented mmnnhhh sdfghj fghj kjhgf tyui cvbnm",
"types of trads happens everytime when market slow","trades have leverage with",
"market is continious with the same platform trades"),
`share`= c(43,65,92,23,73),
`times` = c(86,98,55,12,08),
`parts`=c(4,7,4,8,3))
df<-datatable(df,
options = list(columnDefs =
list(list(className = 'dt-center',
targets = "_all"))),rownames = FALSE)
df
like in flextable i can do something like below but looking for fixed solution or any function for DT tables.
(ncols %in% c(4,5)) {
fl<-width(flxtable, width = d*0.3, j = 1)
fl<-width(flxtable, width = (d*0.7)/(ncols-1), j = 2:ncols)
d is left and right margin of docs template
I had success with this in the past:
DT::datatable(df) %>%
DT::formatStyle(names(df),lineHeight='80%')
Kudos to the post that helped me, however I fail to find it back now.

kableExtra: How does the add_header_above function work?

I want to add a row explaining the columns of my table. But the add_header_above function is a bit confusing. How do you use it? This is the built-in example:
x = kable(head(mtcars), "html")
# Add a row of header with 3 columns on the top of the table. The column span for the 2nd and 3rd one are 5 & 6.
add_header_above(x, header = c(" ", "Group 1" = 5, "Group 2" = 6))
You have to create a named vector corresponding to the header row you want, e.g. c("Group 1" = 5)
Each header item consists of the text and its "span"
"span" is a single number specifying how many columns the item spans in the header row.
These spans cumulate and have to sum to the total number of column in the table.
So, if you have a 7 column table, and wanted a header spanning the whole table, you could say:
add_header_above(myKe, header = c("Big title" = 7))`
If you wanted an empty header over an initial column of rownames, followed by a header spanning columns 2:3, another spanning 3:4, and the last 2 cells blank in your 7-column table, you would say:
add_header_above(myKe, header = c(" " = 1, "header1" = 2, "header2" = 2, " " = 2))
note: A header can't be blank, so you need to use a white space " " in "blank" cells.
Important Caveat: This construction of c("my header" = 7) won't work if your headers are constructed on the fly because tmp= "X"; c(tmp = 7) is interpreted as c("tmp" = 7)
Instead, you would have to say something like:
header = 7
names(header) = "X"
myKe = add_header_above(myKe, header = header)

Resources