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

Extra dependencies aren't always added #721

Closed
dmurdoch opened this issue Sep 5, 2022 · 5 comments · Fixed by #782
Closed

Extra dependencies aren't always added #721

dmurdoch opened this issue Sep 5, 2022 · 5 comments · Fixed by #782

Comments

@dmurdoch
Copy link
Collaborator

dmurdoch commented Sep 5, 2022

This SO post describes the issue and a workaround. The problem is that the usepackage_latex() calls in zzz.R:

kableExtra/R/zzz.R

Lines 5 to 18 in 292f607

usepackage_latex("booktabs")
usepackage_latex("longtable")
usepackage_latex("array")
usepackage_latex("multirow")
usepackage_latex("wrapfig")
usepackage_latex("float")
usepackage_latex("colortbl")
usepackage_latex("pdflscape")
usepackage_latex("tabu")
usepackage_latex("threeparttable")
usepackage_latex("threeparttablex")
usepackage_latex("ulem", "normalem")
usepackage_latex("makecell")
usepackage_latex("xcolor")
won't be executed if kableExtra is already loaded when rmarkdown::render() is called.

This would be the typical state if you are calling rmarkdown::render() explicitly, rather than having RStudio set up a separate session to call it via the Knit button.

To Reproduce

Try to run this document test.Rmd:

---
title: "Test document"
output: pdf_document
---

```{r setup}
library(dplyr)
```

```{r}
iris %>%
    knitr::kable(format="latex") %>%
    kableExtra::kable_styling() %>%
    kableExtra::column_spec(2, width = "10em")
```

using rmarkdown::render("test.Rmd") in an R session. It might succeed the first time, but the second and following calls will fail with a LaTeX error, because the LaTeX array package is not used:

! Undefined control sequence.
<argument> r|>{\raggedleft \arraybackslash 
                                           }p{10em}|r|r|l
l.139 ...\raggedleft\arraybackslash}p{10em}|r|r|l}

Error: LaTeX failed to compile Untitled.tex. See https://yihui.org/tinytex/r/#debugging for debugging tips. See Untitled.log for more info.

A fix for this would be to run the usepackage_latex() calls every time a kableExtra function is called; a more efficient fix would be to set a flag when they are run, and check that flag every time. The flag needs to be cleared at the start of a knitr run.

@paulrougieux
Copy link

paulrougieux commented Sep 6, 2022

Here is a session rendering the above notebook twice, it fails on the second attempt. Running unloadNamespace("kableExtra") before the third attempt makes it successful again.

Full console output of `rmarkdown::render("notebook.Rmd")` 3 times
> rmarkdown::render("notebook.Rmd")


processing file: notebook.Rmd
  |..............                                                        |  20%
  ordinary text without R code

  |............................                                          |  40%
label: setup
  |..........................................                            |  60%
  ordinary text without R code

  |........................................................              |  80%
label: unnamed-chunk-1
  |......................................................................| 100%
  ordinary text without R code


output file: notebook.knit.md

/usr/bin/pandoc +RTS -K512m -RTS notebook.knit.md --to latex --from markdown+autolink_bare_uris+tex_math_single_backslash --output notebook.tex --lua-filter /home/paul/R/x86_64-pc-linux-gnu-library/4.2/rmarkdown/rmarkdown/lua/pagebreak.lua --lua-filter /home/paul/R/x86_64-pc-linux-gnu-library/4.2/rmarkdown/rmarkdown/lua/latex-div.lua --embed-resources --standalone --highlight-style tango --pdf-engine pdflatex --variable graphics --variable 'geometry:margin=1in' --include-in-header /tmp/Rtmp1Khcp1/rmarkdown-str126b56c64270c.html

Output created: notebook.pdf
> rmarkdown::render("notebook.Rmd")


processing file: notebook.Rmd
  |..............                                                        |  20%
  ordinary text without R code

  |............................                                          |  40%
