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

Can't compile to PDF when including an R HTML widget #4225

Closed
4 tasks done
juba opened this issue Feb 4, 2023 · 10 comments
Closed
4 tasks done

Can't compile to PDF when including an R HTML widget #4225

juba opened this issue Feb 4, 2023 · 10 comments
Assignees
Labels
documentation Doc improvements & quarto-web
Milestone

Comments

@juba
Copy link

juba commented Feb 4, 2023

Bug description

Compiling a qmd file to PDF doesn't work if it contains an R HTML widget. Here is a minimal reproducible example with a leaflet map (but the behavior is the same with a visNetwork graph for example) :

---
format:
  pdf:
    prefer-html: false
---

# Leaflet test

```{r}
library(leaflet)

leaflet() %>%
  addTiles()
```

When rendering to PDF with prefer-html: false, I get the following error message :

Error : Functions that produce HTML output found in document targeting pdf output.
Please change the output type of this document to HTML. Alternatively, you can allow
HTML output in non-HTML formats by adding this option to the YAML front-matter of
your quarto file:

prefer-html: true

Note however that the HTML output will not be visible in non-HTML formats.

If I set prefer-html: true, I get another error message during xelatex compilation step :

compilation failed- error
LaTeX Error: Missing \begin{document}.

See the LaTeX manual or LaTeX Companion for explanation.
Type H for immediate help.
...

l.141 <
script src="site_libs/htmlwidgets-1.6.1/htmlwidgets.js"></script>

Indeed, if I take a look at the generated TeX file there are <script> and <link> tags inserted inside TeX code.

I'm using quarto 1.2.335 with Visual Studio code under Linux (KDE Neon / Ubuntu 22.04).

Thanks a lot !

Checklist

  • Please include a minimal, fully reproducible example in a single .qmd file? Please provide the whole file rather than the snippet you believe is causing the issue.
  • Please format your issue so it is easier for us to read the bug report.
  • Please document the RStudio IDE version you're running (if applicable), by providing the value displayed in the "About RStudio" main menu dialog?
  • Please document the operating system you're running. If on Linux, please provide the specific distribution.
@juba juba added the bug Something isn't working label Feb 4, 2023
@cscheid cscheid added the needs-discussion Issues that require a team-wide discussion before proceeding further label Feb 4, 2023
@cderv
Copy link
Collaborator

cderv commented Feb 6, 2023

Using HTML widgets in Rmd or Qmd document with knitr should work the same. We mentions this here:
https://bookdown.org/yihui/rmarkdown-cookbook/html-widgets.html

Equivalent of prefer-html is always_allow_html: yes with R Markdown, and should only be used edge case - It is expected that the HTML content is ignored by Pandoc. Correct way to include widgets for PDF or WORD output is to do a screenshort, which should happen automatically with knitr

This is what happens for me when I copy paste your example in test2.qmd. See knitr log in console

processing file: test2.qmd
  |...................................                 |  67% (unnamed-chunk-1)file://C:\Users\chris\AppData\Local\Temp\RtmpshHYSX\file4fd842046a37\widget4fd84c4161c4.html screenshot completed
                                                                                                            
output file: test2.knit.md

Output is a PDF with a screenshot of the leaflet map for me. This is the expected output I believe.

This will happen only if one of the webshot tools is available. Can you check ?

> knitr:::webshot_available()
webshot2  webshot 
    TRUE     TRUE 

It is possible you don't have that, and why screenshot does not happen. Installing one of the R package should work.

Regarding what happens when prefer-html: true is set, it seems we have an issue indeed with Quarto. The HTML widget code will be correctly inserted using raw HTML code.

::: {.cell-output-display}

```{=html}
<div class="leaflet html-widget html-fill-item-overflow-hidden html-fill-item" id="htmlwidget-11c313e2f71355dccf95" style="width:1650px;height:1050px;"></div>
<script type="application/json" data-for="htmlwidget-11c313e2f71355dccf95">...</script>
```

:::

so it will be ignored by Pandoc when creating the TeX file. However, we are inserting some HTML dependency in the TeX header, which is a bug

<script src="test2_files/libs/htmlwidgets-1.6.1/htmlwidgets.js"></script>
<script src="test2_files/libs/jquery-1.12.4/jquery.min.js"></script>
<link href="test2_files/libs/leaflet-1.3.1/leaflet.css" rel="stylesheet" />
<script src="test2_files/libs/leaflet-1.3.1/leaflet.js"></script>
<link href="test2_files/libs/leafletfix-1.0.0/leafletfix.css" rel="stylesheet" />
<script src="test2_files/libs/proj4-2.6.2/proj4.min.js"></script>
<script src="test2_files/libs/Proj4Leaflet-1.0.1/proj4leaflet.js"></script>
<link href="test2_files/libs/rstudio_leaflet-1.3.1/rstudio_leaflet.css" rel="stylesheet" />
<script src="test2_files/libs/leaflet-binding-2.1.1/leaflet.js"></script>

I though we had fix this, but it seems not everywhere - Related issue : #1378

I'll look into this @cscheid

@juba
Copy link
Author

juba commented Feb 6, 2023

You're right, I didn't have webshot or webshot2 installed. If I install them and compile the file with prefer-html: false, the PDF is rendered with a screenshot, which is nice. If I install them and compile to PDF with prefer-html: true, I still have the same error due to included HTML tags in LaTeX file.

Thanks for the detailed answer !

@cderv
Copy link
Collaborator

cderv commented Feb 6, 2023

If I install them and compile to PDF with prefer-html: true, I still have the same error due to included HTML tags in LaTeX file.

