rstudio / rmarkdown

Dynamic Documents for R
https://rmarkdown.rstudio.com
GNU General Public License v3.0
2.87k stars 972 forks source link

Knitting to pdf crashes with `out.width=` specification in the code chunk #2460

Open oolonek opened 1 year ago

oolonek commented 1 year ago
---
title: 'Min example'
date: "`r format(Sys.time(), '%d %B, %Y')`"
output:
  bookdown::html_document2:
    df_print: paged
    toc: TRUE
  bookdown::word_document2: default
  bookdown::pdf_document2:
    toc: no
    fig_caption: yes
    number_sections: true
    keep_tex: yes
always_allow_html: yes
latex_engine: pdflatex
---

```{r message=FALSE, warning = FALSE}
library(knitr)
library(rmarkdown)
library(plotly)
library(plotly)
p <- plot_ly(economics, x = ~date, y = ~unemploy / pop)
p
xfun::session_info('rmarkdown')

output from `xfun::session_info('bookdown')` 

xfun::session_info('rmarkdown') R version 4.2.2 (2022-10-31) Platform: x86_64-apple-darwin17.0 (64-bit) Running under: macOS Big Sur ... 10.16

Locale: en_US.UTF-8 / en_US.UTF-8 / en_US.UTF-8 / C / en_US.UTF-8 / en_US.UTF-8

Package version: base64enc_0.1.3 bslib_0.4.2 cachem_1.0.7 cli_3.6.0
digest_0.6.31 ellipsis_0.3.2 evaluate_0.20 fastmap_1.1.1
fs_1.6.1 glue_1.6.2 graphics_4.2.2 grDevices_4.2.2 highr_0.10 htmltools_0.5.4 jquerylib_0.1.4 jsonlite_1.8.4 knitr_1.42 lifecycle_1.0.3 magrittr_2.0.3 memoise_2.0.1
methods_4.2.2 mime_0.12 R6_2.5.1 rappdirs_0.3.3 rlang_1.0.6 rmarkdown_2.20 sass_0.4.5 stats_4.2.2
stringi_1.7.12 stringr_1.5.0 tinytex_0.44 tools_4.2.2
utils_4.2.2 vctrs_0.5.2 xfun_0.37 yaml_2.3.7

Pandoc version: 3.1


When running the previous minimal example with `rmarkdown::render('min_ex.rmd', output_dir = '../docs/report/', output_format = 'bookdown::pdf_document2', knit_root_dir = getwd())` I get the following error : 

processing file: min_ex.rmd |.............................. | 57% (unnamed-chunk-2)Quitting from lines 45-48 (min_ex.rmd) Error in s$close() : attempt to apply non-function



If I change the r chunk specification from 
`
```{r, echo=FALSE, fig.cap="plotly_test", fig.topcaption=TRUE, warning=F, out.width="100%", out.height="100%"}```
`
to 
`
```{r, echo=FALSE, fig.cap="plotly_test", fig.topcaption=TRUE, warning=F}```
`
then the output is correctly knitted.

No problem when knitting to html.
cderv commented 1 year ago

Thanks I can reproduce and the traceback of the error is this

Error in `s$close()`:
! tentative d'appliquer un objet qui n'est pas une fonction
Backtrace:
  1. rmarkdown::render("C:/Users/chris/Documents/test.Rmd", encoding = "UTF-8")
  2. knitr::knit(knit_input, knit_output, envir = envir, quiet = quiet)
  3. knitr:::process_file(text, output)
  6. knitr:::process_group.block(group)
  7. knitr:::call_block(x)
     ...
 27. chromote:::synchronize(p, loop = private$child_loop)
 31. base::tryCatch(...)
 32. base (local) tryCatchList(expr, classes, parentenv, handlers)
 33. base (local) tryCatchOne(expr, names, parentenv, handlers[[1L]])
 34. base (local) doTryCatch(return(expr), name, parentenv, handler)
Exécution arrêtée

This seems to be an issue with chromote as it is used by webshot2 which is called by knitr to take a screenshot of the HTMLWIDGET for including into the PDF.

i'll see if something has changed there or how it interfere with the options

cderv commented 1 year ago

Simplified example showing this is not bookdown related

---
title: "Min example"
date: "`r format(Sys.time(), '%d %B, %Y')`"
output:
  pdf_document: default
  html_document:
    df_print: paged
---

```{r message=FALSE, warning = FALSE}
library(plotly)
#| out.height="100%"
library(plotly)
p <- plot_ly(economics, x = ~date, y = ~unemploy / pop)
p

Full error 

