Reputation: 124038
I want to export multiple tables with a multi row caption or header to the same document using the officer
package.
Background: In my company docx template a table or plot has a caption which consists of a title and a subtitle, both with their own styles. While the title corresponds to the caption in docx or officer, the subtitle is simply added as a paragraph.
Thanks to officer
this is not a big deal and works great when exporting (gg)plots or just one table to docx.
However, when I export multiple tables the subtitle is placed at the right position only for the first table, while for all subsequent tables the subtitle is placed after the table:
The issue arises both with officer::body_add_table
and flexible::body_add_flextable
.
I already did some trial and error with changing the order in which I add the elements and had a look at the docs but wasn't able to figure out a solution. Maybe I missed the right argument to fix my issue.
A minimal reproducible example based on the default docx template shipped with officer
:
library(officer)
to_docx <- function(docx, value, title, subtitle) {
# Add table or plot
if (inherits(value, "ggplot")) {
pre_label <- seq_id <- "Figure"
docx <- body_add_gg(docx, value = value)
} else {
pre_label <- seq_id <- "Table"
docx <- body_add_table(docx, value = value, align_table = "center")
}
# Add title above table
run_num <- run_autonum(seq_id = seq_id, pre_label = pre_label)
title <- block_caption(title, style = "Image Caption", autonum = run_num)
docx <- body_add_caption(docx, title, pos = "before")
# Add subtitle above table
subtitle <- fpar(ftext(subtitle, prop = fp_text(color = "red")))
docx <- body_add_fpar(docx, subtitle, style = "Normal", pos = "after")
docx <- cursor_end(docx)
# Add a page breaks
docx <- body_add_break(docx, pos = "after")
invisible(docx)
}
docx <- read_docx()
tab <- head(mtcars[1:3])
to_docx(docx, tab, "Title 1", "Subtitle 1")
to_docx(docx, tab, "Title 2", "Subtitle 2")
fn <- tempfile(fileext = ".docx")
print(docx, fn)
show <- FALSE # Setting to TRUE will open the docx
if (show) fs::file_show(fn)
And as a reference, using the function to export multiple ggplot
s works as intended:
library(ggplot2)
docx <- read_docx()
gg <- ggplot(mtcars, aes(hp, mpg)) +
geom_point()
to_docx(docx, gg, "Title 1", "Subtitle 1")
to_docx(docx, gg, "Title 2", "Subtitle 2")
fn <- tempfile(fileext = ".docx")
print(docx, fn)
show <- FALSE
if (show) fs::file_show(fn)
Upvotes: 0
Views: 195
Reputation: 10675
This was a bug and is now fixed in the dev version (or >= 0.4.5
).
With the update, it's important to assign the result of to_docx
to docx
(there was an internal change with the cursor management):
library(officer)
to_docx <- function(docx, value, title, subtitle) {
# Add table or plot
if (inherits(value, "ggplot")) {
pre_label <- seq_id <- "Figure"
docx <- body_add_gg(docx, value = value)
} else {
pre_label <- seq_id <- "Table"
docx <- body_add_table(docx, value = value, align_table = "center")
}
# Add title above table
run_num <- run_autonum(seq_id = seq_id, pre_label = pre_label)
title <- block_caption(title, style = "Image Caption", autonum = run_num)
docx <- body_add_caption(docx, title, pos = "before")
# Add subtitle above table
subtitle <- fpar(ftext(subtitle, prop = fp_text(color = "red")))
docx <- body_add_fpar(docx, subtitle, style = "Normal", pos = "after")
docx <- cursor_end(docx)
# Add a page breaks
docx <- body_add_break(docx, pos = "after")
invisible(docx)
}
docx <- read_docx()
tab <- head(mtcars[1:3])
docx <- to_docx(docx, tab, "Title 1", "Subtitle 1")
docx <- to_docx(docx, tab, "Title 2", "Subtitle 2")
fn <- tempfile(fileext = ".docx")
print(docx, fn)
show <- FALSE # Setting to TRUE will open the docx
if (show) fs::file_show(fn)
As an alternative solution, you could also use block_list()
, below an illustration (only with the table):
library(officer)
library(ggplot2)
to_docx <- function(docx, value, title, subtitle) {
# Add table
pre_label <- seq_id <- "Table"
run_num <- run_autonum(seq_id = seq_id, pre_label = pre_label)
bl <- block_list(
block_caption(title, style = "Image Caption", autonum = run_num),
fpar(subtitle, fp_p = fp_par(word_style = "Normal")),
block_table(x = value, header = TRUE,
properties = prop_table(
tcf = table_conditional_formatting(
first_row = TRUE, first_column = TRUE)
))
)
docx <- body_add_blocks(docx, bl, pos = "after")
invisible(docx)
}
docx <- read_docx()
tab <- head(mtcars[1:3])
docx <- to_docx(docx, tab, "title-1", "subtitle")
docx <- to_docx(docx, tab, "title-2", "subtitle")
fn <- tempfile(fileext = ".docx")
print(docx, fn)
show <- FALSE # Setting to TRUE will open the docx
if (show) fs::file_show(fn)
Upvotes: 1