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:
Related
I have a 500 x 500 dataset which I would like to be represented in kables in my PDF output. I've arbitrarily chosen 50 x 50 Kables for the output.
Each kabel cell will have an image in it^. Some of these examples will work with pure text so including the image is required in the minimum code.
In the code below, there is the setup and the 3 approaches I've taken:
the 500x500 approach which is obviously too big,
the list method which I can't get to actually render the tables,
the separate, dynamically named, objects^ approach which will render a table if called by exact name but can't get to render from a dynamic name.
The generation of the kables are in different code chunks to the output for ease of positioning in the PDF.
I have tried all these with results = 'asis' and it made no difference.
---
title: "Minimum Example"
date: "2022-11-19"
output: pdf_document
---
\section*{A Bit of Setup}
\renewcommand{\arraystretch}{1.7}
```{r setup}
library(kableExtra)
library(dplyr)
library(tidyr)
library(stringr)
library(png)
library(knitr)
# Image is displayed in each cell of the Kable, creating an example image
png(file="./ExampleImage.png")
par(bg='grey')
bob <- plot.new()
dev.off()
# Define size of data which needs to be represented in a kable.
totalSize_x <- 500
totalSize_y <- 500
```
\section*{Approach 1: Way too big to be displayed}
```{r Approach 1: The Big Boy}
TheBigBoi <- matrix('\\includegraphics[scale=1]{./ExampleImage.png}',totalSize_x, totalSize_y)
kable(TheBigBoi,
format = "latex",
escape = FALSE,
longtable = FALSE) |>
column_spec(1,border_left = T) |>
column_spec(totalSize_y,border_right = T) |>
kable_styling(latex_options=c("scale_down"))
# Gives the Errors
# Error: C stack usage 12426279 is too close to the limit
# Execution halted
```
\section*{Approach 2: A Nice List}
```{r Approach 2: A Nice List}
# Personally, I want this one to work as it's the least stupid solution.
maxKableCells <- 50 # As in that looks good for the images, I understand Kables can be bigger if they want to
TheLittleOne <- matrix('\\includegraphics[scale=1]{./ExampleImage.png}', maxKableCells, maxKableCells)
num_iterations <- (totalSize_x/maxKableCells) * (totalSize_y/maxKableCells)
myList <- vector(mode = "list", length = num_iterations)
for (i in 1:(num_iterations)){
myList[i] <- kable(TheLittleOne,
format = "latex",
escape = FALSE,
longtable = FALSE) |>
column_spec(1,border_left = T) |>
column_spec(maxKableCells,border_right = T) |>
kable_styling(latex_options=c("scale_down"))
}
```
Gonna put some text here
```{r Approach 2 Output}
myList[1] # - ! Undefined control sequence.
#l.177 ``\textbackslash begin\{table\}\n
# \textbackslash centering\n\textbacksl...
```
```{r Approach 2 Output Continued}
noquote(myList[1]) # - just prints out the latex code with extra slashes
```
\section*{Approach 3: Objectively the worst way to acheive this}
```{r Approach 3: Individual Kable Objects AKA Foolishness}
# The most stupid solution but the closest to working
maxKableCells <- 50 # As in that looks good for the images, I understand Kables can be bigger if they want to
TheLittleOne <- matrix('\\includegraphics[scale=1]{./ExampleImage.png}', maxKableCells, maxKableCells)
num_iterations <- (totalSize_x/maxKableCells) * (totalSize_y/maxKableCells)
for (i in 1:(num_iterations)){
assign(paste0('kable_', i), kable(TheLittleOne,
format = "latex",
escape = FALSE,
longtable = FALSE) |>
column_spec(1,border_left = T) |>
column_spec(maxKableCells,border_right = T) |>
kable_styling(latex_options=c("scale_down")))
}
```
Some filler text
```{r Approach 3 Output}
kable_1 # - This one works!
for (i in 1:num_iterations){
paste0('kabel_', i) #Returns nothing
print(paste0('kabel_', i)) # Prints like "kabel_1"
print(noquote(paste0('kabel_', i))) #Prints like kabel_1
noquote(paste0('kabel_', i)) # Returns nothing
}
```
^ I am aware this is a stupid thing to do, this whole thing is stupid but sometimes the tools we use are not our own choice.
I am creating a document with Rmarkdown. The document will have lots of different versions and all of the text for the different versions has been written in an Excel spreadsheet, which is then read into the Rmarkdown file. Inside the text, which sometimes differs between reports, there are keywords in square brackets which need to be replaced with r code. I am having trouble getting the rcode to evaluate inside the text and print out properly in the Rmarkdown output.
# Text like that in the Excel spreadsheet
report_text <- ("There are [NumberFruit] fruits in the fruitbowl. [HighestPercent]% of the fruit are [HighestPercentType].")
#Extract variables within the square brackets
variables <- str_extract_all(report_text, "\\[[A-Z,a-z]+\\]")
# Define all varaibles - the variables are the same in each report. The data in the actual report differs and is defined from a dataframe.
for (i in unlist(variables)){
if(grepl("NumberFruit", i)){
NumberFruit <- 10
} else if(grepl("HighestPercent", i)){
HighestPercent <- 56
} else if(grepl("HighestPercentType", i)){
HighestPercentType <- "apples"
} else if (length(unlist(variables)) > 3){
stop("Additional VARIABLE:",i, "has not been assigned")
}
}
Once the variables have been defined I would normally use something like below, but as the text isn't hardcoded into the Rmarkdown file this approach isn't possible.
final_text <- paste0("There are ",NumberFruit, " fruits in the fruitbowl. ",HighestPercent, "% are ",HighestPercentType, ".")
So I have tried formatting the text as per the paste option above, but this does not produce the desired output.
report_text2 <- gsub('\\[', '",',(gsub('\\]', ', "', report_text)))
#Also tried
report_text2 <- paste0(gsub('\\[', '",',(gsub('\\]', ', "', report_text))))
I then use r final text in the Rmarkdown text to create the text in the report. Both versions of the above code have the same result shown below.
Current Rmarkdown output: There are ",NumberFruit," fruits in the fruitbowl. ",HighestPercent, "% of the fruit are ",HighestPercentType, "."
Desired Rmarkdown output: There are 10 fruits in the fruitbowl. 56% of the fruit are apples.
I have googled for clues on what else to try but have not been able to find anything and am a bit stuck on where to go from here. Any advice on how to get this working would be greatly appreciated. I do not normally deal with text strings and feel like I am missing something fundamental here.
If we need to interpolate the variables created in RMD file, an option is with glue
library(glue)
library(stringr)
final_text <- glue::glue(str_replace_all(str_replace_all(report_text,
"\\[", "{"), "\\]", "}"))
Full code in RMD file
---
title: "test"
author: "akrun"
date: "16/03/2021"
output: html_document
---
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE)
```
## R Markdown
```{r test1}
report_text <- "There are [NumberFruit] fruits in the fruitbowl. [HighestPercent]% of the fruit are [HighestPercentType]."
NumberFruit <- 10
HighestPercent <- 56
HighestPercentType <- "apples"
```
```{r test2}
library(stringr)
final_text <- glue::glue(str_replace_all(str_replace_all(report_text, "\\[", "{"), "\\]", "}"))
```
`r final_text`
-output
Suppose i have a table that looks like :
x = matrix(runif(10*5),nrow=10,ncol=5)
When i display the matrix using kableextra, i want the highest value, per row, of say the last 2 rows, to be bolded.
I looked at this document https://rdrr.io/cran/kableExtra/f/inst/doc/awesome_table_in_pdf.pdf a lot and i did not found how to use cell_spec correctly to perform this goal.
I thought this would be easier than it turned out to be. As far as I can see, this is how to do it:
---
title: "Untitled"
output: pdf_document
---
```{r}
set.seed(123)
library(knitr)
library(kableExtra)
x <- matrix(round(runif(10*5),2), nrow=10,ncol=5)
j1 <- which.max(x[9,])
j2 <- which.max(x[10,])
col <- seq_len(ncol(x))
x[9,] <- x[9,] %>% cell_spec(bold = col == j1)
x[10,] <- x[10,] %>% cell_spec(bold = col == j2)
x %>% kable(booktabs = TRUE, escape = FALSE)
```
A few notes:
I rounded the values so they aren't so ugly when printed.
I couldn't see a way to do everything in one pipeline, though there probably is one. The trouble is that cell_spec is designed to work on vectors, not matrices.
Finally, the escape = FALSE in kable() is essential: otherwise you'll see the code to make it bold, rather than the bold entry itself.
I have read the bookdown book and still cannot figure this out. I am trying to create a Word report through bookdown. I want to use kableExtra to add striping to my tables and also to bold my last table row. Can kableExtra be used when knitting to Word ?
This is a subset of my code :
library(dplyr)
knitr::opts_chunk$set(echo = TRUE)
library(knitr) # required for kable
library(kableExtra) # required for kableExtra
options(knit.r.table.format = "markdown")
myRegion <- c("a", "b", "c")
Current_Perc_1 <- c(85.9, 90.8, 89.7)
Current_Perc_2 <- c(88.0, 91.0, 89.0)
tab_curr_est_2_times <- cbind(myRegion, Current_Perc_1, Current_Perc_2)
tab_curr_est_2_times <- as.data.frame(tab_curr_est_2_times, stringsAsFactors = FALSE)
tab_curr_est_2_times$Current_Perc_1 <- as.double(tab_curr_est_2_times$Current_Perc_1)
tab_curr_est_2_times$Current_Perc_2 <- as.double(tab_curr_est_2_times$Current_Perc_2)
tab_curr_est_2_times$curr_change_1_to_2 <- tab_curr_est_2_times$Current_Perc_2 - tab_curr_est_2_times$Current_Perc_1
tab_1_curr <- tab_curr_est_2_times
tab_1_curr[ nrow(tab_1_curr)+1 , ] <- NA
tab_1_curr$myRegion[ nrow(tab_1_curr) ] <- "BRITISH COLUMBIA"
tab_1_curr$Current_Perc_1[ nrow(tab_1_curr) ] <- 88.4
tab_1_curr$Current_Perc_2[ nrow(tab_1_curr) ] <- 89.3
tab_1_curr$curr_change_1_to_2[ nrow(tab_1_curr) ] <- 0.9
knitr::kable(tab_1_curr, digits = 1, align = "lccc", position = "c",
caption = "\\: my table caption here") %>%
kable_styling("striped") %>%
row_spec(nrow(tab_1_curr), bold = TRUE)
My bookdown settings are as follows:
---
title: "My Report"
author: "Me"
date: "`r Sys.Date()`"
site: "bookdown::bookdown_site"
output:
bookdown::word_document2:
fig_caption: true
documentclass: book
---
When I click on the Knit button in RStudio, I get this table:
I want the last row to be bold and I want the table striped. How do I do this ? (I also get the following error: "Currently generic markdown table using pandoc is not supported.")
This was not possible but since pandoc V2 is out, you can do it with package flextable (>= 0.4.0)(and pandoc V2). Below the code you should add into a code chunk:
library(magrittr)
library(flextable)
tab_1_curr <- structure(list(myRegion = c("a", "b", "c", "BRITISH COLUMBIA"
), Current_Perc_1 = c(85.9, 90.8, 89.7, 88.4), Current_Perc_2 = c(88,
91, 89, 89.3), curr_change_1_to_2 = c(2.09999999999999, 0.200000000000003,
-0.700000000000003, 0.9)), .Names = c("myRegion", "Current_Perc_1",
"Current_Perc_2", "curr_change_1_to_2"), row.names = c(NA, 4L
), class = "data.frame")
regulartable(tab_1_curr) %>%
bold(i = ~ myRegion %in% "BRITISH COLUMBIA") %>%
theme_zebra() %>%
autofit()
The huxtable package is available. It includes similar table customization tools as kableExtra. huxtable is designed to output to LaTeX/PDF and HTML (similar to kableExtra). However, huxtable also includes a as_flextable function to convert a huxtable object to a flextable object, which can be output to Word (as noted by David above). After a lot of searching, it seems to me like huxtable is the only available package that can easily output to all of Word, HTML, and PDF with a single package.
Pandoc version ≥2
Yes, this can be done with Pandoc (see David's answer)
Original answer follows:
Pandoc version <2
The conversion to word is made via pandoc. Currently pandoc only creates four type of tables,
simple tables
multiline_tables
grid_tables
pipe_tables
Some of those supported formats are demontrated in pander and in the pandoc manual p 35-39.
So you cannot create the stripped table currently with pandoc.
You also have a good summary of how you can use tables in rmarkdown.rstudio.
I am trying to make a table using either hwrite or xtable in rmarkdown to produce a html table. I have been unable to use a cellpadding or cellspacing option, this is the code I am using and attached is a photo of the output.
{r, echo = FALSE, results = 'asis'}
cat(hwrite(sd.m.table, row.names = FALSE, cellpadding = 10, row.style = list("font-weight:bold")))
Using xtable() similarly did not work as well. Does anyone have suggestions?
Generated output from code
I'm not familiar with the hwriter package, and I rarely use xtable anymore (because I get frustrated with customizing tables), so I can't give you specific advice on using those.
I'm most comfortable with pixiedust (because I wrote it), but the htmlTable and tableHTML packages produce nice HTML tables and are probably worth looking into as well.
Working example with pixiedust
---
title: "Untitled"
output: html_document
---
```{r}
library(pixiedust)
head(mtcars) %>%
dust() %>%
sprinkle(pad = 10) %>%
medley_all_borders()
```
EDIT:
To get the appearance you are seeking with your data, try using
library(pixiedust)
library(dplyr)
DF <-
data.frame(rep_complete_time = c("2017-01-04 08:58:22",
"2017-01-04 08:58:33",
"2017-01-06 11:35:28"),
result = c(4.99184, 4.07356, 5.01569),
body_fluid = c("Serum", "Serum", "Serum"),
result_type = c("QC", "QC", "QC"),
fluid_lot = c(4426, 4426, 4426),
level = c(1, 1, 1))
DF %>%
# for some reason, sprintf results aren't holding when used in a
# sprinkle. This seems like a bug in pixiedust.
mutate(result = sprintf("%0.1f", result)) %>%
dust() %>%
sprinkle_colnames("Rep Complete Time", "Result", "Body Fluid",
"Result Type", "Fluid Lot", "Level") %>%
# use part = "table" to apply borders to all parts of the table.
# by default, pixiedust only wants to work with the body of the table.
medley_all_borders(part = "table") %>%
# using the sprinkle_table function can apply sprinkles to all of the
# parts of a table.
sprinkle_table(pad = 10,
halign = "left")
I wasn't able to replicate your alignment problem. All of the columns in my results are aligned left.