Update checkboxGroupInput() choices after file upload - r

I have a simple shiny app below. In this app I want the user to be able to upload his own csv and then automatically this will be added as a choice in the checkbox group below the other dataset "D.B" (which I create in my original app).
#ui.r
ui <- fluidPage(
# App title ----
titlePanel("Uploading Files"),
# Sidebar layout with input and output definitions ----
sidebarLayout(
# Sidebar panel for inputs ----
sidebarPanel(
# Input: Select a file ----
fileInput("file1", "Choose CSV File",
multiple = FALSE,
accept = c("text/csv",
"text/comma-separated-values,text/plain",
".csv")),
uiOutput("checkbox"),
textInput("filename","Set Filename")
),
# Main panel for displaying outputs ----
mainPanel(
# Output: Data file ----
tableOutput("contents")
)
)
)
#server.r
server <- function(input, output) {
output$contents <- renderTable({
req(input$file1)
df <- read.csv(input$file1$datapath)
})
D.B <- reactive({
#some code that creates the dataset D.B.
})
output$checkbox<-renderUI({
checkboxGroupInput("datasetSelector","Specify the datasets to compare:", choices = c("D.B")
)
})
}

You could use a reactive value to store choices then add a choice everytime a file is uploaded. Use an observer to watch for file uploads (I also used the library rlist which gives me the append method).
library(rlist)
#ui.r
ui <- fluidPage(
# App title ----
titlePanel("Uploading Files"),
# Sidebar layout with input and output definitions ----
sidebarLayout(
# Sidebar panel for inputs ----
sidebarPanel(
# Input: Select a file ----
fileInput("file1", "Choose CSV File",
multiple = FALSE,
accept = c("text/csv",
"text/comma-separated-values,text/plain",
".csv")),
uiOutput("checkbox"),
textInput("filename","Set Filename")
),
# Main panel for displaying outputs ----
mainPanel(
# Output: Data file ----
tableOutput("contents")
)
)
)
#server.r
#fileOptions = list("D.B.")
server <- function(input, output, session) {
output$contents <- renderTable({
req(input$file1)
df <- read.csv(input$file1$datapath)
head(df)
})
fileOptions <- reactiveValues(currentOptions=c("D.B."))
observeEvent(input$file1, {
fileOptions$currentOptions = list.append(fileOptions$currentOptions, input$file1$datapath)
})
D.B <- reactive({
#some code that creates the dataset D.B.
})
output$checkbox<-renderUI({
checkboxGroupInput("datasetSelector","Specify the datasets to compare:", choices = fileOptions$currentOptions
)
})
}

Related

R Shiny allow user to select one or multiple datasets to download

I am new to R shiny and I hope someone can please guide me in the right direction.
I want the user to be able to select one or multiple datasets to download.
Code works when I put the multiple=F in selectInput but when I change it to TRUE, I get the error below:
"Warning: Error in switch: EXPR must be a length 1 vector"
Any help will be greatly appreciated as I am stuck on this for days.
Thank you
library(shiny)
library(openxlsx)
# Define UI for data download app ----
ui <- fluidPage(
# App title ----
titlePanel("Downloading Data"),
# Sidebar layout with input and output definitions ----
sidebarLayout(
# Sidebar panel for inputs ----
sidebarPanel(
# Input: Choose dataset ----
selectInput("dataset", "Choose a dataset:",
choices = c("rock", "pressure", "cars"), multiple=T),
# Button
downloadButton("downloadData", "Download")
),
# Main panel for displaying outputs ----
mainPanel(
tableOutput("table")
)
)
)
# Define server logic to display and download selected file ----
server <- function(input, output) {
# Reactive value for selected dataset ----
datasetInput <- reactive({
switch(input$dataset,
"rock" = rock,
"pressure" = pressure,
"cars" = cars)
})
# Table of selected dataset ----
output$table <- renderTable({
datasetInput()
})
# Downloadable xlsx of selected dataset ----
output$downloadData <- downloadHandler(
filename = function() {
"selected.xlsx"
},
content = function(filename) {
write.xlsx(datasetInput(), file = filename, rowNames = FALSE)
}
)
}
# Create Shiny app ----
shinyApp(ui, server)
In order to display several datasets, you can create a module (it is like creating a smaller shiny app inside your shiny app that you can call with parameters, just like a function). Here I created a module to display a table, with a dataframe as parameter.
For the download, I followed the link I gave you previously.
library(shiny)
#Using module
mod_export_table_ui <- function(id){
ns <- NS(id)
tagList(
tableOutput(ns("table_export"))
)
}
mod_export_table_server <- function(input, output, session, df_export){
ns <- session$ns
output$table_export <- renderTable({
df_export
})
}
# Define UI for data download app ----
ui <- fluidPage(
# App title ----
titlePanel("Downloading Data"),
# Sidebar layout with input and output definitions ----
sidebarLayout(
# Sidebar panel for inputs ----
sidebarPanel(
# Input: Choose dataset ----
selectInput("dataset", "Choose a dataset:",
choices = c("rock", "pressure", "cars"), multiple=T),
# Button
downloadButton("downloadData", "Download")
),
# Main panel for displaying outputs ----
mainPanel(
uiOutput("tables")
)
)
)
# Define server logic to display and download selected file ----
server <- function(input, output, session) {
rv <- reactiveValues()
#List of datasets
observeEvent(input$dataset, {
req(input$dataset)
rv$lst_datasets <- lapply(
1:length(input$dataset),
function(i) {
head(eval(parse(text =input$dataset[i])))
}
)
})
# Module UIs
output$tables <- renderUI({
req(rv$lst_datasets)
lapply(
1:length(rv$lst_datasets),
function(i) {
mod_export_table_ui(id = paste0("table", i))
}
)
})
# Module Servers
observeEvent(rv$lst_datasets, {
req(rv$lst_datasets)
lapply(
1:length(rv$lst_datasets),
function(i) {
callModule(
module = mod_export_table_server,
session = session,
id = paste0("table", i),
df_export = rv$lst_datasets[[i]]
)
}
)
})
output$downloadData <-downloadHandler(
filename = "Downloads.zip",
content = function(file){
withProgress(message = "Writing Files to Disk. Please wait...", {
temp <- setwd(tempdir())
on.exit(setwd(temp))
files <- c()
for(i in 1:length(rv$lst_datasets)){
writexl::write_xlsx(rv$lst_datasets[[i]],
path = paste0("dataset",i, ".xlsx")
)
files <- c(files, paste0("dataset",i, ".xlsx"))
}
zip(zipfile = file, files = files)
})
}
)
}
# Create Shiny app ----
shinyApp(ui, server)

Shiny dashboard with two sidepanels and a plot

I'm trying to get a Rshiny code to display two panels on the left hand side (one for file input and the other to action plot) and a plot on the right hand side, but I got the following error:
Error in match.arg(position) : 'arg' must be NULL or a character vector
Here is the code:
library(shiny)
library(pheatmap)
# Define UI for dataset viewer app ----
ui <- fluidPage(
# App title ----
titlePanel("plot"),
# Sidebar layout with input and output definitions ----
sidebarLayout(
# Sidebar panel for inputs ----
sidebarPanel("Sidebar panel",
# Input: Selector for choosing dataset ----
fileInput("file1", "Choose CSV File",
accept = c(
"text/csv",
"text/comma-separated-values,text/plain",
".csv")
),
tags$hr(),
checkboxInput("header", "Header", TRUE)
),
# tags$hr(),
sidebarPanel('get heatmap',
actionButton('getHmap', 'get heatmap')
),
# Main panel for displaying outputs ----
mainPanel("Plot",
#column(6,
plotOutput("themap"),
tableOutput("table.output"))
#)
)
)
server = function(input, output, session) {
a <- reactive({
inFile <- input$file1
if (is.null(inFile))
return(NULL)
tbl <- read.csv(inFile$datapath, header=input$header) #, sep=input$sep, dec = input$dec)
return(tbl)
})
output$table.output <- renderTable({
a()
})
plotdata <- eventReactive(input$getHmap, {
a <- as.matrix(a()[-1])
row.names(a) <- a()$ID
a[is.na(a)] <- 0
a
})
output$themap = renderPlot({
pheatmap(plotdata())
})
}
shinyApp(ui, server)
I'm new to Rshiny. Can someone help me find the cause of this problem please?

How to process a file being uploaded and renamed in a shiny application

I have a simple shiny app below. In this app I want the user to be able to upload his own csv and then automatically this will be added as a choice in the checkbox group below the other dataset "D.B" (which I create in my original app). Then when the user chooses a file it will be displayed as a table.
Here I have managed to rename the uploaded file. However I can not then connect the renamed table with renderTable() while keeping the "changing name" ability.
# Define UI for data upload app ----
ui <- fluidPage(
# App title ----
titlePanel("Uploading Files"),
# Sidebar layout with input and output definitions ----
sidebarLayout(
# Sidebar panel for inputs ----
sidebarPanel(
# Input: Select a file ----
fileInput("file1", "Choose CSV File",
multiple = FALSE,
accept = c("text/csv",
"text/comma-separated-values,text/plain",
".csv")),
checkboxGroupInput("datasetSelector","Data Files", choices=c("D.B")),
textInput("filename","Set Filename",value = "Set Name")
),
# Main panel for displaying outputs ----
mainPanel(
# Output: Data file ----
tableOutput("contents")
)
)
)
#server.r
server <- function(input, output, session) {
observeEvent(input$filename, {
req(input$file1)
Name<-input$filename
updateCheckboxGroupInput(session,"datasetSelector", choices=c("D.B",Name))
})
observeEvent(input$file1, {
Data<-input$file1$datapath
Name<-input$filename
New <- read.csv(Data)
updateCheckboxGroupInput(session,"datasetSelector",
choices=c("D.B",input$file1$name))
})
D.B <- reactive({
if("D.B"%in% input$datasetSelector){
x <- read.csv("something.csv", stringsAsFactors = F)
}
})
output$contents <- renderTable({
New
})
}
Here is one solution.
This solution uses the ability of shiny inputs to take named lists. In a named list the label is the display name and the value is what is returned. E.g. c("a" = 1, "b" = 2) will display the labels a and b in the UI, but will return values of 1 and 2 in the server.
Because you want one of your labels to come from an input, it is necessary to build the ordered list in two parts. First, the values and then the labels. E.g. mylist = c(1,2) sets up the values then names(mylist) = c("a","b") assigns the labels.
Here is the code I had working:
library(shiny)
# Define UI for data upload app ----
ui <- fluidPage(
# App title ----
titlePanel("Uploading Files"),
# Sidebar layout with input and output definitions ----
sidebarLayout(
# Sidebar panel for inputs ----
sidebarPanel(
# Input: Select a file ----
fileInput("file1", "Choose CSV File",
multiple = FALSE,
accept = c("text/csv",
"text/comma-separated-values,text/plain",
".csv")),
checkboxGroupInput("datasetSelector","Data Files", choices=c("D.B" = "original")),
textInput("filename","Set Filename",value = "Set Name")
),
# Main panel for displaying outputs ----
mainPanel(
# Output: Data file ----
tableOutput("contents")
)
)
)
#server.r
server <- function(input, output, session) {
observeEvent(input$filename, {
req(input$file1)
Name<-input$filename
# make list
choices = c("original", "loaded")
# assign labels to list
names(choices) = c("D.B", Name)
updateCheckboxGroupInput(session,"datasetSelector", choices=choices)
})
observeEvent(input$file1, {
Data<-input$file1$datapath
Name<-input$filename
New <- read.csv(Data)
# make list
choices = c("original", "loaded")
# assign labels to list
names(choices) = c("D.B", Name)
updateCheckboxGroupInput(session,"datasetSelector", choices=choices)
})
D.B <- reactive({
if("D.B"%in% input$datasetSelector){
x <- read.csv("something.csv", stringsAsFactors = F)
}
})
output_table = reactive({
if("original" %in% input$datasetSelector)
return(D.B())
if("loaded" %in% input$datasetSelector)
return(read.csv(input$file1$datapath))
})
output$contents <- renderTable({
output_table()
})
}
# Run the app ----
shinyApp(ui = ui, server = server)

Save As functionality in shiny app download

I am building a shiny app where I am trying to put a download button which will ask user to choose name while saving the file. In below example, when user clicks on download button, it automatically downloads the file without asking user for the filename.
ui <- fluidPage(
# App title ----
titlePanel("Downloading Data"),
# Sidebar layout with input and output definitions ----
sidebarLayout(
# Sidebar panel for inputs ----
sidebarPanel(
# Input: Choose dataset ----
selectInput("dataset", "Choose a dataset:",
choices = c("rock", "pressure", "cars")),
# Button
downloadButton("downloadData", "Download")
),
# Main panel for displaying outputs ----
mainPanel(
tableOutput("table")
)
)
)
server
server <- function(input, output) {
# Reactive value for selected dataset ----
datasetInput <- reactive({
switch(input$dataset,
"rock" = rock,
"pressure" = pressure,
"cars" = cars)
})
# Table of selected dataset ----
output$table <- renderTable({
datasetInput()
})
# Downloadable csv of selected dataset ----
output$downloadData <- downloadHandler(
filename = function() {
paste(input$dataset, ".csv", sep = "")
},
content = function(file) {
write.csv(datasetInput(), file, row.names = FALSE)
}
)
}
shinyApp(ui,server)
Let me know if anyone has some idea.
A simplistic way to take in file name. It does need another TextInput
ui <- fluidPage(
# App title ----
titlePanel("Downloading Data"),
# Sidebar layout with input and output definitions ----
sidebarLayout(
# Sidebar panel for inputs ----
sidebarPanel(
# Input: Choose dataset ----
selectInput("dataset", "Choose a dataset:",
choices = c("rock", "pressure", "cars")),
textInput("file_name_input", "enter file name",placeholder = "Default"),
# Button
downloadButton("downloadData", "Download")
),
# Main panel for displaying outputs ----
mainPanel(
tableOutput("table")
)
)
)
server
server <- function(input, output) {
# Reactive value for selected dataset ----
datasetInput <- reactive({
switch(input$dataset,
"rock" = rock,
"pressure" = pressure,
"cars" = cars)
})
# Table of selected dataset ----
output$table <- renderTable({
datasetInput()
})
# Downloadable csv of selected dataset ----
output$downloadData <- downloadHandler(
filename = function() {
paste(input$file_name_input, ".csv", sep = "")
},
content = function(file) {
write.csv(datasetInput(), file, row.names = FALSE)
}
)
}
shinyApp(ui,server)

using drop down bottom in shiny to loaed files from a folder

I am using shiny to upload different data files from a certain folder and plot a histogram based on a certain column. The name of each file looks like "30092017ARB.csv" (date + ARB.csv).
The code loops over all file names in the data-folder and print the name of files in a drop-down bottom. After selecting the name of file it should be uploaded and plot a histogram of the mw-column (the name of column is "mw). My GUI looks as follows:
library("shiny")
dataset <- list.files("C:/R_myfirstT/data", pattern=".*.csv$")
# Define UI for dataset viewer app ----
ui <- fluidPage(
# App title ----
titlePanel("Data plot"),
# Sidebar layout with input and output definitions ----
sidebarLayout(
# Sidebar panel for inputs ----
sidebarPanel(
# Input: Selector for choosing dataset ----
selectInput(inputId = "date",
label = "Choose a date:",
choices = dataset)
),
# Main panel for displaying outputs ----
mainPanel(
plotOutput("plot")
)
)
)
and the server
# Define server ----
dataset <- list.files("C:/R_myfirstT/data", pattern=".*.csv$")
dat.name<-paste("C:/R_myfirstT/data/",dataset,sep = "")
server <- function(input, output) {
datasetInput <- reactive({
switch(input$dataset,
for (i in 1:length(dataset)){
toString(dataset[i])=read.csv(file=dat.name[i], header=TRUE, sep=";")
}
)
output$plot <- renderPlot({
hist(dataset.mw, breaks = 40)
})
})
}
My problem is: I do not get any histogram! I get just the which is nice however, not entirely my goal!
Any idea what could be the reason?
Something like this works:
ui.R
library("shiny")
# Define UI for dataset viewer app ----
ui <- fluidPage(
# App title ----
titlePanel("Data plot"),
# Sidebar layout with input and output definitions ----
sidebarLayout(
# Sidebar panel for inputs ----
sidebarPanel(
# Input: Selector for choosing dataset ----
selectInput(inputId = 'date',
label = 'Choose a date:',
choices = list.files(path = "./data",
full.names = FALSE,
recursive = FALSE))
),
# Main panel for displaying outputs ----
mainPanel(
plotOutput("plot")
)
)
)
server.R
# Define server ----
server <- function(input, output) {
dataset <- reactive({
infile <- input$date
if (is.null(infile)){
return(NULL)
}
read.csv(paste0('./data/',infile))
})
output$plot <- renderPlot({
x <- dataset()[,1]
hist(x, breaks = 40)
})
}

Resources