````r
Error in `s$close()`:
! attempt to apply non-function
---
Backtrace:
     ▆
  1. └─rmarkdown::render("test.Rmd")
  2.   └─knitr::knit(knit_input, knit_output, envir = envir, quiet = quiet)
  3.     └─knitr:::process_file(text, output)
  4.       ├─base::withCallingHandlers(...)
  5.       ├─base::withCallingHandlers(...)
  6.       ├─knitr:::process_group(group)
  7.       └─knitr:::process_group.block(group)
  8.         └─knitr:::call_block(x)
  9.           └─knitr:::block_exec(params)
 10.             └─knitr:::eng_r(options)
 11.               ├─knitr:::in_input_dir(...)
 12.               │ └─knitr:::in_dir(input_dir(), expr)
 13.               └─knitr (local) evaluate(...)
 14.                 └─evaluate::evaluate(...)
 15.                   └─evaluate:::evaluate_call(...)
 16.                     ├─base (local) handle(...)
 17.                     ├─base::withCallingHandlers(...)
 18.                     ├─base::withVisible(value_fun(ev$value, ev$visible))
 19.                     └─knitr (local) value_fun(ev$value, ev$visible)
 20.                       └─knitr (local) fun(x, options = options)
 21.                         ├─base::withVisible(knit_print(x, ...))
 22.                         └─knitr::knit_print(x, ...)
 23.                           └─knitr:::html_screenshot(x)
 24.                             ├─knitr:::in_dir(...)
 25.                             ├─base::do.call(...)
 26.                             └─webshot2 (local) `<fn>`(...)
 27.                               └─cm$wait_for(p)
 28.                                 └─chromote:::synchronize(p, loop = private$child_loop)
 29.                                   ├─promises::with_promise_domain(...)
 30.                                   │ └─domain$wrapSync(expr)
 31.                                   │   └─base::force(expr)
 32.                                   └─base::tryCatch(...)
 33.                                     └─base (local) tryCatchList(expr, classes, parentenv, handlers)
 34.                                       └─base (local) tryCatchOne(expr, names, parentenv, handlers[[1L]])
 35.                                         └─base (local) doTryCatch(return(expr), name, parentenv, handler)
cderv commented 1 year ago

So this is indeed an issue with webshot2 and chromote as it does not seem they accept width and height in %.

Currently when provided as knitr option on the chunk, we pass out.width and out.height (user specified or internally computed) as value to webshot2::webshot() - see

Here is a minimal reprex:

> webshot2::webshot("https://github.com/rstudio/shiny", vwidth = 468, vheight = "100%")
Error in s$close() : attempt to apply non-function

I don't think it can take % really, but they should at least error nicely if this is the case.

On our side, I wonder if we can pass some pixel value when a % value is passed to out.(witdh|height) options. @yihui in case you have an idea...

thanks for the report @oolonek. As a workaround, it seems older webshot 📦 (which is using deprecated phantomjs tool) accepts % so you can default to this in the meantime setting this in setup chunk

knitr::opts_chunk$set(webshot = "webshot")

or webshot = "webshot" as chunk option.

Hope it helps

oolonek commented 1 year ago

Thanks for the workaround @cderv ! Will watch here for the longer term solution.

retodomax commented 6 months ago

Thanks @cderv. I run into the same issue

See reprex below

---
title: Test
format:
  pdf: default
fig-width: 6
fig-asp: 0.618
---

## Plots

```{r}
library(leaflet)
leaflet() %>%
  addTiles()


Workaround with `webshot = "webshot"` works also in this case.
cderv commented 6 months ago

Thanks for the report. This is still an issue with webshot2 I believe that does not handle the resulting dimensions.

It seems not to handle the decimal value

webshot2::webshot("https://github.com/rstudio/shiny", vwidth = 6*72, vheight = 6*72*0.618)
#> Error in s$close(): tentative d'appliquer un objet qui n'est pas une fonction

(6 is your fig.width, 72 is the default DPI 0.618 is the aspect ratio -> this is used to calculate the height))

As I said above, maybe we can do something in knitr to pass transformed argument, but we would need to round the number here.

It seems an issue in webshot2 really. 🤔

davidperezros commented 5 days ago

I've just had the same issue. @cderv solution worked perfectly in my case. Can anyone explain me why by specifyng in the chunk options webshot = "webshot" problem is solved? Shouldn't be by default webshot = "webshot"?

Thanks in advance!

P.S: First time adding a comment on a GH issue. Don't know if I'm using this tool properly!

So this is indeed an issue with webshot2 and chromote as it does not seem they accept width and height in %.

Currently when provided as knitr option on the chunk, we pass out.width and out.height (user specified or internally computed) as value to webshot2::webshot() - see

Here is a minimal reprex:

> webshot2::webshot("https://github.com/rstudio/shiny", vwidth = 468, vheight = "100%")
Error in s$close() : attempt to apply non-function

I don't think it can take % really, but they should at least error nicely if this is the case.

On our side, I wonder if we can pass some pixel value when a % value is passed to out.(witdh|height) options. @yihui in case you have an idea...

thanks for the report @oolonek. As a workaround, it seems older webshot 📦 (which is using deprecated phantomjs tool) accepts % so you can default to this in the meantime setting this in setup chunk

knitr::opts_chunk$set(webshot = "webshot")

or webshot = "webshot" as chunk option.

Hope it helps

cderv commented 5 days ago

Can anyone explain me why by specifyng in the chunk options webshot = "webshot" problem is solved? Shouldn't be by default webshot = "webshot"?

knitr will by default use either webshot or webshot2 depending on which is installed. Priority is given to webshot2 in this detection as it is a more recent package based on chromium features, while webshot use deprecated phantomjs.

This is up to the user to set its own default using global knitr option for example if the current default is not desired.