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

include_graphics() cannot find file when 1) working folder is not where the document is and 2) knit from working folder. #1825

Closed
3 tasks done
sleeubc opened this issue Mar 28, 2020 · 9 comments
Labels
question

Comments

@sleeubc
Copy link

@sleeubc sleeubc commented Mar 28, 2020

I found that include_graphics() cannot find a file when 1) working folder is not where the Rmd document is and 2) knit from working folder.

This zip file has a reproducible example:
path_issue.zip

To see the bug (I think it is), please follow the steps:

  1. Open path_issue.Rproj (to set the working folder to be the root of path_issue folder.)
  2. Open main.Rmd in Rmd subfolder. (Note the Rmd file location differs from the working folder.)
  3. Set Knit Directory to "Current Working Directory"
  4. Run main.Rmd in the Source pane. Both readRDS() and include_graphics() can find files in subdir folder.
  5. Try knitting it. readRDS() works but include_graphics() cannot find file.

Thank you.

xfun::session_info()
R version 3.6.3 (2020-02-29)
Platform: x86_64-w64-mingw32/x64 (64-bit)
Running under: Windows 10 x64 (build 18363), RStudio 1.2.5033

Locale:
LC_COLLATE=English_United States.1252
LC_CTYPE=English_United States.1252
LC_MONETARY=English_United States.1252
LC_NUMERIC=C
LC_TIME=English_United States.1252

Package version:
assertthat_0.2.1 backports_1.1.5
base64enc_0.1.3 callr_3.4.3
cli_2.0.2 compiler_3.6.3
crayon_1.3.4 curl_4.3
desc_1.2.0 digest_0.6.25
evaluate_0.14 fansi_0.4.1
glue_1.3.2 graphics_3.6.3
grDevices_3.6.3 highr_0.8
htmltools_0.4.0 jsonlite_1.6.1
knitr_1.28.2 magrittr_1.5
markdown_1.1 methods_3.6.3
mime_0.9 pkgbuild_1.0.6
prettyunits_1.1.1 processx_3.4.2
ps_1.3.2 R6_2.4.1
Rcpp_1.0.4 remotes_2.1.1
rlang_0.4.5 rmarkdown_2.1
rprojroot_1.3-2 rstudioapi_0.11
stats_3.6.3 stringi_1.4.6
stringr_1.4.0 tinytex_0.20
tools_3.6.3 utils_3.6.3
withr_2.1.2 xfun_0.12
yaml_2.2.1


By filing an issue to this repo, I promise that

  • I have fully read the issue guide at https://yihui.org/issue/.
  • I have provided the necessary information about my issue.
    • If I'm asking a question, I have already asked it on Stack Overflow or RStudio Community, waited for at least 24 hours, and included a link to my question there.
    • If I'm filing a bug report, I have included a minimal, self-contained, and reproducible example, and have also included xfun::session_info('knitr'). I have upgraded all my packages to their latest versions (e.g., R, RStudio, and R packages), and also tried the development version: remotes::install_github('yihui/knitr').
    • If I have posted the same issue elsewhere, I have also mentioned it in this issue.
  • I have learned the Github Markdown syntax, and formatted my issue correctly.

I understand that my issue may be closed if I don't fulfill my promises.

@BrazilForever11
Copy link

@BrazilForever11 BrazilForever11 commented May 13, 2020

I would like to upvote this issue.

@cderv
Copy link
Collaborator

@cderv cderv commented May 13, 2020

You see a difference between readRDS and include_graphics behavior and it seems on the R side but it is an error during pandoc conversion. The knit directory option will control how knitr evaluates the chunk. That is why the readRDS works fine. include_graphics also works fine currently and results in this markdown syntax, which is what is asked.

```r
knitr::include_graphics("subdir/emoji.png")
```

![](subdir/emoji.png)

However, that means that pandoc is expecting the file to be in subdir/ during its rendering, but pandoc conversion happens on the temporary md files written in Rmd directory by default. So the subdir is in the parent directory, not in the one used during rendering. That is why you get the error.

If you trick rmarkdown by writing the intermediates file in working dir too, it will work as expected.

work_dir <- getwd()
# html file will be written to Rmd dir
rmarkdown::render("Rmd/main.Rmd", 
                  # chunks will be evaluated with this working dir
                  knit_root_dir = work_dir, 
                  # md file to be converted by pandoc will be in working dir
                  intermediates_dir = work_dir)

There is no pandoc error in this case.

You could think that a full path is better for include_graphics, but a relative path is used here, because if HTML is not self contained, the image file need to be accessible from the html file that will be produce inside the Rmd directory. With your example, try setting a full path

knitr::include_graphics(normalizePath("subdir/emoji.png"))

It will work with self-contained. But not without as you can't load an image in web page from a full path on disk. You can try.

I hope this helps understand how all this works under the hood.

In the end, we may improve how include_graphics works for self-contained output. I need to 🤔 about it to see if something could be done...

As often, I think rmarkdown works better if anything is accessible relatively from the directory were the Rmarkdown file is. If not, you need to take care on where and how it is included. managing path for cache, intermediates, dependencies and all is not easy, and having it all relatively to the Rmd file is a lot easier.

Thanks for the report though !

@sleeubc
Copy link
Author

@sleeubc sleeubc commented May 13, 2020

I appreciate your detailed reply. As you suggested, I will use relative paths to Rmd documents.

@fernandomayer
Copy link

@fernandomayer fernandomayer commented Jun 16, 2020

I'm having a similar issue with knitr::include_graphics, but with a Rnw file instead of Rmd.

