R Shiny- Dynamic FileInput label - r

I am building an app where I need to have option for single file upload vs dual file upload. I have achieved single vs dual file upload using conditionalpanel, but I am not being able to change the FileInput label.
This is what I need-
1) When user clicks on single file. There should be only one FileInput with label "Choose Consolidated file"
2) When user clicks on separate files. There should be 2 FileInputs with label "Choose test file" and "Choose control file"
Below is a working code
library(shiny)
ui<-shinyUI(fluidPage(
sidebarLayout(
sidebarPanel(
radioButtons("p", "separate input files or consolidated?",
list("Single file"='a', "Separate files"='b'))
),
mainPanel(
fileInput("file1","Choose first file",
accept = c(
"text/csv",
"text/comma-separated-values,text/plain",
".csv","sas7bdat")
),
conditionalPanel(
condition = "output.dual",
fileInput("file2", "Choose second file",
accept = c(
"text/csv",
"text/comma-separated-values,text/plain",
".csv","sas7bdat")
)
),
conditionalPanel(
condition = "output.dual",
checkboxInput('headercheckbox',
"Files have different headers?",
value = FALSE
)
)### bracket close of conditional panel
)
)
))
server<-shinyServer(function(input, output) {
output$dual <- reactive({ input$p == 'b' })
outputOptions(output, 'dual', suspendWhenHidden = FALSE)
})
shinyApp(ui,server)
Let me know if anyone can help?

I recommend using uiOutput and renderUI for this. If you want to know more about these functions the shiny reference materials are pretty good. https://shiny.rstudio.com/reference/shiny/latest/renderUI.html
ui<-shinyUI(
fluidPage(
sidebarLayout(
sidebarPanel(
radioButtons("p", "separate input files or consolidated?",
list("Single file"='a', "Separate files"='b'))
),
mainPanel(
uiOutput('file_area_1'),
uiOutput('file_area_2'),
uiOutput('diff_headers')
)### bracket close of conditional panel
)
)
)
server<-shinyServer(function(input, output) {
output$dual <- reactive({ input$p == 'b' })
outputOptions(output, 'dual', suspendWhenHidden = FALSE)
output$file_area_1 <- renderUI({
message = 'Choose consolidated file'
if(input$p == 'b'){
message = 'Choose test file'
}else{
mesage = ''
}
fileInput("file1",message,
accept = c(
"text/csv",
"text/comma-separated-values,text/plain",
".csv","sas7bdat")
)
})
output$file_area_2 <- renderUI({
if(input$p == 'b'){
fileInput("file2","Choose control file",
accept = c(
"text/csv",
"text/comma-separated-values,text/plain",
".csv","sas7bdat")
)
}
})
output$diff_headers <- renderUI({
if(input$p == 'b'){
checkboxInput('headercheckbox',
"Files have different headers?",
value = FALSE
)
}
})
})
shinyApp(ui,server)

I think if you allow the panels to define the condition based on the user input, you can get the functionality you want:
ui<-shinyUI(fluidPage(
sidebarLayout(
sidebarPanel(
radioButtons("p", "separate input files or consolidated?",
list("Single file"='a', "Separate files"='b'))
),
mainPanel(
conditionalPanel(
condition ="output.dual == 'a' " ,
fileInput("file1","Choose Consolodated file",
accept = c(
"text/csv",
"text/comma-separated-values,text/plain",
".csv","sas7bdat")
)
),
conditionalPanel(
condition ="output.dual == 'b' " ,
fileInput("file1","Choose Test file",
accept = c(
"text/csv",
"text/comma-separated-values,text/plain",
".csv","sas7bdat")
)
),
conditionalPanel(
condition = "output.dual == 'b'",
fileInput("file2", "Choose control file",
accept = c(
"text/csv",
"text/comma-separated-values,text/plain",
".csv","sas7bdat")
)
),
conditionalPanel(
condition = "output.dual == 'b'",
checkboxInput('headercheckbox',
"Files have different headers?",
value = FALSE
)
)### bracket close of conditional panel
)
)
))
server<-shinyServer(function(input, output) {
output$dual <- reactive({ input$p })
outputOptions(output, 'dual', suspendWhenHidden = FALSE)
})
shinyApp(ui,server)

