gt icon indicating copy to clipboard operation
gt copied to clipboard

Preserve `caption` of <gt_tbl> object when generating LaTeX code with `gt::as_latex()`

Open ami-null opened this issue 11 months ago • 4 comments

Prework

Proposal

gt::as_latex() drops the caption in the gt_tbl object:

dt <- mtcars[1:2, 1:2]
gt::gt(data = dt, caption = "mtcars data") |> 
    gt::as_latex() |> 
    as.character()
#> [1] "\\begin{longtable}{rr}\n\\toprule\nmpg & cyl \\\\ \n\\midrule\\addlinespace[2.5pt]\n21 & 6 \\\\ \n21 & 6 \\\\ \n\\bottomrule\n\\end{longtable}\n"

gt::gt(data = dt) |> 
    gt::tab_caption("mtcars data") |> 
    gt::as_latex() |> 
    as.character()
#> [1] "\\begin{longtable}{rr}\n\\toprule\nmpg & cyl \\\\ \n\\midrule\\addlinespace[2.5pt]\n21 & 6 \\\\ \n21 & 6 \\\\ \n\\bottomrule\n\\end{longtable}\n"

As can be seen in the output, there is no \caption{} command in the LaTeX code that is generated. This is an issue because my workflow is saving the generated LaTeX code string to a file and then calling \input{} on that file in LaTeX, and then I end up getting a table with no captions. This also prevents cross-referencing tables in PDF documents generated using Rmarkdown or Quarto.

Interestingly enough, when the title and subtitle in gt::tab_header() are retained, but through an un-numbered \caption*{} in the LaTeX code:

gt::gt(data = dt) |> 
    gt::tab_header(
        title = gt::md("tab_header title"),
        subtitle = gt::md("tab_header subtitle")
    ) |> 
    gt::as_latex() |> 
    as.character()
#> [1] "\\begin{longtable}{rr}\n\\caption*{\n{\\large tab\\_header title} \\\\ \n{\\small tab\\_header subtitle}\n} \\\\ \n\\toprule\nmpg & cyl \\\\ \n\\midrule\\addlinespace[2.5pt]\n21 & 6 \\\\ \n21 & 6 \\\\ \n\\bottomrule\n\\end{longtable}\n"

I understand that this a possible duplicate of #818. But, I am opening this one seeing that #818 is almost 3 years old.

sessionInfo()
#> R version 4.3.3 (2024-02-29 ucrt)
#> Platform: x86_64-w64-mingw32/x64 (64-bit)
#> Running under: Windows 10 x64 (build 19045)
#> 
#> Matrix products: default
#> 
#> 
#> locale:
#> [1] LC_COLLATE=English_United States.utf8 
#> [2] LC_CTYPE=English_United States.utf8   
#> [3] LC_MONETARY=English_United States.utf8
#> [4] LC_NUMERIC=C                          
#> [5] LC_TIME=English_United States.utf8    
#> 
#> time zone: 
#> tzcode source: internal
#> 
#> attached base packages:
#> [1] stats     graphics  grDevices utils     datasets  methods   base     
#> 
#> loaded via a namespace (and not attached):
#>  [1] vctrs_0.6.5       cli_3.6.2         gt_0.10.1         knitr_1.45       
#>  [5] rlang_1.1.3       xfun_0.42         purrr_1.0.2       styler_1.10.2    
#>  [9] generics_0.1.3    glue_1.7.0        markdown_1.12     htmltools_0.5.7  
#> [13] fansi_1.0.6       rmarkdown_2.26    R.cache_0.16.0    tibble_3.2.1     
#> [17] evaluate_0.23     fastmap_1.1.1     yaml_2.3.8        lifecycle_1.0.4  
#> [21] compiler_4.3.3    dplyr_1.1.4       fs_1.6.3          pkgconfig_2.0.3  
#> [25] rstudioapi_0.15.0 R.oo_1.26.0       R.utils_2.12.3    digest_0.6.34    
#> [29] R6_2.5.1          tidyselect_1.2.0  utf8_1.2.4        reprex_2.1.0     
#> [33] pillar_1.9.0      commonmark_1.9.1  magrittr_2.0.3    R.methodsS3_1.8.2
#> [37] tools_4.3.3       withr_3.0.0       xml2_1.3.6

