Reputation: 234
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.
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?
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.Edit: the table works now! Great thanks to Maël's answer, but please check my own findings to see my final result:
Upvotes: 7
Views: 2636
Reputation: 234
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 (×).
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~
Previously I used text reference (eg.(ref:foo)
) to use markdown formatting in table captions. This won't work now, since the developer has removed markdown rendering abilities of table captions since version 0.8.3.
To fix the issue, you can write your markdown caption as a string, then pass it to ftExtra::as_paragraph_md()
in set_caption()
. For example:
tab_caption <- "A scientifically formatted `flextable` with ^superscripts^ and ~subscripts~"
a %>%
flextable() %>%
set_caption(
caption = ftExtra::as_paragraph_md(tab_caption), # <- Here
style = "Table Caption"
) %>%
colformat_md() %>%
theme_apa() %>% # The 3-part-table used in academics
align(align = "center", part = "all") %>%
set_table_properties(layout = "autofit")
It should be noted that the rendered caption will not follow the Table Caption
style in the reference docx. To specify the style of the caption, you have to use flextable::set_flextable_defaults()
to set the default to the caption style you want, and then set the table format separately:
set_flextable_defaults( # Caption styles
font.family = "Times New Roman",
font.size = 12,
padding.bottom = 6,
padding.top = 12,
line_spacing = 1.5,
table_align = "center",
)
# The table styles
table_defaults <- function(x) {
x |>
flextable::border_inner_h(
part = "header", border = officer::fp_border(color = "black")
) |>
flextable::align(align = "center", part = "all") |>
flextable::valign(valign = "top", part = "body") |>
flextable::padding(
padding.top = 3,
padding.bottom = 3,
padding.left = 5,
padding.right = 5,
part = "all"
) |>
flextable::line_spacing(
space = 1.15,
part = "all"
) |>
flextable::fontsize(size = 11, part = "all") |>
flextable::set_table_properties(layout = "autofit")
}
a <- table_defaults(a)
Upvotes: 3
Reputation: 1381
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:
Upvotes: -1
Reputation: 4419
An option that probably falls in the no-go zone for this open issue:
---
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)
Upvotes: 1
Reputation: 51914
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)
```
Upvotes: 3