haozhu233 / kableExtra

Construct Complex Table with knitr::kable() + pipe.
https://haozhu233.github.io/kableExtra/
Other
692 stars 148 forks source link

Plot rendering does not work with complex project structure, wrong path resolution #725

Open sondalex opened 2 years ago

sondalex commented 2 years ago

Describe the bug kableExtra plots do not work when knitting from different directory than the main .Rmd file and using root.dir option in knitr::opts_knit$set

To Reproduce

Assume the following project structure:

# kableExtra-Plot-Bug-Example
- render.R
- book/
  - example.Rmd
# render.R
library(rmarkdown)
rmarkdown::render("book/example.Rmd", "pdf_document")
<!-- book/example.Rmd -->
<!-- Example extracted from https://haozhu233.github.io/kableExtra/awesome_table_in_pdf.pdf (p.12-13)-->

```{r setup, include=FALSE}
knitr::opts_knit$set(root.dir = "../")
library(kableExtra)

mpg_list <- split(mtcars$mpg, mtcars$cyl)
inline_plot <- data.frame(cyl = c(4, 6, 8), mpg_box = "", mpg_hist = "",
    mpg_line1 = "", mpg_line2 = "", mpg_points1 = "", mpg_points2 = "", mpg_poly = "")
inline_plot %>% kbl(booktabs = TRUE) %>% kable_paper(full_width = FALSE) %>%
    column_spec(3, image = spec_hist(mpg_list))

If you run

```console
user@desktop:~/kableExtra-Plot-Bug-Example$ Rscript render.R

An error will occur when converting the created tex document to to pdf:

Error: File `book_files/figure-latex//hist_<random number>.pdf` not found : using draft setting

Current implementation

Currently, the default directory is set with respect to the <working directory>/figure-latex:

https://github.com/haozhu233/kableExtra/blob/292f60715959ea952ff25a8aedfd782793b15f7b/R/mini_plots.R#L295-L302

Beginning of Solution

One not optimal solution would be to use absolute paths

rmd_files_dir <- function(create = TRUE) {
  # prepend base directory, base directory != root.dir, 
  # base directory: directory of the main .Rmd file
  current_file <- knitr::current_input(dir=TRUE)
  base_dir <- dirname(current_file)
  target_dir <- knitr::opts_chunk$get("fig.path")
  fig_dir_name <- paste0(base_dir, "/", target_dir)
  if (!dir.exists(fig_dir_name) & create) dir.create(fig_dir_name, recursive=TRUE)
  return(fig_dir_name)
}

fig_dir_name change:

fig_dir_name <- knitr::opts_chunk$get("fig.path")

has the advantage of inheriting knitr defaults.

A better solution, would be to use relative paths, however the function(s) writing the tex \includegraphics paths statement would have to take care of trimming the base directory (book/ in this example) because pandoc path resolving is relative to the base directory and not root.dir.

Notes

In order to simplify reproduction, I made the example available in a GitHub repo.

To clone it:

user@desktop:~$ git clone  https://github.com/sondalex/kableExtra-Plot-Bug-Example.git
dmurdoch commented 1 year ago

I don't get an error when I run your code, but I also don't get the histogram in the output. If you're still interested in this, could you check whether things are fixed, or broken in a different way?

sondalex commented 12 months ago

Hi sure, I will try again. I will keep you updated.

sondalex commented 11 months ago

The temporary tex file is saved at book/example.tex. The line which stops pdflatex conversion is the following:

book/example.tex
141:4 &  & \includegraphics[width=0.67in, height=0.17in]{example_files/figure-latex//hist_102501edb50b6.pdf} &  &  &  &  & \\

It would work if the generated tex was equal to:

book/example.tex
141:4 &  & \includegraphics[width=0.67in, height=0.17in]{../example_files/figure-latex//hist_102501edb50b6.pdf} &  &  &  & \\

Unfortunately, knitr calls pdflatex from the book directory and not from the project root. Therefore, first example fails.