Created on 2024-03-20 with reprex v2.1.0

ami-null avatar Mar 20 '24 12:03 ami-null

I managed to fix this in AaronGullickson#1 using tab_header() and making it work in both longtable and floating table environments with the option to set a label for cross-referencing which, I think, is missing for GT tables in R Markdown. Context: #1588

Here are the four essential outputs:

Longtable with caption:

head(state.x77) |>
  as.data.frame() |>
  gt() |>
  tab_options(latex.use.longtable = TRUE,
              latex.tbl.pos = "!t") |>
  tab_header(title = "This is a title",
             subtitle = "subtitle",
             label = "1") |>
    gtsave("table-long-cap.tex")
\begingroup
\fontsize{12.0pt}{14.4pt}\selectfont
\begin{longtable}{rrrrrrrr}
\caption{
{\large This is a title} \\ 
{\small subtitle}
}\label{tab1} \\ 
\toprule
Population & Income & Illiteracy & Life Exp & Murder & HS Grad & Frost & Area \\ 
\midrule\addlinespace[2.5pt]
3615 & 3624 & 2.1 & 69.05 & 15.1 & 41.3 & 20 & 50708 \\ 
365 & 6315 & 1.5 & 69.31 & 11.3 & 66.7 & 152 & 566432 \\ 
2212 & 4530 & 1.8 & 70.55 & 7.8 & 58.1 & 15 & 113417 \\ 
2110 & 3378 & 1.9 & 70.66 & 10.1 & 39.9 & 65 & 51945 \\ 
21198 & 5114 & 1.1 & 71.71 & 10.3 & 62.6 & 20 & 156361 \\ 
2541 & 4884 & 0.7 & 72.06 & 6.8 & 63.9 & 166 & 103766 \\ 
\bottomrule
\end{longtable}
\endgroup

Longtable without caption:

head(state.x77) |>
  as.data.frame() |>
  gt() |>
  tab_options(latex.use.longtable = TRUE,
              latex.tbl.pos = "!t") |>
  tab_header(title = "This is a title",
             subtitle = "subtitle") |>
    gtsave("table-long-nocap.tex")
\begingroup
\fontsize{12.0pt}{14.4pt}\selectfont
\begin{longtable}{rrrrrrrr}
\caption*{
{\large This is a title} \\ 
{\small subtitle}
} \\ 
\toprule
Population & Income & Illiteracy & Life Exp & Murder & HS Grad & Frost & Area \\ 
\midrule\addlinespace[2.5pt]
3615 & 3624 & 2.1 & 69.05 & 15.1 & 41.3 & 20 & 50708 \\ 
365 & 6315 & 1.5 & 69.31 & 11.3 & 66.7 & 152 & 566432 \\ 
2212 & 4530 & 1.8 & 70.55 & 7.8 & 58.1 & 15 & 113417 \\ 
2110 & 3378 & 1.9 & 70.66 & 10.1 & 39.9 & 65 & 51945 \\ 
21198 & 5114 & 1.1 & 71.71 & 10.3 & 62.6 & 20 & 156361 \\ 
2541 & 4884 & 0.7 & 72.06 & 6.8 & 63.9 & 166 & 103766 \\ 
\bottomrule
\end{longtable}
\endgroup

Floating table with caption:

head(state.x77) |>
  as.data.frame() |>
  gt() |>
  tab_options(latex.use.longtable = FALSE,
              latex.tbl.pos = "!t") |>
  tab_header(title = "This is a title",
             subtitle = "subtitle",
             label = "table2") |>
    gtsave("table-float-cap.tex")
\begin{table}[!t]
\caption{
{\large This is a title} \\ 
{\small subtitle}
}\label{tabtable2} 
\fontsize{12.0pt}{14.4pt}\selectfont
\begin{tabular*}{\linewidth}{@{\extracolsep{\fill}}rrrrrrrr}
\toprule
Population & Income & Illiteracy & Life Exp & Murder & HS Grad & Frost & Area \\ 
\midrule\addlinespace[2.5pt]
3615 & 3624 & 2.1 & 69.05 & 15.1 & 41.3 & 20 & 50708 \\ 
365 & 6315 & 1.5 & 69.31 & 11.3 & 66.7 & 152 & 566432 \\ 
2212 & 4530 & 1.8 & 70.55 & 7.8 & 58.1 & 15 & 113417 \\ 
2110 & 3378 & 1.9 & 70.66 & 10.1 & 39.9 & 65 & 51945 \\ 
21198 & 5114 & 1.1 & 71.71 & 10.3 & 62.6 & 20 & 156361 \\ 
2541 & 4884 & 0.7 & 72.06 & 6.8 & 63.9 & 166 & 103766 \\ 
\bottomrule
\end{tabular*}
\end{table}

