29

I'm still new to r and shiny, and i'm stumped with what should otherwise be simple logic. I am trying to display pdf files in imageOutput widgets but with no luck. Could someone steer me in the right direction?

sample ui.R

shinyUI(pageWithSidebar(
mainPanel(
  selectInput("sel_ed",
              label = "View outputs for Ecodistrict:", 
              choices = c(244,245,247,249), 
              selected = NULL,
              multiple = FALSE),

  imageOutput("imp_pdf",width="500px",height="500px")
))

sample server.R

shinyServer(function(input, output, session) {

importance <- function(inputSpecies){
img_dir <- pdf(paste(inputSpecies,"\\models\\MATL\\MATRF_Importance",sep=""))
}

output$imp_pdf <- renderImage({importance(input$sel_ed)}) 

})

Most of the errors i get have to do with expected character vector arguments, or atomic vectors. I know that shiny is more or less designed to render AND display images or plots but there has to be a way to display pdf's that are already on a local drive..

Jeramy
  • 389
  • 1
  • 4
  • 7
  • may not be related, but you can use `/` for paths instead of \\ even in windows – beroe Oct 19 '13 at 19:16
  • I think there is no ready made component at the moment. But of course you can display pdf in a webpage. If it can be done in a webapge then shiny can be adapted to do it. See https://github.com/mozilla/pdf.js – xiaodai Oct 20 '13 at 12:42

3 Answers3

36

To embed a PDF viewer (the default PDF viewer of your web browser, pdf.js on mozilla for example) in your Shiny ui, you can use an iframe which the src will be the path to your PDF.

Here is 2 differents ways to include an iframe in your interface :

in the Ui you can directly add an iframe tag with an absolute src attribute as bellow :

tags$iframe(style="height:600px; width:100%", src="http://localhost/ressources/pdf/R-Intro.pdf"))

Or get an URL from the ui in the server , write the iframe tag with the input URL and return the HTML code in a htmlOutput in the ui :

Ui :
textInput("pdfurl", "PDF URL")
htmlOutput('pdfviewer')

Server :

output$pdfviewer <- renderText({
    return(paste('<iframe style="height:600px; width:100%" src="', input$pdfurl, '"></iframe>', sep = ""))
})

Note that when pages are loaded with a HTTP(S) protocol (the case of the Shiny app) for security reasons you can't framed locals files with their "file:" URLs. If you want to display locals pdf you should access to them with a http(s): URL, so you have to save them in your www directory (a local web server) and access to files with their http(s): URLs (the URL will be something like http://localhost/.../mypdf.pdf) as in the second iframe of my example. (Then you can't use a fileInput directly, you have to format it)

Ui.R :

library(shiny)

row <- function(...) {
  tags$div(class="row", ...)
}

col <- function(width, ...) {
  tags$div(class=paste0("span", width), ...)
}

shinyUI(bootstrapPage(

  headerPanel("PDF VIEWER"),

  mainPanel(

    tags$div(
      class = "container",

      row(
        col(3, textInput("pdfurl", "PDF URL"))
      ),
      row(
        col(6, htmlOutput('pdfviewer')),
        col(6, tags$iframe(style="height:600px; width:100%", src="http://localhost/ressources/pdf/R-Intro.pdf"))
      )
    )
  )
))

Server.R :

shinyServer(function(input, output, session) {

  output$pdfviewer <- renderText({
      return(paste('<iframe style="height:600px; width:100%" src="', input$pdfurl, '"></iframe>', sep = ""))
  })

})

The web pages with the PDF viewers :

enter image description here

Hope this help.

Fabian N.
  • 3,807
  • 2
  • 23
  • 46
Julien Navarre
  • 7,653
  • 3
  • 42
  • 69
  • 7
    An FYI: in my experience using this method, you need to open the Shiny app in a browser to actually see the PDF. It doesn't display in the RStudio window. – moman822 May 02 '17 at 19:39
  • Is there anyway to secure the `www` folder? or to preview PDFs without use of the `www` I want to be able to preview pictures/pdfs in an `iframe` type manner, without producing an unsecure URL link that anyone can potentially access – road_to_quantdom Jun 24 '19 at 19:31
9

Create a folder called www in the original directory that contains your server.R and ui.R scripts. Place the PDF in the www/ folder, then use something like the code below:

In server.R:

shinyServer(function(input, output) {

  observeEvent(input$generate, {
    output$pdfview <- renderUI({
      tags$iframe(style="height:600px; width:100%", src="foo.pdf")
    })
  })
})

In ui.R:

shinyUI(fluidPage(

  titlePanel("Display a PDF"),

  sidebarLayout(
    sidebarPanel(
      actionButton("generate", "Generate PDF")
    ),

    mainPanel(
      uiOutput("pdfview")
    )
  )
))
Kris
  • 351
  • 3
  • 5
  • Simple answer that works, +1! One comment though: if the file is static (does not change based on user input), you can add the `tags$iframe()` directly in the UI part, no need to use `renderUI()` and `uiOutput()`. – Antoine Jun 21 '21 at 17:53
4

Additional to Fabian N.'s answer.

There are two important things:

  1. Make sure you create a R Shiny Web Application from Rstudio. Make sure you run as "Run App". Otherwise, files in "www" folder can not be accessed!

enter image description here

  1. Make sure you create a "www" folder in Web Application directory.
Josiah Yoder
  • 3,321
  • 4
  • 40
  • 58
  • You can also run it from the command line, e.g., `runApp('maintask',host = "0.0.0.0")` if you wanted it to be externally visible. And I believe any R Shiny application is an R Shiny Web Application. – Josiah Yoder Jun 14 '19 at 19:07