Related

how to select options for the R scripts that will execute in R Shiny

I'm making a R shiny app, and I've already got two separate R scripts (Domain1.R and Domain2.R) that I'm putting into R shiny.
These R scripts extract tables from PDF files (it tested and works well). I've added options for listing the domains "Domain1" and "Domain2," as well as an Extract Button. The problem is that after selecting the options and clicking the extract button, Both R scripts are executed. When the relevant option is chosen, I want either one R script to run.
The domain selection(choices: domain 1 and domain 2 should call the corresponding R scripts, It should run the code "Domain1" if I pick domain1 from the choices, however, it now performs both the "Domain1" and "Domain2" R scripts. How can this problem be resolved?
I'm new to the R shiny, and I'd appreciate it if anyone could assist me.
Sharing the entire code below:
library(shiny)
options(shiny.maxRequestSize=30*1024^2)
shinyApp(
ui = tagList(
navbarPage(
theme = "spacelab",
"Dataset",
tabPanel("Study report extracting",
sidebarPanel(
fileInput("file1", "Select datasets:",
accept = c(
"text/csv",
"text/comma-separated-values,text/plain",
".csv")
),
tags$hr(),
checkboxInput("header", "Header", TRUE),
textInput("txt", "Study info:", "Study name read"),
sliderInput("slider", "Tables to read:", 1, 100, 30),
tags$h5("Prepare extraction"),
actionButton("dataset", "Extract", class = "btn-primary")
),
mainPanel(
tableOutput("contents"),
tabsetPanel(
tabPanel("PDF File select",
h4("Domains"),
tableOutput("table"),
h3("Extracting..."),
selectInput("pdfExtract1", "Pick a PDF", choices = c('Domain1')),
tableOutput("preview"),
actionButton("pdfExtract", "Extract", class = "btn-primary"),
selectInput("pdfExtract1", "Pick a PDF", choices = c('Domain2')),
tableOutput("preview"),
actionButton("pdfExtract", "Extract", class = "btn-primary")
),
tabPanel("Raw data", "TBD"),
tabPanel("calculation", "TBD")
)
)
), # end of first tabpanel
tabPanel("Calculation",
sidebarPanel(
fileInput("file2", "Select datasets:",
accept = c(
"text/csv",
"text/comma-separated-values,text/plain",
".csv")
),
tags$hr(),
checkboxInput("header", "Header", TRUE),
textInput("txt2", "Study info:", "Study name read"),
sliderInput("slider", "Tables to read:", 1, 100, 30),
tags$h5("Preparing the calculation"),
actionButton("dataset2", "Extract", class = "btn-primary")
),
mainPanel(
tableOutput("contents2"),
tabsetPanel(
tabPanel("Datasets",
h4("Domains"),
tableOutput("table2"),
h3("Calculating...")
)
)
)
),
tabPanel("Comparision",
sidebarPanel(
fileInput("file3", "Select study report and datasets:"),
textInput("txt3", "Study info:", "Study name read"),
tags$h5("Prepare comparison"),
actionButton("action2", "Compare", class = "btn-primary")
),
mainPanel(
tabsetPanel(
tabPanel("PDF File select",
h4("Domains"),
tableOutput("table3"),
h3("Comparing..."),
),
tabPanel("calculation data", "TBD")
)
)
)
)
),
server = function(input, output, session) {
output$contents <- renderTable({
# input$file1 will be NULL initially. After the user selects
# and uploads a file, it will be a data frame with 'name',
# 'size', 'type', and 'datapath' columns. The 'datapath'
# column will contain the local filenames where the data can
# be found.
inFile <- input$file1
if (is.null(inFile))
return(NULL)
read.csv(inFile$datapath, header = input$header)
})
output$contents2 <- renderTable({
# input$file1 will be NULL initially. After the user selects
# and uploads a file, it will be a data frame with 'name',
# 'size', 'type', and 'datapath' columns. The 'datapath'
# column will contain the local filenames where the data can
# be found.
inFile <- input$file2
if (is.null(inFile))
return(NULL)
read.csv(inFile$datapath, header = input$header)
})
output$txtout <- renderText({
paste(input$txt, input$slider, format(input$date), sep = ", ")
})
output$table <- renderTable({
df <- c("Domain1","Domain2","Domain3","Domain4")
})
output$table2 <- renderTable({
df <- c("Domain1","Domain2","Domain3","Domain4")
})
output$table3 <- renderTable({
df <- c("Domain1","Domain2","Domain3","Domain4")
})
observeEvent(input$dataset, {
source("Domain1.R", local = TRUE)
})
observeEvent(input$dataset2, {
source("calculation.R", local = TRUE)
})
observeEvent(input$pdfExtract1, { #When I press the extract button, nothing happens.
source("Domain1.R", local = TRUE)
})
observeEvent(input$pdfExtract1, { #When I press the extract button, nothing happens.
source("Domain2.R", local = TRUE)
})
}
)
You have some elements sharing the same id here:
selectInput("pdfExtract1", "Pick a PDF", choices = c('Domain1')),
tableOutput("preview"),
actionButton("pdfExtract", "Extract", class = "btn-primary"),
selectInput("pdfExtract1", "Pick a PDF", choices = c('Domain2')),
tableOutput("preview"),
actionButton("pdfExtract", "Extract", class = "btn-primary")
This is wrong. Replace this code block with:
selectInput("pdfExtract1", "Pick a PDF", choices = c("Domain1", "Domain2")),
tableOutput("preview"),
actionButton("pdfExtract", "Extract", class = "btn-primary")
Then observe the click on the button, and run the script corresponding to the selection:
observeEvent(input$pdfExtract, {
if(input$pdfExtract1 == "Domain1"){
source("Domain1.R", local = TRUE)
}else{
source("Domain2.R", local = TRUE)
}
})
But there's something not clear in your app: it also runs Domain1.R when the user clicks on the dataset button:
observeEvent(input$dataset, {
source("Domain1.R", local = TRUE)
})
I don't know what you want to do so I cannot further comment this point.

R Shiny - How to show/hide "fileinput" based on condition (tab panel selection)

I need to show "fileinput"/file upload option when a particular tabpanel is selected.
Ex. There are 3 tabpanels like A,B and C
When tab B is selected the "fileinput" option should appear and when A or C is selected, the "fileinput" option should be hidden from the sidebarpanel.
I tried the below but not working. Can anyone help? Thanks...
sidebarPanel(
conditionalPanel(condition = "input$id == 'B'", fileInput("file", "Choose xlsx file", accept = ".xlsx"))
mainPanel(
tabsetPanel(
tabPanel("A", value = 'A', DT::dataTableOutput("Table A")),
tabPanel("B", value = 'B', DT::dataTableOutput("Table B")),
tabPanel("C", value = 'C', DT::dataTableOutput("Table C")),
id ="tabselected"
)
)
You need to use the appropriate ID of the tabsetPanel in the condition with a . instead of $. Try this
library(readxl)
runApp(list(
ui = shinyUI(
fluidPage(
sidebarLayout(
sidebarPanel(
conditionalPanel(condition = "input.tabselected == 'tab2'",
fileInput("file", "Choose xlsx file", accept = ".xlsx")),
selectInput(
inputId = 'selected.indicator',
label = 'Select an option: ',
choices = colnames(mtcars)
)
),
mainPanel(
tabsetPanel(
tabPanel("A", value = 'tab1', DTOutput("t1")),
tabPanel("B", value = 'tab2', DTOutput("t2")),
tabPanel("C", value = 'tab3', DTOutput("t3")),
id ="tabselected"
)
)
)
)
),
server = function(input, output, session) {
output$t1 <- renderDT(cars)
output$t3 <- renderDT(mtcars)
mydata <- reactive({
req(input$file)
inFile <- input$file
df <- read_excel(inFile$datapath)
})
output$t2 <- renderDT({
req(mydata())
mydata()
})
}
))

R shiny conditional panels with multiple file inputs

I have come across unusual behavior with the conditional panel in R shiny. I want to have multiple file inputs that the user can upload depending on how many files they want. The below is reducible code. This issue is if the condition is greater than 1 I cannot populate all the files with csv files?? I can for second but not the first
library('shiny')
library('shinythemes')
## adding the conditional statements
ui =
navbarPage("Page Title",
tabPanel("Panel 1",
sidebarPanel(
## Add Name,
## Number of surveys analysising
numericInput("n_values", "Number of columns in next panel:", 1, min = 1, max = 2)
),
mainPanel(
tags$div(
h2("Home Page")
)
)
),
tabPanel("Panel 2",
conditionalPanel(condition = "input.n_values == 1",
fixedPage(theme = "flatly",
fixedRow(
column(2,"First Column",
fileInput("File1", "Choose a CSV files", multiple = F),
p("Click the button to check the data was read in correctly")
),
fixedRow(
column(12,
verbatimTextOutput("errorText1")
)
)
)
)
),
conditionalPanel(condition = "input.n_values == 2",
fixedPage(theme = "flatly",
fixedRow(
column(2,"First Column",
fileInput("File1", "Choose a CSV files", multiple = F),
p("Click the button to check the data was read in correctly")
),
column(2,"Second Column",
fileInput("File2", "Choose a CSV files", multiple = F),
p("Click the button to check the data was read in correctly")
),
fixedRow(
column(12,
verbatimTextOutput("errorText2")
)
)
)
)
)
)
)
server = function(input, output,session) {
## Call the error message function and print
output$errorText1 <- renderText({
validate(
if (input$n_values == 1) {
need(!is.null(input$File1)
, 'You need to input the files before we can validate the data. Please select all the necessary files.')
}
)
validate("allgravy")
})
output$errorText2 <- renderText({
validate(
if (input$n_values == 2) {
need(!is.null(input$File1) & !is.null(input$File2)
, 'You need to input the files before we can validate the data. Please select all the necessary files.')
}
)
validate("allgravy")
})
}
shinyApp(ui, server)
when the condition "number of columns is 2" I can not upload files in the first column, is this a coding issue?
The code works when not in a conditionalPanel, see below for a reproducible example
ui =
navbarPage("Page Title",
tabPanel("Panel 1",
sidebarPanel(
## Add Name,
## Number of surveys analysising
numericInput("n_surveys", "Number of surveys analysing:", 2, min = 1, max = 10)
),
mainPanel(
tags$div(
h2("Home Page")
)
)
),
tabPanel("Panel 2",
fixedPage(theme = "flatly",
fixedRow(
column(2,h4("First Column"),
fileInput("File1", "Choose a CSV files", multiple = F),
actionButton("CheckData", "Validate Input"),
p("Click the button to check the data was read in correctly")
),
column(2,h4("Second Column"),
fileInput("File2", "Choose a CSV files", multiple = F)
),
fixedRow(
column(12,
verbatimTextOutput("errorText")
)
)
)
)
)
)
server = function(input, output,session) {
## Call the error message function and print
output$errorText <- renderText({
validate(
need(!is.null(input$File1)
, 'You need to input the files before we can validate the data. Please select all the necessary files.')
)
validate("seems allgood")
})
}
shinyApp(ui, server)
Chairs
The issue is that you are using the same element twice; you are using the line fileInput("File1", "Choose a CSV files", multiple = F) twice in your code and that is not allowed (I think it has to do with this).
You can solve this by only using the element once, and changing your conditions. For example like this:
library('shiny')
library('shinythemes')
## adding the conditional statements
ui =
navbarPage("Page Title",
tabPanel("Panel 1",
sidebarPanel(
## Add Name,
## Number of surveys analysising
numericInput("n_values", "Number of columns in next panel:", 1, min = 1, max = 2)
),
mainPanel(
tags$div(
h2("Home Page")
)
)
),
tabPanel("Panel 2",
conditionalPanel(condition = "input.n_values == 1 | input.n_values == 2",
fixedPage(theme = "flatly",
fixedRow(
column(2,"First Column",
fileInput("File1", "Choose a CSV files", multiple = F),
p("Click the button to check the data was read in correctly")
),
conditionalPanel(condition = "input.n_values == 2",
column(2,"Second Column",
fileInput("File2", "Choose a CSV files", multiple = F),
p("Click the button to check the data was read in correctly")
)
)
),
fixedRow(
column(12,
verbatimTextOutput("errorText2")
)
)
)
)
)
)
)
server = function(input, output,session) {
## Call the error message function and print
output$errorText1 <- renderText({
validate(
if (input$n_values == 1) {
need(!is.null(input$File1)
, 'You need to input the files before we can validate the data. Please select all the necessary files.')
}
)
validate("allgravy")
})
output$errorText2 <- renderText({
validate(
if (input$n_values == 2) {
need(!is.null(input$File1) & !is.null(input$File2)
, 'You need to input the files before we can validate the data. Please select all the necessary files.')
}
)
validate("allgravy")
})
}
shinyApp(ui, server)
I did not really look at formatting or lay-out, this code is just to illustrate a working example. Hope this helps!

Shiny: add upload widget after input type selection

I am pretty new to shiny.
I am working on an application and at one point it gives the option of either uploading a csv file or using text input to generate the 'csv'(it's actually a data.table internally). Depending on the selection I would like either the sidebarpanel to extend and load the upload widget (or the text input to appear in the main panel)
At the moment the upload-widget shows up right when the app is loaded.
I appreciate any help!
ui <- shinyUI(fluidPage(
tagList(
navbarPage( id = 'mynavlist', "My App",
tabPanel("Create Boolean Gates",
sidebarPanel(
radioButtons("radio", label = p("Choose one option"),
choices = list("Upload Template" = 1, "Create Template" = 2),
selected = 1),
tags$hr(),
####only when selection is 'Upload Template'
uiOutput("templ_upload"),
tags$hr()
),
mainPanel(
#####only when upload was selected and after uploading the csv file
tableOutput(outputId = 'table'),
####only when selection is 'Create Template'
uiOutput("templ_create")
)
)
))))
server <- shinyServer(function(input, output) {
#### display upload widget if 'upload template' is chosen
output$templ_upload <- renderUI({
fileInput(inputId = 'templ_file', label = 'Choose a Template in csv
format')
tags$hr()
checkboxInput('header', 'Header', TRUE)
radioButtons('sep', 'Separator',
c(Comma=',',Semicolon=';',Tab='\t'))
})
####show the data after upload in mainpanel
output$table <- renderTable({
if (is.null(input$table)){
h5("You have not uploaded a valid file")
}else{
template_csv <- fread(input$table$datapath, header=input$header,
sep=input$sep,quote=input$quote, check.names = FALSE)
return(template_csv)
}
})
####to be finished
# output$templ_create <- renderUI({
# })
})
shinyApp(ui = ui, server = server)
A conditionalPanel() could be used, but I think in this case it is easier to
specify these conditions in the renderUI():
(DonĀ“t forget to use a tagList() if you want to pass multiple UI elements from the renderUI())
output$templ_upload <- renderUI({
if(input$radio == 1){
tagList(
fileInput(inputId = 'templ_file', label = 'Choose a Template in csv
format'),
tags$hr(),
checkboxInput('header', 'Header', TRUE),
radioButtons('sep', 'Separator',
c(Comma=',',Semicolon=';',Tab='\t'))
)
}
})
output$templ_create <- renderUI({
if(input$radio == 2){
textInput("table", "Table", "Sample text")
}
})

updateTabsetPanel not working

Does anyone know why this simple code is not working?
What I am trying to do: make the structure tab active whenever users click on the run button (input$runButton). When I click the run button, the value of input$runButton gets updated, but the tab is not changed to structure.
Here is a simple reproducible example:
server.R
function(input, output, session) {
#RUN button
observeEvent(input$runButton, {
updateTabsetPanel(session, "allResults", 'structure')
})
#VAR SELECTION
output$inputVars <- renderText({
if (input$runButton == 0)
return()
print("Vars Selected")
})
#STRUCTURE RESULT
output$structure <- renderText({
if (input$runButton == 0)
return()
print("Structure Results")
})
}
ui.R
fluidPage(
titlePanel("Periscope Structure"),
br(),
sidebarPanel(
fileInput(inputId="inFile", "Choose CSV File",
accept = c(
"text/csv",
"text/comma-separated-values,text/plain",
".csv")
),
checkboxInput("header", "Header", TRUE),
numericInput("level", "Structure Level", 3, min = 2, max = 10),
br(),
actionButton("runButton", strong("Run!"))
),
mainPanel(
tabsetPanel(id = "allResults",
tabPanel('Variable Selection', textOutput('inputVars')),
tabPanel('Structure Result', textOutput('structure')))
)
)
Thank you!
Note that you need to assign a value to TabPanel so you can make them active using the updateTabsetPanel call, so try this:
require(shiny)
ui <- fluidPage(
titlePanel("Periscope Structure"),
br(),
sidebarPanel(
fileInput(inputId="inFile", "Choose CSV File",
accept = c(
"text/csv",
"text/comma-separated-values,text/plain",
".csv")
),
checkboxInput("header", "Header", TRUE),
numericInput("level", "Structure Level", 3, min = 2, max = 10),
br(),
actionButton("runButton", strong("Run!"))
),
mainPanel(
tabsetPanel(id = "allResults",
tabPanel(value = "inputVars",'Variable Selection', textOutput('inputVars')),
tabPanel(value = "structure",'Structure Result', textOutput('structure')))
)
)
server <- function(input, output, session) {
#RUN button
observeEvent(input$runButton, {
updateTabsetPanel(session, "allResults", 'structure')
})
#VAR SELECTION
output$inputVars <- renderText({
if (input$runButton == 0)
return()
print("Vars Selected")
})
#STRUCTURE RESULT
output$structure <- renderText({
if (input$runButton == 0)
return()
print("Structure Results")
})
}
runApp(shinyApp(ui, server), launch.browser = TRUE)
Note that if you are using shiny modules, that you have to refer to the correct session. For example, if a single tab is a module, the session of that tab won't be able to switch to another tab
To fix this, you can actually pass the session of the "parent" (container) of all your tabs into the constructor of the tab module, and then use that
Rough sketch of an example
shinyUI(function(request) {
source('page/search.R', local = T)
source('page/app.R', local = T)
fluidPage(
tabsetPanel(id = 'inTabset',
tabPanel(id = 'search', 'Search', searchUI('search'), value = 'search'),
tabPanel(id = 'app', 'App', appUI('app'), value = 'app')
)
)
})
shinyServer(function(input, output, session) {
source('page/search.R', local = T)
source('page/app.R', local = T)
searchSession = callModule(searchServer, 'search')
callModule(appServer, 'app', session, searchSession)
})
The shiny module
appUI = function(id) {
ns = NS(id)
tagList(
actionButton(ns('sendToHeatmap'), 'Send ortholog groups to heatmap')
)
}
appServer = function(input, output, session, parentSession, searchSession) {
# listen to a button press and switch to tab
observeEvent(input$sendToSearch, {
updateTextInput(searchSession, 'searchBox', 'funsearchterm')
updateTabsetPanel(parentSession, 'inTabset', selected = 'search')
})
}

Resources