label: setup
  |..........................................                            |  60%
  ordinary text without R code

  |........................................................              |  80%
label: unnamed-chunk-1
  |......................................................................| 100%
  ordinary text without R code


output file: notebook.knit.md

/usr/bin/pandoc +RTS -K512m -RTS notebook.knit.md --to latex --from markdown+autolink_bare_uris+tex_math_single_backslash --output notebook.tex --lua-filter /home/paul/R/x86_64-pc-linux-gnu-library/4.2/rmarkdown/rmarkdown/lua/pagebreak.lua --lua-filter /home/paul/R/x86_64-pc-linux-gnu-library/4.2/rmarkdown/rmarkdown/lua/latex-div.lua --embed-resources --standalone --highlight-style tango --pdf-engine pdflatex --variable graphics --variable 'geometry:margin=1in'
! Undefined control sequence.
<argument> r|>{\raggedleft \arraybackslash
                                           }p{10em}|r|r|l
l.128 ...\raggedleft\arraybackslash}p{10em}|r|r|l}

Error: LaTeX failed to compile notebook.tex. See https://yihui.org/tinytex/r/#debugging for debugging tips. See notebook.log for more info.
> unloadNamespace("kableExtra")
> rmarkdown::render("notebook.Rmd")


processing file: notebook.Rmd
  |..............                                                        |  20%
  ordinary text without R code

  |............................                                          |  40%
label: setup
  |..........................................                            |  60%
  ordinary text without R code

  |........................................................              |  80%
label: unnamed-chunk-1
  |......................................................................| 100%
  ordinary text without R code


output file: notebook.knit.md

/usr/bin/pandoc +RTS -K512m -RTS notebook.knit.md --to latex --from markdown+autolink_bare_uris+tex_math_single_backslash --output notebook.tex --lua-filter /home/paul/R/x86_64-pc-linux-gnu-library/4.2/rmarkdown/rmarkdown/lua/pagebreak.lua --lua-filter /home/paul/R/x86_64-pc-linux-gnu-library/4.2/rmarkdown/rmarkdown/lua/latex-div.lua --embed-resources --standalone --highlight-style tango --pdf-engine pdflatex --variable graphics --variable 'geometry:margin=1in' --include-in-header /tmp/Rtmp1Khcp1/rmarkdown-str126b54aee94e7.html

Output created: notebook.pdf

Note:

  • adding library(kableExtra) to the notebook doesn't fix the issue.
  • as explained in my SO question, the real use case is a a loop within which I render the same notebook several times for different product groups. Similar to the use case described in bookdown where a report is rendered "for each state of a country".

@dmurdoch
Copy link
Collaborator Author

dmurdoch commented Sep 6, 2022

Adding unloadNamespace("kableExtra") to the setup code chunk before the first use of anything from the package fixes it for me.

@paulrougieux
Copy link

The fix works for me, but I guess there is a better way to solve this in kableExtra without having to add unloadNamespace("kableExtra") to the setup chunk.

@dmurdoch
Copy link
Collaborator Author

dmurdoch commented Sep 6, 2022

I took a look, and couldn't spot a simple one. kableExtra needs to call the usepackage_latex functions once per document, but I don't think knitr provides a hook that is run at the right time. The "document" hook runs a little bit too late: the markdown that goes to Pandoc has already been produced. I guess you could write a document hook that edited the YAML header to add the dependencies that kableExtra needs, but if the header already contains extra dependencies, that could be really messy.

@dmurdoch
Copy link
Collaborator Author

dmurdoch commented Sep 6, 2022

Some kableExtra functions add "kableExtra" to the class of the object being printed, and then the knit_print.kableExtra method will be called. Probably the conceptually easiest way to implement this would be to add that class name (or a different one) to all functions that might create extra package dependencies, then add them in the knit_print method. (Or maybe all functions that take kable() results and modify them.)

That's a lot of changes to make, but they're all small changes. I might try it and put in a PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants