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

rgl plots don't display in quarto #1800

Closed
dmurdoch opened this issue Aug 10, 2022 · 12 comments · Fixed by #1857
Closed

rgl plots don't display in quarto #1800

dmurdoch opened this issue Aug 10, 2022 · 12 comments · Fixed by #1857
Labels
third-party Issues involving interaction with a third-party library
Milestone

Comments

@dmurdoch
Copy link
Contributor

rgl plots work in RMarkdown using several low level hooks that are set up by the rgl::setupKnitr() function. This doesn't work in quarto, presumably because things are implemented differently, though other htmlwidgets-using packages (e.g. leaflet) work fine.

I'm not sure if this requires changes to rgl, to quarto, or to both.

I've also started an rgl issue.

Here's a sample RMarkdown document:

---
title: "Untitled"
output: html_document
---

```{r}
library(rgl)
setupKnitr(autoprint = TRUE)
```

```{r}
plot3d(1:10, 1:10, 1:10)
```

Here's the same thing as a Quarto document:

---
title: "Untitled"
format: html
editor: visual
---

This normally wouldn't be echoed:

```{r}
library(rgl)
setupKnitr(autoprint = TRUE)
```

rgl doesn't display:

```{r}
plot3d(1:10, 1:10, 1:10)
```
@cscheid
Copy link
Collaborator

cscheid commented Aug 11, 2022

Maybe a place to start is for you to see if there's a difference between leaflet and rgl's setup.

@cscheid cscheid added this to the Future milestone Aug 11, 2022
@cscheid cscheid added the third-party Issues involving interaction with a third-party library label Aug 11, 2022
@dmurdoch
Copy link
Contributor Author

Yes, there certainly is, because rgl tries to emulate base graphics (i.e. minor changes should be ignored, only major changes should be displayed).

@dmurdoch
Copy link
Contributor Author

The biggest difference I've found so far is printing methods(knitr::sew): in RMarkdown, this prints

methods(knitr::sew)

##  [1] sew.character*        sew.default*          sew.error*           
##  [4] sew.html_screenshot*  sew.knit_asis*        sew.knit_embed_url*  
##  [7] sew.knit_image_paths* sew.list*             sew.message*         
## [10] sew.recordedplot*     sew.rglRecordedplot*  sew.rlang_error*     
## [13] sew.source*           sew.warning*         
## see '?methods' for accessing help and source code

and rgl reliies on it to display the plot. In Quarto, I see

methods(knitr::sew)

no methods found

In knitr, display of graphics happens in two steps. The second step is called sew, but it looks like Quarto isn't using that. Can you point me to how Quarto does printing?

@dmurdoch
Copy link
Contributor Author

I think the issue might lie in this code that patches knitr::sew with a non-generic function:

# this used to be completely generic, however R 3.4 wasn't able to
# dispatch correctly via UseMethod so we do manual binding
} else if (inherits(x, "character")) {
knitr:::sew.character(x, options, ...)
} else if (inherits(x, "html_screenshot")) {
knitr:::sew.html_screenshot(x, options, ...)
} else if (inherits(x, "knit_embed_url")) {
knitr:::sew.knit_embed_url(x, options, ...)
} else if (inherits(x, "source")) {
knitr:::sew.source(x, options, ...)
} else if (inherits(x, "warning")) {
knitr:::sew.warning(x, options, ...)
} else if (inherits(x, "message")) {
knitr:::sew.message(x, options, ...)
} else if (inherits(x, "error")) {
knitr:::sew.error(x, options, ...)
} else if (inherits(x, "list")) {
knitr:::sew.list(x, options, ...)
} else if (inherits(x, "recordedplot")) {
knitr:::sew.recordedplot(x, options, ...)
} else {
# this works generically for recent versions of R however
# not for R < 3.5
knitr_sew(x, options, ...)
}
}

The result of knit_print on the graph to print from rgl should have class c("rglRecordedplot", "knit_other_plot"), neither of which is in the list of specified classes, so I believe this should fall through to the call to knitr_sew, the saved copy of knitr::sew before patching. However, somehow the methods table has been messed up as shown in my previous comment, so it doesn't get dispatched.

@jjallaire
Copy link
Collaborator

Hi @dmurdoch, just a note that we are doing this so that we can provide a more predictable markdown AST for downstream filters (e.g. enclosing things in the correct div structure). If you want to play with other variations of patching / dispatching to knitr::sew() then it is very easy to install the development version of Quarto, after which time you can just hack on patch.R without any rebuild.

To install the dev version: https://github.com/quarto-dev/quarto-cli#development-version

You may need to add quarto-cli/package/dist/bin to your path to make sure that the dev version is picked up by default. You can confirm you are running the dev version with:

$ quarto --version

Which should be 99.9.9

I'm also happy to hack on this with some guidance from you (i.e. more directed speculation as to what sort of change would get rgl working and preserve our override). I note that in the comments we have some code that works around limitations in R 3.4 -- I think we could probably drop this at this point if need be.

Note also that changes in knitr could resolve this (and mitigrate the need to do any patching) but we generally don't want to depend on the very latest version of knitr.

@dmurdoch
Copy link
Contributor Author

@jjallaire, thanks for the dev install instructions. I'll try that and see if I can figure out what's going on.

@jjallaire
Copy link
Collaborator

When working on the R code its hard (impossible?) to hit a breakpoint b/c the R code is run from Quarto not from the current R session. I typically just use calls to str() to figure out what's going on (and note again that as soon as you make a change to patch.R it will be available, no need to restart preview or do any build or configure)

@jjallaire
Copy link
Collaborator

I'm not seeing the scroll bar you mention. One thing we do with htmlwidgets in Quarto is that if they mark themselves as "knitr figures" (i.e. respecting fig.width and fig.height) then we attempt to make them responsive to the width of the body column by setting width=100% (which should at a minimum avoid horizontal scrollbars). Here is what I see on OS X w/ Chrome:

Screen Shot 2022-08-13 at 1 45 27 PM

Perhaps there is another example that will exhibit the scroll bars? If so LMK and I can suggest an approach to work around this.

@jjallaire
Copy link
Collaborator

Re-opening pending resolution of the scrollbar issue.

@jjallaire jjallaire reopened this Aug 13, 2022
@dmurdoch
Copy link
Contributor Author

I'm not sure what's going on with the scrollbars. The initial display I see in Firefox has both showing. In Chrome I only get one, as in the attached screenshot
Screen Shot 2022-08-13 at 3 25 00 PM
.

@jjallaire
Copy link
Collaborator

Okay, I did indeed observed the scrollbar in Firefox.

We set overflow-x: auto on output divs (e.g. so that wide tables can scroll horizontally). I think this CSS is giving canvas some trouble so I just trigger an opt-out for overflow-x when I see an RGL widget (we already had this implemented for shiny select inputs): 0e49ed4

@dmurdoch
Copy link
Contributor Author

Thanks, looks great now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
third-party Issues involving interaction with a third-party library
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants