Render images for interactive display from folder loaded with shinyDirChoose - r

The code below works if the user chooses several images. How can I implement this with shinyDirChoose, so that the user only chooses the folder where the images are located.
Problem: I don't know how to get the local datapath which is stored in the files() object. This path is needed for rendering the images.
Couldn't find any good answers in the web so far.
library(shiny)
ui <- shinyUI(fluidPage(
tags$script('
$(document).on("keydown", function (e) {
Shiny.onInputChange("rightCursor", [e.which,e.timeStamp]);
});
'),
sidebarLayout(
sidebarPanel(
fileInput(inputId = 'files',
label = 'Select an image or several images',
multiple = TRUE,
accept=c('image/png', 'image/jpeg'))
),
mainPanel(
uiOutput('images'),
tableOutput('files')
)
)
))
server <- shinyServer(function(input, output) {
rv <- reactiveValues(page = 1)
output$files <- renderTable(input$files)
files <- reactive({
files <- input$files
files$datapath <- gsub("\\\\", "/", files$datapath)
files
})
output$images <- renderUI({
if(is.null(input$files)) return(NULL)
imagename = paste0("image", rv$page)
image_output <- imageOutput(imagename)
})
observe({
if(is.null(input$files)) return(NULL)
for (i in 1:nrow(files()))
{
print(i)
local({
my_i <- i
imagename = paste0("image", my_i)
output[[imagename]] <-
renderImage({
list(src = files()$datapath[my_i], width = 400, height = 400,
alt = "Image failed to render")
}, deleteFile = FALSE)
})
}
})
navPage <- function(direction) {
rv$page <- rv$page + direction
}
observeEvent(input$rightCursor,{
navPage(1)
print(rv$page)
})
})
shinyApp(ui=ui,server=server)
The user only chooses the folder where the images are located, instead of one or several files.

Here is a way.
library(shiny)
library(shinyFiles)
ui <- fluidPage(
tags$head(
tags$script('
$(document).on("keydown", function (e) {
Shiny.onInputChange("rightCursor", [e.which,e.timeStamp]);
});
')
),
mainPanel(
shinyDirButton("dir", "Input directory", "Upload"),
verbatimTextOutput("dir", placeholder = TRUE),
uiOutput('images')
))
server <- function(input, output) {
shinyDirChoose(
input, "dir", roots = c(home = "~"), filetypes = c("png", "jpg")
)
folder <- reactiveVal()
output$dir <- renderText({
folder()
})
observeEvent(input$dir, {
if (!"path" %in% names(input$dir)) return()
home <- normalizePath("~")
folder(
file.path(
home,
paste(unlist(input$dir$path[-1]), collapse = .Platform$file.sep)
)
)
})
files <- eventReactive(folder(), {
list.files(folder(), full.names = TRUE)
})
page <- reactiveVal(1)
output$images <- renderUI({
req(files())
imagename = paste0("image", page())
imageOutput(imagename)
})
observeEvent(files(), {
for (i in 1:length(files()))
{
print(i)
local({
my_i <- i
imagename = paste0("image", my_i)
output[[imagename]] <-
renderImage({
list(src = files()[my_i], width = 400, height = 400,
alt = "Image failed to render")
}, deleteFile = FALSE)
})
}
})
observeEvent(input$rightCursor,{
page(page()+1)
})
}
# Run the application
shinyApp(ui = ui, server = server)

Related

How to create a button that will create a pdf file of a table

I currently have a table being generated and I would like the user to be able to create a pdf file when they click the download button.
I am currently getting an error where when I click the download button I get an html file that downloads the entire page of the app. I thought that using pdf(file) would work but it ignores the function.
Here is currently what I have.
library(shiny)
library(xlsx)
library(shinyWidgets)
population <- read.xlsx("population.xlsx", 1)
fieldsMandatory <- c("selectedCountry")
labelMandatory <- function(label) {
tagList(
label,
span("*", class = "mandatory_star")
)
}
appCSS <-
".mandatory_star {color: red;}"
ui <- fluidPage(
navbarPage(title = span("Spatial Tracking of COVID-19 using Mathematical Models", style = "color:#000000; font-weight:bold; font-size:15pt"),
tabPanel(title = "Model",
sidebarLayout(
sidebarPanel(
shinyjs::useShinyjs(),
shinyjs::inlineCSS(appCSS),
div(
id = "dashboard",
pickerInput(
inputId = "selectedCountry",
labelMandatory ("Country"),
choices = population$Country,
multiple = FALSE,
options = pickerOptions(
actionsBox = TRUE,
title = "Please select a country")
),
sliderInput(inputId = "agg",
label = "Aggregation Factor",
min = 0, max = 50, step = 5, value = 10),
actionButton("go","Run Simulation"),
)
),
mainPanel(
tabsetPanel(
tabPanel("Input Summary", verbatimTextOutput("summary"),
tableOutput("table"),
downloadButton(outputId = "downloadSummary", label = "Save Summary"))
)
)
)
)
)
)
server <- function(input, output, session){
observeEvent(input$resetAll, {
shinyjs::reset("dashboard")
})
values <- reactiveValues()
values$df <- data.frame(Variable = character(), Value = character())
observeEvent(input$go, {
row1 <- data.frame(Variable = "Country", Value = input$selectedCountry)
row2 <- data.frame(Variable = "Aggregation Factor", Value = input$agg)
values$df <- rbind(row1, row2)
})
output$table <- renderTable(values$df)
observe({
# check if all mandatory fields have a value
mandatoryFilled <-
vapply(fieldsMandatory,
function(x) {
!is.null(input[[x]]) && input[[x]] != ""
},
logical(1))
mandatoryFilled <- all(mandatoryFilled)
# enable/disable the submit button
shinyjs::toggleState(id = "go", condition = mandatoryFilled)
})
output$downloadSummary <- downloadHandler(
filename = function(file) {
paste('my-report.pdf', )
},
content = function(file) {
pdf(file)
}
)
}
shinyApp(ui,server)
Here's a minimal example:
library(shiny)
ui <- fluidPage(
downloadButton("savepdf", "Save pdf")
)
server <- function(input, output, session) {
output$savepdf <- downloadHandler(
filename = "test.pdf",
content = function(file) {
pdf(file)
plot(iris$Sepal.Length, iris$Sepal.Width)
dev.off()
}
)
}
shinyApp(ui, server)
Also see here.
Here is a minimal example with the package latexpdf. It will create the pdf table in the folder of the app.
library(shiny)
library(latexpdf)
dat <- head(iris, 5)
ui <- fluidPage(
br(),
actionButton("dwnld", "Create pdf"),
tableOutput("mytable")
)
server <- function(input, output, session){
output[["mytable"]] <- renderTable({
dat
})
observeEvent(input[["dwnld"]], {
as.pdf(dat)
})
}
shinyApp(ui, server)

How to insert multiple images into shiny after click of a button?

I created a shiny app which has two buttons as you can see in the following screenshot. I want to display 8 images which I have in this folder in the shiny app after I click the "Show Images" button. I tried using renderImages but couldn't get it to work.
Here is the code I have so far:
ui.R
fluidPage(
# Application title
titlePanel("For Fun!!"),
hr(),
sidebarLayout(
# Sidebar with a slider and selection inputs
sidebarPanel(
actionButton("update", "Print Text"),
hr(),
actionButton("test", "Show Images")
),
mainPanel(
verbatimTextOutput("plot"),
uiOutput("images")
)
)
)
server.r
server <- function(input, output) {
randomVals <- eventReactive(input$update, {
myString="Hello!"
myString
})
output$plot <- renderPrint({
myString=randomVals()
print(myString)
})
}
This is what I'm looking for as an output:
Thanks for your time
Try it like this.
library(shiny)
server <- shinyServer(function(input, output) {
output$files <- renderTable(input$files)
files <- reactive({
files <- input$files
files$datapath <- gsub("\\\\", "/", files$datapath)
files
})
output$images <- renderUI({
if(is.null(input$files)) return(NULL)
image_output_list <-
lapply(1:nrow(files()),
function(i)
{
imagename = paste0("image", i)
imageOutput(imagename)
})
do.call(tagList, image_output_list)
})
observe({
if(is.null(input$files)) return(NULL)
for (i in 1:nrow(files()))
{
print(i)
local({
my_i <- i
imagename = paste0("image", my_i)
print(imagename)
output[[imagename]] <-
renderImage({
list(src = files()$datapath[my_i],
alt = "Image failed to render")
}, deleteFile = FALSE)
})
}
})
})
ui <- shinyUI(fluidPage(
titlePanel("Uploading Files"),
sidebarLayout(
sidebarPanel(
fileInput(inputId = 'files',
label = 'Select an Image',
multiple = TRUE,
accept=c('image/png', 'image/jpeg'))
),
mainPanel(
tableOutput('files'),
uiOutput('images')
)
)
))
shinyApp(ui=ui,server=server)

Use download button with dataframe inside observe event

I have a application that allows user to upload the data, then an action button to trigger some calculation. I then have some progress bar to show user how long the process would take. Once the calculation finish, I would like to add a download button so user can download the calculation result.
I am not sure how to access the datatable created inside observe event function so I can use it in the downloadhandler function?
Here is my code:
server <- function(input, output) {
options(shiny.maxRequestSize=200*1024^2)
file_name <- reactive({
inFile <- input$file1
if (is.null(inFile))
return(NULL)
return (stringi::stri_extract_first(str = inFile$name, regex = ".*(?=\\.)"))
})
output$myFileName <- renderText({ paste("Claim data selected:",file_name()) })
mydata <- reactive({
inFile <- input$file1
if (is.null(inFile))
return(NULL)
tbl <- read.csv(inFile$datapath,sep=";")
return(tbl)
})
output$my_output_data <- DT::renderDataTable({
mydata() },
options = list(
lengthChange = FALSE,
autowidth = TRUE,
columnDefs = list(list(width = '70%', targets = 1)))
)
output$summary <- renderText({
dt.size <- nrow({mydata()})
paste("There are",dt.size,"records.", sep =" ")
})
observeEvent(input$goButton1,{
output$table1 <- DT::renderDataTable({
withProgress(message = 'Calculation in progress...',
value = 0, {function1({mydata()},progress=TRUE)})
})
output$table1 <- DT::renderDataTable(function1({mydata()}))
output$downloadData <- downloadHandler(
filename = function() {
paste("DLR result-", Sys.Date(), ".csv", sep="")
},
content = function(file) {
#fwrite("output$table 1 should be here", file)
})
})
}
The issue with the code you have given is that the fread function from the data.table library takes a data.frame or data.table argument. Here you have given it a DT javascript DataTable object. My code uses base R data.frames instead of data.table, but you should be able to adapt it accordingly.
library(shiny)
library(shinydashboard)
ui = dashboardPage(
dashboardHeader(title = "File Download"),
dashboardSidebar(),
dashboardBody(
fluidPage(
fluidRow(
box(width=12,
title = "UploadDownload",
fileInput("file1", label="File1 upload"),
downloadButton("downloadData", "Download")
)
),
fluidRow(
box(width=12,
title = "DataTable",
textOutput("myFileName"),
DT::dataTableOutput("my_output_data")
)
)
)
)
)
server = function(input, output) {
file_name = reactive({
req(input$file1)
return(gsub("\\..*$", "", input$file1$name))
})
output$myFileName = renderText({
paste("Claim data selected:",file_name())
})
mydata = reactive ({
req(input$file1)
tbl = read.csv(input$file1$datapath)
return(tbl)
})
mydata2 = reactive ({
tbl = mydata()
# a calculation that will take some time
withProgress(message="Adding another column", detail="this may take some time",
{
n = dim(tbl)[2]
tbl$newcolumn = NULL
for (i in 1:n) {
tbl$newcolumn[i] = sample.int(10,1)
incProgress(1/n)
Sys.sleep(5/n)
}
})
})
output$my_output_data = DT::renderDataTable(
mydata(),
options = list(
lengthChange=FALSE,
autowidth=TRUE,
columnDefs=list(list(width='70%', targets=1))
)
)
output$downloadData = downloadHandler(
filename = function() {
paste("DLR results-", Sys.Date(), ".csv", sep="")
},
content = function(file) {
write.csv(mydata2(), file)
}
)
}
shinyApp(ui, server)

shinyFiles folder selection: display the default folder

I need to display selected folder for Shiny users, and I asked here how to do this (Display selected folder path in Shiny). It works but now I can't figure out how to show the default folder (for example, current directory) before the selection was made.
library(shiny)
library(shinyFiles)
ui <- fluidPage( # Application title
mainPanel(
shinyDirButton("dir", "Input directory", "Upload"),
verbatimTextOutput("dir", placeholder = TRUE)
))
server <- function(input, output) {
shinyDirChoose(
input,
'dir',
roots = c(home = '~'),
filetypes = c('', 'txt', 'bigWig', "tsv", "csv", "bw")
)
dir <- reactive(input$dir)
output$dir <- renderText({
parseDirPath(c(home = '~'), dir())
})
## change smth here... if output$dir is null, display getwd() but it doesn't work
observeEvent(ignoreNULL = TRUE,
eventExpr = {
input$dir
},
handlerExpr = {
home <- normalizePath("~")
datapath <<-
file.path(home, paste(unlist(dir()$path[-1]), collapse = .Platform$file.sep))
})
}
# Run the application
shinyApp(ui = ui, server = server)
I can think only of a conditional panel displaying some text if the folder wasn't selected. But I guess there should a better way to do this. Thank you!
Concerning "beyond" displaying you could save the datapath variable in a reactiveValue and set the working directory as the default:
global <- reactiveValues(datapath = getwd())
And the app:
library(shiny)
library(shinyFiles)
ui <- fluidPage( # Application title
mainPanel(
shinyDirButton("dir", "Input directory", "Upload"),
verbatimTextOutput("dir", placeholder = TRUE)
))
server <- function(input, output) {
shinyDirChoose(
input,
'dir',
roots = c(home = '~'),
filetypes = c('', 'txt', 'bigWig', "tsv", "csv", "bw")
)
global <- reactiveValues(datapath = getwd())
dir <- reactive(input$dir)
output$dir <- renderText({
global$datapath
})
observeEvent(ignoreNULL = TRUE,
eventExpr = {
input$dir
},
handlerExpr = {
home <- normalizePath("~")
global$datapath <-
file.path(home, paste(unlist(dir()$path[-1]), collapse = .Platform$file.sep))
})
}
# Run the application
shinyApp(ui = ui, server = server)

Dynamically display images from upload in Shiny UI

This is pretty much the same question as presented here:
dynamically add plots to web page using shiny
But instead of producing a variable number of plots (which I've successfully done), I am trying to upload a selection of images into the application and display them on the user interface. Using the same approach as described in the question above, I've produced my application with the code below. But only the first image is rendering in the UI.
What obvious thing have I missed today?
R 3.2.2 (Windows 7)
shiny 0.12.2
server.R
library(shiny)
shinyServer(function(input, output) {
output$files <- renderTable(input$files)
files <- reactive({
files <- input$files
files$datapath <- gsub("\\\\", "/", files$datapath)
files
})
output$images <- renderUI({
image_output_list <-
lapply(seq_along(nrow(files())),
function(i)
{
imagename = paste0("image", i)
imageOutput(imagename)
})
do.call(tagList, image_output_list)
})
observe({
for (i in seq_along(nrow(files())))
{
local({
my_i <- i
imagename = paste0("image", my_i)
output[[imagename]] <-
renderImage({
list(src = files()$datapath[my_i],
alt = "Image failed to render")
}, deleteFile = FALSE)
})
}
})
})
ui.R
library(shiny)
shinyUI(fluidPage(
titlePanel("Uploading Files"),
sidebarLayout(
sidebarPanel(
fileInput(inputId = 'files',
label = 'Select an Image',
multiple = TRUE,
accept=c('image/png', 'image/jpeg'))
),
mainPanel(
tableOutput('files'),
uiOutput('images')
)
)
))
Your so close! Try this:
library(shiny)
server <- shinyServer(function(input, output) {
output$files <- renderTable(input$files)
files <- reactive({
files <- input$files
files$datapath <- gsub("\\\\", "/", files$datapath)
files
})
output$images <- renderUI({
if(is.null(input$files)) return(NULL)
image_output_list <-
lapply(1:nrow(files()),
function(i)
{
imagename = paste0("image", i)
imageOutput(imagename)
})
do.call(tagList, image_output_list)
})
observe({
if(is.null(input$files)) return(NULL)
for (i in 1:nrow(files()))
{
print(i)
local({
my_i <- i
imagename = paste0("image", my_i)
print(imagename)
output[[imagename]] <-
renderImage({
list(src = files()$datapath[my_i],
alt = "Image failed to render")
}, deleteFile = FALSE)
})
}
})
})
ui <- shinyUI(fluidPage(
titlePanel("Uploading Files"),
sidebarLayout(
sidebarPanel(
fileInput(inputId = 'files',
label = 'Select an Image',
multiple = TRUE,
accept=c('image/png', 'image/jpeg'))
),
mainPanel(
tableOutput('files'),
uiOutput('images')
)
)
))
shinyApp(ui=ui,server=server)
I changed seq_along to just 1:nrow(files()) but seq_len(nrow(files())) or seq_along(t(files())) would work to.

Resources