How to display dynamically generated PDF files inside shiny golem app - r

I'm generating a powerpoint presentation in R using officer, and then converting this to a PDF so a user can preview slides inside the shiny golem app. But after referencing this thread and this SO answer to a similar question I'm still not quite sure how to accomplish this. I am able to display external PDFs located in inst/app/www inside an iframe, but not sure how to do this for PDFs generated inside the app itself.
Here is the relevant code snippet from my app_server.R file:
output$preview <- renderUI({
# Creates rpptx object with one slide
preview_rpptx <- add_title_slide(x = NULL, title = input_list[["title"]])
# Creates www/ directory if it doesn't exist
if (!dir_exists("www")) dir_create("www")
# Generates .pptx file
pptx_file_path <- file_temp("preview", tmp_dir = "www", ext = ".pptx")
print(preview_rpptx, pptx_file_path)
# Converts .pptx to .pdf
pdf_file_path <- file_temp("preview", tmp_dir = "www", ext = ".pdf")
convert_to_pdf(path = pptx_file_path, pdf_file = pdf_file_path)
tags$iframe(style = "height:600px; width:100%", src = str_sub(pdf_file_path, 5))
}
Running the app, I get a "Not Found" error inside the iframe. But I can see that the PDF file was generated properly in the www/ directory.

Since I don't know how to do with a file as you ask, I would encode this file to a base64 string and set this string to the src attribute:
library(base64enc)
output$preview <- renderUI({
......
pdf_file_path <- "PATH/TO/PDF_FILE"
b64 <- dataURI(file = pdf_file_path, mime = "application/pdf")
tags$iframe(
style = "height: 600px; width: 100%;", src = b64
)
}

Related

How to create a download link in shiny for a local excel workbook (not dataframe) via downloadHandler

ref: How to download workbook via downloadHandler on Shiny?
** Workbook is already held in the app's directory**
Does anyone have experience with putting in a download link into a shiny app for an excel file held in the app's directory? I have an excel form that I need users to be able to download and use (it is specifically NOT a dataframe).
The following code worked for when I put in a powerpoint file in the downloadHandler function:
output$downloadinflationguidance <- downloadHandler(
filename = function() {
paste("www/inflation-guidance - ", Sys.Date(), '.pptx', sep='')
},
content = function(con) {
pptx <- read_pptx("www/inflation-guidance.pptx")
print(pptx, target = con)
}
)
But when I swap out the powerpoint stuff for the excel form (see below) it doesn't work. When I run the app and click on the download link, the user gets an error saying "file not found". The excel file is held locally on the app in a folder titled "www". Am I missing a trick here?
shinyUI(
downloadLink("dl_excel_calc", label = "Excel Version")
)
shinyServer(function(input, output, session) {
output$dl_excel_calc <- downloadHandler(
filename = function() {
paste0("indexation_tool_excel -", Sys.Date(), ".xlsx", sep='')
},
content = function(con) {
xlsx <- read_excel('indexation_tool_excel.xlsx')
print(xlsx, target = con)
}
)
}

get download dir from browser

I have this shinyapp where I want to download a file via a button. So I can do this by calling a downloadHandler like:
output$downloadData <- downloadHandler(
filename = "plot1.png",
content = function(file) {
plotPNG(func = function(){
plot(some.Data)
},
filename = file,
width = 3000,
height = 2000,
res = 300
)
}
)
Here the file is downloaded into the default download directory. What now if I want to download into another dir? In other words: Is there a way to determine the default download dir and to manipulate that?
The downloadHandler() should be able to handle this problem. The filename argument is, "A string of the filename, including extension, that the user's web browser should default to when downloading the file.." Therefore we can manipulate the default directory by defining the path in the filename.
server<-function(input,output){
output$downloadData <- downloadHandler(
# Sets filename the browser should default too
filename = function() {
paste(PATH_TO_DIR,"plot1",".png/xls/etc.",sep="")
}, # Closes Filename Function
# Creates Download file
content = function(file) {
plotPNG(func = function(){
plot(some.Data)
},
file = filename(),
width = 3000,
height = 2000,
res = 300
)
}
ui<-
downloadButton("downloadData", 'Download File')
)
This can be used in co-op with a download button, and the name of the file and path can be dynamically generated when the button is pushed by defining the path with variables. I think this may open a file browser, and I do not know if this is avoidable.
Also note that the file name, path, and content type will not appear to work in a local session (RStudio), they only work once deployed in the browser.

RShiny: Input multiple image files and put them into a table

I'm trying to work on a project in shiny to compare images uploaded by user and that saved in my amazon s3 server.
while downloading from s3, I am using this:
save_object(object=xyz ,bucket = "xyz", file = paste0("www/",xyz,".jpg"))
I'm taking input as:
fileInput("image","upload the image")
My dataframe is like this:
a$name<- xyz
a$server_image<- paste0("<img src=",'"',"xyz.jpg",'"'," ","height=",'"',"300",'"',"></img>")
a$uploaded_image<- paste0("<img src=",'"',input$image$datapath,'"'," ","height=",'"',"300",'"',"></img>")
I'm trying to get output like below.
output$output_table<-DT::renderDataTable({DT::datatable(a,escape = FALSE)})
In this case, the image downloaded from aws s3 into "www/" directory is correctly showed in the table, but there is problem with viewing uploaded image.
I also tried to use file.copy on input$image to copy it to a folder "www", but it also doesn't work when I deploy the app.
How can I view an image taken using fileInput and View without using renderImage?
I'm suspecting that your app renders <img src=... before the file is copied in www.
A solution is to convert the image in its base64 encoding and then to render the table including the image from its base64 string.
library(shiny)
library(DT)
ui <- shinyUI(
fluidPage(
fileInput("image", "upload image"),
DT::dataTableOutput("table")
)
)
server <- shinyServer(function(input, output) {
base64 <- eventReactive(input$image, {
base64enc::dataURI(file=input$image$datapath, mime=input$image$type)
})
output$table <- DT::renderDataTable({
req(input$image)
dat <- data.frame(image = sprintf('<img src=%s height="300"></img>', base64()))
datatable(dat, escape=FALSE)
})
})

Shiny SelectInput to generate filepath for renderImage

I have a series of ".jpg" files within my www folder of my script. I want to have renderImage to render the image with the filename that is named "dateplatform.jpg" based on the inputs (date, platform) of my UI. When I try the script below within my server.r file the app isn't displaying any image. Any thoughts?
ui (partial)
fluidRow(
column(width=12,
imageOutput("platformimage")
)
)
server (partial)
filename <- reactive ({
paste(input$date, input$platform, sep="")
})
output$platformimage <- reactive({
renderImage({
list(src = filename(),
width = 600,
height = 600)
},deleteFile = FALSE)
})
filename has to have at least the extension attached to it, and it's probably safer to normalizePath it:
filename <- reactive({
normalizePath(file.path(paste0(input$date, input$platform, '.jpg')))
})
If this fail, it's probably because of the server can't find the file. Check the path created by filename(), and fix inside file.path()
Hope this helps.

Shiny interactive document download button overwrites original R markdown

So I'm trying to write an html R markdown document with interactive shiny bits that allow the user to edit a graph and then download the results to a pdf. However, there is something catastrophically wrong with the way that I'm trying to do this because as soon as the html starts, it overwrites the original markdown file with the contents of the pdf - turning it into complete gibberish right in the editor.
I doubt that I've found a completely new way to fail at R but I haven't been able to find where anybody else has had this issue. Additionally, I've looked over the shiny reference material and I'm just going in circles at this point, so any help would be greatly appreciated.
I'm using Rstudio 1.0.44, rmarkdown 1.2 and shiny 0.14.2. A small (not)working example:
---
title: "Minimum Failing Example"
author: "wittyalias"
date: "December 5, 2016"
output: html_document
runtime: shiny
---
```{r echo = FALSE}
library(ggplot2)
today <- Sys.Date()
inputPanel(downloadButton("dnld", label = "Download pdf"))
renderPlot({
# Example code from http://www.cookbook-r.com/Graphs/Multiple_graphs_on_one_page_(ggplot2)/
p1 <<- ggplot(ChickWeight, aes(x=Time, y=weight, colour=Diet, group=Chick)) +
geom_line() +
ggtitle("Growth curve for individual chicks")
p1
})
reactive({
fname <- paste0("Chick Weight - ", today, ".pdf")
output$dnld <- downloadHandler(filename = fname,
content = makethepdf(file))
makethepdf <- function(fname) {
pdf(fname,
width = 14,
height = 8.5)
p1
dev.off()
}
})
```
EDIT: To be clear: I want the user to be able to download multiple pages of graphs, some of which will have different formatting. The user won't be downloading just a pdf version of the markdown document.
This happens because reasons I weren't able to identify makethepdf runs with the file = [name of the file]. Insert a print(fname) to see. The download handler isn't supposed to be inside an observer though. You need to have it outside on its own. I also failed to make pdf() dev.off() combination work for some reason so here's a working version below.
output$dnld = downloadHandler(filename = paste0("Chick Weight - ", today, ".pdf"),
content = function(file){
ggsave(file, plot = p1, width = 14, height = 8.5)
})
Use tempfile() and tempdir() to create a temporary file:
output$downloadReport = downloadHandler(
filename = function() {
normalizePath(tempfile("report_", fileext = ".docx"), winslash = "/")
},
content = function(file) {
out = rmarkdown::render("./report.Rmd",
output_file = file,
output_dir = tempdir(),
output_format = "pdf_document",
intermediates_dir = tempdir(),
envir = new.env(),
params = list( fontSize = 10)
)
})
I usually use a separate .Rmd template for my downloaded reports as the layout and text are usually similar but not identical to what works in an app.
I also find using parameters is a convenient way to pass input settings from my app to my report. See this RStudio post for details
Alright, so there are a number of problems with my code, but using some of the suggestions in the other answers I've been able to work it out.
The primary problem with this little document is that content in the downloadHandler is a function, but in my code I set content equal to the result of a function call. It looks like when the shiny app is first run it compiles content, thinking that it is a function, but actually ends up calling the function. It sends file as an arguement, which doesn't seem to exist except as a base function. Calling makethepdf with just file throws an error when I use it in the console, but for whatever reason in this app it just goes with the call, apparently with file = [name of the .Rmd] (just as OganM said).
To fix, change this:
output$dnld <- downloadHandler(filename = fname,
content = makethepdf(file))
to
output$dnld <- downloadHandler(filename = fname,
content = makethepdf)
To be clear: this code does not overwrite the .Rmd file if content calls makethepdf with any argument other than file. For instance, content = makethepdf(fnm)) causes the download button to display an object not found error and content = makethepdf(fname)) causes the download button to throw an attempt to apply non-function error when pressed.

Resources