Thanks for confirming. This is indeed an issue I think - in R Markdown, we correctly do not include HTML dependency in non HTML output, even when always_allow_html: true

@cderv cderv added this to the v1.3 milestone Feb 6, 2023
@cscheid cscheid removed the needs-discussion Issues that require a team-wide discussion before proceeding further label Feb 6, 2023
@cderv cderv added documentation Doc improvements & quarto-web and removed bug Something isn't working labels Mar 9, 2023
@cderv cderv modified the milestones: v1.3, v1.4 Apr 7, 2023
@cderv
Copy link
Collaborator

cderv commented Apr 11, 2023

Another related discussion item that shows we need to deal with this better: #5160 as the message is really unclear (coming from rmarkdown and not adapted to Quarto IMO)

@jtkiley
Copy link

jtkiley commented Nov 16, 2023

Correct way to include widgets for PDF or WORD output is to do a screenshort, which should happen automatically with knitr

@cderv Is there an equivalent way to get an automatic screenshot with Python? I have a similar snag where I'm using plotly to make graphs for both HTML and PDF output. HTML is fine and the PDF has mime errors.

Alternatively, is there a workaround to embed the optionality so that the HTML version renders inline and the PDF gets a screenshot (even if manually serialized and then inserted as an image)? I'm thinking something like hidden code blocks/markdown that only run for the PDF version and some way of setting eval: false for PDF only. The overall idea here is a qmd file that generates both outputs correctly (without editing between runs), even if it's a bit of a hack.

I didn't find an issue tracking this for Python, but I'm happy to make one or comment there if it helps.

@cderv
Copy link
Collaborator

cderv commented Nov 17, 2023

Is there an equivalent way to get an automatic screenshot with Python? I have a similar snag where I'm using plotly to make graphs for both HTML and PDF output. HTML is fine and the PDF has mime errors.

In R, this is done directly by knitr (used by Quarto) which will detect a htmlwidget content, and trigger the snapshoting to include as an image and not a HTML content.

For python, this would require same logic but in jupyter. I know of some ways to to export as an image. For example, with Plotly you can do export to image (https://plotly.com/python/static-image-export#display-bytes-as-image-using-ipythondisplayimage)

This would be a way to do it conditionally
---
title: "test"
format: 
  html: default
  pdf: default
keep-md: true
---

## Two Figures

```{python}
#| echo: true
#| output: false
import plotly.graph_objects as go
from IPython.display import Image
import numpy as np
np.random.seed(1)

N = 100
x = np.random.rand(N)
y = np.random.rand(N)
colors = np.random.rand(N)
sz = np.random.rand(N) * 30

fig = go.Figure()
fig.add_trace(go.Scatter(
    x=x,
    y=y,
    mode="markers",
    marker=go.scatter.Marker(
        size=sz,
        color=colors,
        opacity=0.6,
        colorscale="Viridis"
    )
))
```

::: {.content-visible when-format='pdf'}
```{python}
#| echo: false
img_bytes = fig.to_image(format="png")

Image(img_bytes)
```

:::

::: {.content-visible when-format='html'}
```{python}
#| echo: false
fig.show()
```
:::

Not ideal as it will evaluate both cells, but just include the right result. This will be improve when it will be possible to do pre-engine filter. Which is not yet possible.

Also, this will be different depending on the tools (with bokeh you would need to export to png using selenium I believe (https://docs.bokeh.org/en/latest/docs/first_steps/first_steps_7.html), but the logic is the same.

So I don't think this is auto detected, and automatic, but this can be done with the right conditional.

Maybe it can be simplified if Python code in Jupyter does have access to the output format information, but I am not sure it does. (this would allow some if in Python cells for conditional, instead of using conditional div)

Hope it helps

@jtkiley
Copy link

jtkiley commented Nov 17, 2023

I'm going to try your sample approach soon with a recent document of mine, but it looks like a huge improvement from where I was. The parts I was missing were (i) using the div syntax, and (ii) using Image().

It would still be great to have it be more automatic, but a workaround is a lot better than the edit-and-rerun approach I was using.

Thank you!

@cderv
Copy link
Collaborator

cderv commented Nov 17, 2023

(ii) using Image().

To be clear, this is quite specific to IPython, and which tools supports it. it seems bokeh don't for example.

The keywords you need to look for is how to output to file in Jupyter. Quarto will run Jupyter for python, so you need the display of cells to output non HTML content for non HTML output.

It would still be great to have it be more automatic

I agree. I would be really good to have something like that !

@jtkiley
Copy link

jtkiley commented Nov 21, 2023

Thanks again, @cderv! I had a chance to test this out, and it worked well.

I did need to split the Image() calls into their own cells, which creates a little more friction, but it's not bad for a workaround. I'll also have to play around more with getting two graphs without a page break, but I'm way ahead of where I was. Many thanks!

@cderv
Copy link
Collaborator

cderv commented Nov 23, 2023

@jtkiley Great !

I will close this issue because the original issue is fixed

---
format: pdf
---

# Leaflet test

```{r}
library(leaflet)

leaflet() %>%
  addTiles()
```

now works correctly

  • when you have webshot or webshot2 installed and configured,
  • and the error message tells you to install then if not install (message thrown by rmarkdown)

So I believe this ok.

Please @juba do open a new issue if something is missing or should be clarified. We'll start fresh on the problem.

@jtkiley happy to discuss it further in https://github.com/quarto-dev/quarto-cli/discussions or open a new issue with improvement request if you think we should handle it better. I'll add an example about what we discussed though.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
documentation Doc improvements & quarto-web
Projects
None yet
Development

No branches or pull requests

4 participants