Floating table without caption:

head(state.x77) |>
  as.data.frame() |>
  gt() |>
  tab_options(latex.use.longtable = FALSE,
              latex.tbl.pos = "!t") |>
  tab_header(title = "This is a title",
             subtitle = "subtitle") |>
    gtsave("table-float-nocap.tex")
\begin{table}[!t]
\caption*{
{\large This is a title} \\ 
{\small subtitle}
} 
\fontsize{12.0pt}{14.4pt}\selectfont
\begin{tabular*}{\linewidth}{@{\extracolsep{\fill}}rrrrrrrr}
\toprule
Population & Income & Illiteracy & Life Exp & Murder & HS Grad & Frost & Area \\ 
\midrule\addlinespace[2.5pt]
3615 & 3624 & 2.1 & 69.05 & 15.1 & 41.3 & 20 & 50708 \\ 
365 & 6315 & 1.5 & 69.31 & 11.3 & 66.7 & 152 & 566432 \\ 
2212 & 4530 & 1.8 & 70.55 & 7.8 & 58.1 & 15 & 113417 \\ 
2110 & 3378 & 1.9 & 70.66 & 10.1 & 39.9 & 65 & 51945 \\ 
21198 & 5114 & 1.1 & 71.71 & 10.3 & 62.6 & 20 & 156361 \\ 
2541 & 4884 & 0.7 & 72.06 & 6.8 & 63.9 & 166 & 103766 \\ 
\bottomrule
\end{tabular*}
\end{table}

nielsbock avatar Jun 03 '24 16:06 nielsbock

That looks great. Is it merged? Or, will it be merged?

ami-null avatar Jun 12 '24 16:06 ami-null

It's not merged. I have made a pull request to @AaronGullickson at https://github.com/AaronGullickson/gt/pull/1 who was initially working on the LaTex floating table. I have also left the above solution for another (https://github.com/AaronGullickson/gt/pull/2), where tab_caption() is used for cross-referencing. This was done so the Latex output was in line with the html output. I also updated the knitr helper functions so that cross-referencing is possible using the chunk options in Bookdown. You can download it from here: pak::pak(nielsbock/gt@floating-table) if you would like to check it out!

nielsbock avatar Jun 13 '24 06:06 nielsbock

I will try to get to it today or tomorrow

AaronGullickson avatar Jun 13 '24 15:06 AaronGullickson

I came here to report a similar issue/bug regarding the table captions when rendering to quarto pdf

---
title: "mtcars quarto table captions"
format: 
  pdf:
    toc: true
    lot: true
    lof: true
    keep-tex: true
    keep-md: true
---


```{r}
#| label: tbl-mtcars

mtcars |>
  head() |>
  gt::gt() |>
  gt::tab_caption(caption = deparse(substitute(mtcars))) 
```


```{r}
#| label: tbl-mtcars-tail
#| tbl-cap: "mtcars tail"

mtcars |>
  tail() |>
  gt::gt() 
```

```{r}
#| lst-label: lst-mtcars-options
#| lst-cap: "mtcars table options"

TBL <- mtcars |>
  head() |>
  gt::gt() |>
  gt::tab_caption(caption = deparse(substitute(mtcars)))

TBL$`_options` |>
  dplyr::filter(parameter == 'table_caption')


TBL$`_options` |>
  dplyr::filter(parameter == 'table_caption') |>
  dplyr::pull(value)
```

mtcars.pdf

jkylearmstrong avatar Jul 02 '24 17:07 jkylearmstrong

the development version of gt now includes a fix for this, thanks to @nielsbock, in case people want to try it out!

pak::pak("rstudio/gt")

We'd love to receive your feedback so please open a new issue if something is not working as expected.

olivroy avatar Aug 29 '24 16:08 olivroy