A minimal reproducible example is here:
rnw-example.zip

  1. Set the working directory to the root of the project, e.g., setwd("/somewhere/rnw-example")
  2. Run knitr::knit("main.Rnw")
  3. Run system("pdflatex main.tex")

The resulting PDF file will contain the histogram generated in the first chunk, but it will not find the figure in img directory.

However, this used to work, at least with knitr 1.23 (I tested with this version now and it really works). But, with the last version (1.28.9) it does not work anymore.

I believe that if this change wasn't intentional, then it must be a bug in recent versions.

> xfun::session_info("knitr")
R version 4.0.1 (2020-06-06)
Platform: x86_64-pc-linux-gnu (64-bit)
Running under: Manjaro Linux

Locale:
  LC_CTYPE=en_GB.UTF-8       LC_NUMERIC=C              
  LC_TIME=en_GB.UTF-8        LC_COLLATE=en_GB.UTF-8    
  LC_MONETARY=en_GB.UTF-8    LC_MESSAGES=en_GB.UTF-8   
  LC_PAPER=en_GB.UTF-8       LC_NAME=C                 
  LC_ADDRESS=C               LC_TELEPHONE=C            
  LC_MEASUREMENT=en_GB.UTF-8 LC_IDENTIFICATION=C       

Package version:
  evaluate_0.14   glue_1.4.1      graphics_4.0.1  grDevices_4.0.1
  highr_0.8       knitr_1.28.9    magrittr_1.5    markdown_1.1   
  methods_4.0.1   mime_0.9        stats_4.0.1     stringi_1.4.6  
  stringr_1.4.0   tools_4.0.1     utils_4.0.1     xfun_0.14      
  yaml_2.2.1     

@cderv
Copy link
Collaborator

@cderv cderv commented Jun 17, 2020

However, this used to work, at least with knitr 1.23 (I tested with this version now and it really works). But, with the last version (1.28.9) it does not work anymore.

I think the change you are looking for is the one describe in NEWS

By default, include_graphics(files) will signal an error if any files do not exist and are not web resources. To avoid the error (e.g., if you think it is a false positive), use include_graphics(..., error = FALSE)

In last dev version, you can now change the value through a global R option

The argument error of include_graphics() takes value from the global R option knitr.graphics.error by default, e.g., you may set options(knitr.graphics.error = FALSE) so include_graphics() won't signal an error if the graphics file to be included doesn't exist.

Try setting options(knitr.graphics.error = FALSE) before knitting your file, and you won't have the error.

reproducible example
# Using dev version
# remotes::install_github("yihui/knitr")
dir.create(tmp_dir <- tempfile())
old <- setwd(tmp_dir)
xfun::download_file("https://github.com/yihui/knitr/files/4784206/rnw-example.zip")
unzip("rnw-example.zip")
setwd("rnw-example/")
fs::dir_ls()
# rstudioapi::navigateToFile("main.Rnw")
# rstudioapi::navigateToFile("subdir/file1.Rnw")
knitr::knit("main.Rnw")
# we have the error
# rstudioapi::navigateToFile("main.tex")
xfun::read_utf8("main.tex")[78]
# do not throw an error
options(knitr.graphics.error = FALSE)
knitr::knit("main.Rnw")
# rstudioapi::navigateToFile("main.tex")
xfun::read_utf8("main.tex")[77]
fs::dir_ls()
tinytex::pdflatex("main.tex")
# open pdf (I am on windows)
# shell.exec("main.pdf")
# clean
unlink(tmp_dir, recursive = TRUE)
setwd(old)


However, you're issue is with the child document, used in child chunk option, and I think it should not throw an error... 🤔 I suppose the child document is executed in its own folder so "img/Rlogo.pdf" does not exist relatively to subdir/.
I'll look deeper into it to see if I am right.

@cderv
Copy link
Collaborator

@cderv cderv commented Jun 17, 2020

I suppose the child document is executed in its own folder so

This is confirmed. The child document is evaluated as any other document and by default each chunks is executed in the directory of the input document, i.e subdir/ in your case for the child document.
This is why this will error as subdir/img/Rlogo.pdf does not exists

include_graphics("img/Rlogo.pdf")

You can use

include_graphics("img/Rlogo.pdf", error = FALSE)

and it will not error. (as before knitr < 1.28)
Setting the option knitr.graphics.error to FALSE will get you this old behavior. You can also, if desired, configure the child document so that the chunks are evaluated in the current working dir (or another dir)

I think everything is already here so that it works correctly, isn't it ?

Hope it helps.

@Danny-dK
Copy link

@Danny-dK Danny-dK commented Nov 19, 2020

Not sure if this helps.
I had a similar issue where my child rmd were in a sub directory and knitr couldn't find an image (normalizePath did not work either). This solution worked here https://stackoverflow.com/a/61067297 by using paste0(getwd(), '/imagefolder/img.png') within the include_graphics part.

@cderv
Copy link
Collaborator

@cderv cderv commented Jan 29, 2021

Reading this thread again I am not sure there is any issue with this apart from the one with child document where the new default error = TRUE can be unexpected.
I opened a new one for this: #1957

I'll close this one then.

Please open new issues if you have some unexpected behavior with this.

Thanks everyone.

@cderv cderv closed this as completed Jan 29, 2021
@cderv cderv added the question label Jan 29, 2021
@github-actions
Copy link

@github-actions github-actions bot commented Aug 4, 2021

This old thread has been automatically locked. If you think you have found something related to this, please open a new issue by following the issue guide (https://yihui.org/issue/), and link to this old issue if necessary.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Aug 4, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
question
Projects
None yet
Development

No branches or pull requests

5 participants