Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Latex caption + cross-referencing in bookdown #1800

Merged
merged 16 commits into from
Aug 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

## New features

* Creating a caption with `tab_caption()` will now be preserved in Latex output with `as_latex()`. Cross-referencing a table using the internal cross-referencing system of **bookdown** is now enabled for PDF and HTML outputs (for HTML, set `options("htmltools.preserve.raw" = FALSE)`). Quarto users should use the `tbl-cap` and `label` cell options.

* PDF output now defaults to a full-width floating environment using `tabular*` (@AronGullickson, #1588). Float position can be controlled by the `latex.tbl.pos` argument in `tab_options`. Quarto users can alternatively use the `tbl-pos` argument to control positioning. To use a `longtable` environment instead, use `tab_option(latex.use_longtable = TRUE)`.

## Interactive table support
Expand Down
5 changes: 5 additions & 0 deletions R/export.R
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,9 @@ as_latex <- function(data) {
# Create a LaTeX fragment for the start of the table
table_start <- create_table_start_l(data = data, colwidth_df = colwidth_df)

# Create the caption component
caption_component <- create_caption_component_l(data = data)

# Create the heading component
heading_component <- create_heading_component_l(data = data)

Expand Down Expand Up @@ -238,6 +241,7 @@ as_latex <- function(data) {
table_width_statement,
fontsize_statement,
table_start,
caption_component,
heading_component,
columns_component,
body_component,
Expand All @@ -252,6 +256,7 @@ as_latex <- function(data) {
knitr::asis_output(
paste0(
wrap_start_statement,
caption_component,
heading_component,
table_width_statement,
fontsize_statement,
Expand Down
31 changes: 13 additions & 18 deletions R/knitr-utils.R
Original file line number Diff line number Diff line change
Expand Up @@ -23,35 +23,30 @@


kable_caption <- function(label, caption, format) {

label <- label %||% knitr::opts_current$get("label")

if (!is.null(caption) && !is.na(caption)) {

caption <-
paste0(
create_label("tab:", label, latex = (format == "latex")), caption
)
# create a label for bookdown if applicable
if (is.null(label)) label <- knitr::opts_current$get("label")
if (is.null(label)) label <- NA
if (!is.null(caption) && !anyNA(caption) && !anyNA(label)) {
caption <- paste0(
create_label(
knitr::opts_knit$get("label.prefix")[["table"]],
label,
latex = (format == "latex")
), caption
)
}

caption
}

create_label <- function(..., latex = FALSE) {

if (isTRUE(knitr::opts_knit$get("bookdown.internal.label"))) {

lab1 <- "(#"
lab1 <- "(\\#"
lab2 <- ")"

} else if (latex) {

lab1 <- "\\label{"
lab2 <- "}"

} else {
return("")
return("") # we don't want the label at all
}

paste(c(lab1, ..., lab2), collapse = "")
}
42 changes: 42 additions & 0 deletions R/utils_render_latex.R
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,48 @@ create_table_start_l <- function(data, colwidth_df) {
)
}

#' Create the caption component of a table
#'
#' The table caption component contains the caption; if
#' there are no caption components defined this function will return an empty
#' string.
#'
#' @noRd
create_caption_component_l <- function(data) {

# Create the table caption if available
table_caption <- dt_options_get_value(data = data, option = "table_caption")

if (!all(is.na(table_caption))) {

table_caption <- process_text(table_caption, context = "latex")

if (isTRUE(getOption("knitr.in.progress"))) {

table_caption <- kable_caption(label = NULL, table_caption, "latex")
ifelse(check_quarto(),
"",
paste0("\\caption",
latex_group(table_caption),
ifelse(dt_options_get_value(data = data, option = "latex_use_longtable"),
" \\\\ \n",
" \n")
)
)
} else {
paste0("\\caption",
latex_group(table_caption),
ifelse(dt_options_get_value(data = data, option = "latex_use_longtable"),
" \\\\ \n",
" \n")
)
}

} else {
NULL
}
}

#' Create the heading component of a table
#'
#' The table heading component contains the title and possibly a subtitle; if
Expand Down
10 changes: 6 additions & 4 deletions tests/gt-examples/02-html-rmd/html-06-mtcars.Rmd
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
---
title: "html-06-mtcars"
output:
- html_document
- bookdown::html_document2
---

```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE)
library(gt)
options("htmltools.preserve.raw" = FALSE)
```

Create a display table based on `mtcars`.

```{r}
Testing that the caption in \@ref(tab:mtcars) can be cross referenced.
```{r mtcars}
gt(mtcars, rownames_to_stub = TRUE) %>%
cols_align(
align = "right",
Expand Down Expand Up @@ -98,5 +99,6 @@ gt(mtcars, rownames_to_stub = TRUE) %>%
cols_label(
hp = md("*HP*"),
qsec = "QMT, seconds"
)
) %>%
tab_caption(md("The **mtcars** dataset"))
```
3 changes: 2 additions & 1 deletion tests/gt-examples/03-latex/latex-01-iris.Rmd
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,6 @@ gt(iris) %>%
tab_source_note(
source_note = md("The data were collected by *Anderson* (1935).")
) %>%
tab_options(latex.use_longtable = TRUE)
tab_options(latex.use_longtable = TRUE) %>%
tab_caption(md("The **iris** dataset"))
```
8 changes: 5 additions & 3 deletions tests/gt-examples/03-latex/latex-06-mtcars.Rmd
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
title: "latex-06-mtcars"
output:
- pdf_document
- bookdown::pdf_document2
---

```{r setup, include=FALSE}
Expand All @@ -11,8 +11,9 @@ library(gt)
```

Create a display table based on `mtcars` (Motor Trend Car Road Test).
Testing that the caption in \@ref(tab:mtcars) can be cross referenced.

```{r}
```{r mtcars}
gt(mtcars, rownames_to_stub = TRUE) %>%
cols_align(
align = "right",
Expand Down Expand Up @@ -100,5 +101,6 @@ gt(mtcars, rownames_to_stub = TRUE) %>%
hp = md("*HP*"),
qsec = "QMT, seconds"
) %>%
tab_options(latex.use_longtable = TRUE)
tab_options(latex.use_longtable = TRUE) %>%
tab_caption(md("The **mtcars** dataset"))
```
7 changes: 7 additions & 0 deletions tests/testthat/_snaps/l_table_parts.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
# A gt table contains the expected caption component

Code
as.character(as_latex(gt_tbl))
Output
[1] "\\begingroup\n\\fontsize{12.0pt}{14.4pt}\\selectfont\n\\begin{longtable}{rrrrrrrrrrr}\n\\caption{test caption} \\\\ \n\\toprule\nmpg & cyl & disp & hp & drat & wt & qsec & vs & am & gear & carb \\\\ \n\\midrule\\addlinespace[2.5pt]\n21.0 & 6 & 160 & 110 & 3.90 & 2.620 & 16.46 & 0 & 1 & 4 & 4 \\\\ \n21.0 & 6 & 160 & 110 & 3.90 & 2.875 & 17.02 & 0 & 1 & 4 & 4 \\\\ \n22.8 & 4 & 108 & 93 & 3.85 & 2.320 & 18.61 & 1 & 1 & 4 & 1 \\\\ \n21.4 & 6 & 258 & 110 & 3.08 & 3.215 & 19.44 & 1 & 0 & 3 & 1 \\\\ \n18.7 & 8 & 360 & 175 & 3.15 & 3.440 & 17.02 & 0 & 0 & 3 & 2 \\\\ \n\\bottomrule\n\\end{longtable}\n\\endgroup\n"

# A gt table contains the expected heading components

Code
Expand Down
20 changes: 20 additions & 0 deletions tests/testthat/test-l_table_parts.R
Original file line number Diff line number Diff line change
@@ -1,3 +1,23 @@
test_that("A gt table contains the expected caption component", {

# Create a `tbl_latex` object with `gt()`; this table contains a caption
tbl_latex <-
gt(mtcars_short) %>%
tab_caption("test caption") %>%
tab_options(latex.use_longtable = TRUE)

# Expect a characteristic pattern
expect_match(
as_latex(tbl_latex) %>% as.character(),
"\\caption{test caption} \\\\ \n",
fixed = TRUE
)

# Perform a snapshot test where a LaTeX table
# contains only a caption
expect_snapshot_latex(tbl_latex)
})

test_that("A gt table contains the expected heading components", {

# Create a `tbl_latex` object with `gt()`; this table contains a title
Expand Down
2 changes: 1 addition & 1 deletion tests/testthat/test-utils_render_html.R
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ test_that("bookdown-style crossrefs are added when appropriate", {

# If bookdown, then ref is generated
knitr::opts_knit$set(bookdown.internal.label = TRUE)
expect_caption_eq("test", "(#tab:foo)test")
expect_caption_eq("test", "(\\#tab:foo)test")

expect_null(create_caption_component_h(exibble %>% gt()))

Expand Down
Loading