renderthis icon indicating copy to clipboard operation
renderthis copied to clipboard

excluding certain slides while rendering

Open SNAnalyst opened this issue 1 year ago • 13 comments

I often make slide decks (I still use Xaringan, but this will also be true when I move to Quarto for making my slides) that include several slides I do not want to include in a pdf handout. So, I'll make an extensive set of slides and render those to html for my actual live presentation. But, when I share a pdf handout of the presentation afterwards, I usually want to exclude several slides (e.g., slides with copyrighted material, slides with the password for the wifi at a conference, slides that contain video, etc.).

It would be great if I could add a class to a slide that renderthis uses to skip it when building the pdf. For example, something like this:

---
class: not_handout

blabla content blabla
---

and then use: renderthis::to_pdf("slides.Rmd", skip = "not_handout")

Of course, if there already is some way to hack this, that would be great too.

SNAnalyst avatar Sep 18 '24 14:09 SNAnalyst

Hmm, adding some kind of class like that would probably require a change to the xaringan package as all renderthis does is call the package to render the slides. renderthis does have a slides argument in some functions, e.g. to_png("slides.pdf", slides = c(1, 3, 5)), but not to_pdf(). So if you knew the slide numbers you wanted to include this could be used, but it would only return a set of pngs, not the pdf. We could probably add this slides argument though to the to_pdf() function. It's certainly less ideal though because you'd have to keep track of all the slide numbers, and if you changed one thing like insert a single slide then all those numbers are off, so the class approach would really be much nicer. I just don't think that's something renderthis could address.

jhelvy avatar Sep 18 '24 16:09 jhelvy

Btw this is a good idea, so I would reach out to the Quarto team too as they could probably add something like this to the revealjs slides.

jhelvy avatar Sep 18 '24 16:09 jhelvy

Thanks! This helps. It should be fairly easy to write a helper function that returns the slides with the specific class. That way, it is not really much of an inconvenience to have to "manually" extract the slide numbers with the class. It could automatically return the slide numbers, so no bookkeeping is needed when slides are added to or removed to the whole deck.

It would be awesome if the slides argument could be included in to_pdf and in to_html so that published slide decks can be curated.

Here is one simple piece of code I whipped together to extract the slide numbers that have the class that I would like to exclude

slides_to_exclude <- function(rmd, class = "no_handout") {
  txt <- readLines(rmd_file)
  # identify the slides
  all_slides <- which(txt == "---")
  n_slides <- length(all_slides)
  class_line <- which(grepl(paste0("class[:].*", class), txt))
  
  # which slide is this class on
  slides_no <- findInterval(class_line, all_slides)
  # correct for opening slide and YAML
  seal <- any(sapply(1:(all_slides[2] - 1), function(z) grepl("seal[:] false", txt[z])))
  if (seal) {
    slides_no <- slides_no - 2
  } else {
    slides_no <- slides_no - 1
  }
  slides_no
}

With the help of that, it would be straightforward to run something like:

renderthis::to_pdf(rmdfile, slides = -slides_to_exclude(rmdfile, class = "no_handout")) renderthis::to_html(rmdfile, slides = -slides_to_exclude(rmdfile, class = "no_handout"))

Of course, the slides_to_exclude() function can be improved upon, but something like this should work and be a life-saver

SNAnalyst avatar Sep 19 '24 13:09 SNAnalyst

It should be fairly easy to write a helper function that returns the slides with the specific class. That way, it is not really much of an inconvenience to have to "manually" extract the slide numbers with the class. It could automatically return the slide numbers, so no bookkeeping is needed when slides are added to or removed to the whole deck.

This is the kind of thing that's easy to get right for one particular slide deck and hard to get right for all slide decks all the time. We're using browser automation via chromote for complex slides and doing the filtering in the browser is the only reliable way to ensure you're hiding the slides you want to hide.

That said, this could be relatively easy with CSS that could be added to the slide deck. (To be clear, added by authors to their own stylesheets and not injected by renderthis.) A @media print {} query combined with an appropriate display: none would work:

@media print {
  .remark-slide-container:has(.remark-slide-content.no_handout) {
    display: none;
  }
}

gadenbuie avatar Sep 19 '24 15:09 gadenbuie

Yes, Garrick, I agree that the function may not work for every slide deck. The point was that I am OK with having to provide slide numbers to the to_pdf and to_html functions myself, because if I don't want to manually keep track of which slides I want to exclude (like the user has to do in to_png as well), I can easily write a little function that does it for me on my slide deck. I definitely did not expect you to include such a function in the package.

Anyway, I am suggesting that it would be very useful to have a slides argument in to_pdf and to_html, so users can decide to exclude certain slides when printing to pdf or to html, just like in the to_png function that is already in the renderthis package.

SNAnalyst avatar Sep 20 '24 08:09 SNAnalyst

to fix your trouble check this solution click maybe this will solve your problem.

Ya'll is this spam?

jhelvy avatar Oct 24 '24 00:10 jhelvy

Hi, I have been trying to use to_pdf to render panelsets in my xaringan slides and cannot figure out how to make it work with the changes to chrome (headless). I have updated my chromote package, not sure what else to do. Any help is appreciated.

to_pdf("u3-d01-viz-num.html", complex_slides = TRUE) Error in onRejected(reason) : code: -32000 message: Browser window not found

grover4 avatar Mar 21 '25 18:03 grover4

Have you looked over the setup configuration for your browser?

jhelvy avatar Mar 21 '25 19:03 jhelvy

Thanks for the reply! I had not before writing, but tried what was suggested but still getting the same error. I am pretty sure it has something to do with chrome going headless (whatever that means... ). This function used to work for me before with panelsets

Sys.setenv(PAGEDOWN_CHROME = "C:\Program Files\Google\Chrome\Application\chrome.exe") Sys.setenv(CHROMOTE_CHROME = "C:\Program Files\Google\Chrome\Application\chrome.exe")

to_pdf("u3-d01-viz-num.html",complex_slides = TRUE) Error in onRejected(reason) : code: -32000 message: Browser window not found

grover4 avatar Mar 21 '25 19:03 grover4

There have been quite a few changes in Chrome in the last year. We just released a new version of chromote that may resolve your issues. You can read about it here: https://shiny.posit.co/blog/posts/chromote-0.5.0/

If just updating chromote doesn't do the trick, try this

library(chromote) #v0.5.0

local_chrome_version(binary = "chrome-headless-shell")

# ... renderthis code ...

gadenbuie avatar Mar 21 '25 22:03 gadenbuie

Yay! Thanks so much! The local_chrome_version line did the trick. I had updated the chromote package to version 0.5.0 and also tried local_chrome_version earlier, but not with this particular binary "chrome-headless-shell".

Just to be sure, I notice that I need to use the local_chrome_version line before every call of renderthis, even within a single R session. Is this accurate?

grover4 avatar Mar 21 '25 23:03 grover4

Great to hear!

I notice that I need to use the local_chrome_version line before every call of renderthis, even within a single R session. Is this accurate?

No, you should only need to do this once per session.

gadenbuie avatar Mar 21 '25 23:03 gadenbuie

Hm, ok. I did need to type it again but I am leaving it alone for now.. :) Thanks again

grover4 avatar Mar 22 '25 00:03 grover4