Generating a downloadable Quarto document from a shiny app on shinyapps.io

The following shiny app is intended pass user inputs from the app into a parameterized html quarto document that, when rendered, is downloaded via downloadHandler() and downloadButton(). This reproducible example works perfectly when deployed locally, but not when hosted on shinyapps.io. My understanding is that the quarto::quarto_render() call should have permission to write a file on shinyapps.io (it wouldn't be persistent from instance to instance, but that's fine). Does shinyapps.io not support quarto rendering? If not, does it support RMarkdown and would this code be expected to work with the appropriate conversions?

app.R:

library(shiny)
library(quarto)

ui <- fluidPage(

    titlePanel("Reproducable Example"),

    sidebarLayout(
      sidebarPanel(
        textInput(inputId = "user.name", label = "User name:"),
        br(),
        downloadButton(outputId = "report", label = "Generate Report:")
      ),
      mainPanel(
        
      )
    )
)


server <- function(input, output) {
  output$report <- downloadHandler(
    filename = "Reprod_ex.html",
    content = function(file) {
      
      quarto::quarto_render("myquarto.qmd", 
                            execute_params = list(username = input$user.name))
      
      file.copy("qmd_output.html", file)
      
    }
  )
}

# Run the application 
shinyApp(ui = ui, server = server)

myquarto.qmd:

---
format:
  html: 
    toc: false
    anchor-sections: false
    fig-cap-location: bottom
    tbl-cap-location: top
    number-sections: false
    smooth-scroll: true
    self-contained: true
    css: my-style.css
    output-file: "qmd_output.html"
params:
  username: NA
---

# Heading

My name is `r params$username`.
htmlrshinyshinyappsquarto

It looks like the issue you're encountering is related to file permissions when running the Shiny app on shinyapps.io. When the quarto_render() function is called, it attempts to create an output file (in this case "qmd_output.html") but is unable to do so due to restrictions on file creation and modification on shinyapps.io.

One solution to this problem would be to use the tempfile() function to create a temporary file that can be used as the output file for the quarto_render() function. This will allow the file to be created and modified within the Shiny app's file system on shinyapps.io.

You could update your server function to something like this:

Copy code

server <- function(input, output) {
  output$report <- downloadHandler(
    filename = "Reprod_ex.html",
    content = function(file) {
      
      temp_file <- tempfile(fileext = ".html")
      
      quarto::quarto_render("myquarto.qmd", 
                            execute_params = list(username = input$user.name),
                            output_file = temp_file)
      
      file.copy(temp_file, file)
      
    }
  )
}

Here, we're using tempfile() to create a temporary file with a ".html" file extension. Then we're passing this temporary file as the output_file argument to the quarto_render() function. And then we're copying the temp_file to the file which we want to download.

Additionally, you may also need to update the output-file parameter in your myquarto.qmd file to match the name of the temporary file being created.

It's also important to note that the temporary files created with tempfile() will only be accessible for the duration of the Shiny app session and will be deleted when the session ends.

ShinyApps.io does support rendering RMarkdown documents, but it may not have native support for the quarto package. The quarto package is a relatively new package and it's not clear if it's fully supported by shinyapps.io.

If you want to use RMarkdown, you can convert the quarto document myquarto.qmd to Rmarkdown format and then use rmarkdown package to render the markdown document.

You could modify your server function to something like this:

Copy code

server <- function(input, output) {
  output$report <- downloadHandler(
    filename = "Reprod_ex.Rmd",
    content = function(file) {
      
      temp_file <- tempfile(fileext = ".Rmd")
      
      quarto::quarto_convert("myquarto.qmd", 
                            output_file = temp_file)
      
      rmarkdown::render(temp_file, output_format = "html_document", output_file = file)
    }
  )
}

Here, we're using quarto_convert() to convert the quarto document "myquarto.qmd" to Rmarkdown format and the resulting Rmarkdown file is being saved as temp_file. Then we're using rmarkdown::render() function to render the markdown document and the result is being saved as the file which we want to download.

It is worth noting that this way of converting quarto to Rmarkdown will lose some of the features of quarto and also the format may not be exactly the same as the quarto output.

Quarto is not an R package (even if it has an R package interface) it is an independent software and it seems it is not yet installed on shinyapps.io's servers as per this pendent GitHub issue. You can comment/up-vote there.

Thank you so much for your thorough reply!

Between the use of tempfile() and rendering it as a markdown file, I was finally able to get the app working on shinyapps.io! One note, there doesn't appear to be a quarto_convert() function in {quarto} and a search for that function didn't return any matching results. So I just had to make the appropriate conversions manually.

2 Likes

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.

If you have a query related to it or one of the replies, start a new topic and refer back with a link.