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!
Related
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()
})
}
))
I need some help as to how to re-hide a shiny output once it has been rendered. Below I have provided a reproducible example to explain my question.
I want text 2.2 to only be shown if Option 1 and B are selected, and text 1 to only show when option 2 is selected. I have done this by including conditionalPanel() with the conditions set accordingly.
This works, however, once the text has been rendered this text will not disappear when the input changes. I want text 2.2 to disappear if the user then changes the inputs to select any other option i.e. chooses Option 2.
Is it possible to do this with shiny? Apologies if this has been asked before - I couldn't find anything through searching - your help is much appreciated!
library(shiny)
ui <- fluidPage(
sidebarPanel(
selectInput("Input1", label = "Input1", choices = c("Option 1", "Option 2") ),
conditionalPanel(condition = "input.Input1 == 'Option 1'",
selectInput("Input2", label = "Input2",
choices = c("A", "B"))),
),
mainPanel(
tabsetPanel(
tabPanel("Tab 1", textOutput(outputId = "text1")),
tabPanel("Tab 2", textOutput(outputId = "text2.1"), textOutput(outputId = "text2.2") )
)
)
)
server <- function(input, output) {
observe({if(input$Input1 == 'Option 2'){
output$text1 <- renderText("This text only shows for option 2")
}})
output$text2.1 <- renderText("some text")
observe({if(input$Input2 == 'B'){
output$text2.2 <- renderText("Show this only if option 1B is selected")
}})
}
shinyApp(ui, server)
You need to specify the different if possiblities inside the observe environment. Here's a solution:
library(shiny)
ui <- fluidPage(
sidebarPanel(
selectInput("Input1", label = "Input1", choices = c("Option 1", "Option 2") ),
conditionalPanel(condition = "input.Input1 == 'Option 1'",
selectInput("Input2", label = "Input2",
choices = c("A", "B"))),
),
mainPanel(
tabsetPanel(
tabPanel("Tab 1", textOutput(outputId = "text1")),
tabPanel("Tab 2", textOutput(outputId = "text2.1"), textOutput(outputId = "text2.2") )
)
)
)
server <- function(input, output) {
observe({
if(input$Input1 == 'Option 2'){
output$text1 <- renderText("This text only shows for option 2")
}
else {
output$text1 <- renderText("")
}
})
output$text2.1 <- renderText("some text")
observe({
if (input$Input2 == "B") {
output$text2.2 <- renderText("Show this only if option 1B is selected")
}
else {
output$text2.2 <- renderText("")
}
})
}
shinyApp(ui, server)
I have a shiny application in which a dataTable is displayed when the user selects Sector A from the radioButtons menu in the sidebar. The problem is that it is displayed twice. I checked it in browser mode too. Why does this happen I display the whole app here since it may be caused by the if logic of the app. renderTable() works fine so I guess there is an issue with DT
#ui.r
library(shiny)
library(shinythemes)
library(DT)
ui <- fluidPage(
theme=shinytheme("slate") ,
# App title ----
titlePanel("Tabsets"),
# Sidebar layout with input and output definitions ----
sidebarLayout(
# Sidebar panel for inputs ----
sidebarPanel(
uiOutput("rad")
),
# Main panel for displaying outputs ----
mainPanel(
uiOutput("tabers"),
DT::dataTableOutput("table")
)
)
)
#server.r
library(shiny)
library(DT)
server = function(input, output) {
output$rad<-renderUI({
radioButtons("radio", label = "",
choices = list("Home"=1,"About" = 2, "Sector A" = 3, "Sector B" = 4,"Sector C" = 5),
selected = 1)
#selected = character(0))
})
output$tabers<-renderUI({
if(is.null(input$radio)) {
tabsetPanel(
id="tabF",
type = "tabs",
tabPanel("Global"),
tabPanel("Performance")
)
}
else if(input$radio==3){
tabsetPanel(
id="tabC",
type = "tabs",
tabPanel("Constituents",
output$table <- renderDataTable({
mtcars
})
),
tabPanel("Clusters" ),
tabPanel("Index")
)
}
else if(input$radio==4){
tabsetPanel(
id="tabD",
type = "tabs",
tabPanel("Constituents"
),
tabPanel("Clusters" ),
tabPanel("Index")
)
}
else if(input$radio==5){
tabsetPanel(
id="tabE",
type = "tabs",
tabPanel("Constituents"
),
tabPanel("Clusters" ),
tabPanel("Index")
)
}
else if(input$radio==2){
}
# Left last else in here but should not get called as is
else if(input$radio==1){
tabsetPanel(
id="tabA",
type = "tabs",
tabPanel("Global"),
tabPanel("Performance" )
)
}
})
}
It looks like renderTable does the same thing. For some reason, the output of renderDataTable({mtcars}) gets displayed twice, first through uiOutput, second through dataTableOutput() (both are in mainPanel). Commenting the line dataTableOutput("table") fixes the behavior in that it shows the table only once. Interestingly, removing the assignment like so:
else if(input$radio==3){
tabsetPanel(
id="tabC",
type = "tabs",
tabPanel("Constituents",
renderDataTable({
mtcars
})
),
tabPanel("Clusters" ),
tabPanel("Index")
)
}
also renders the table once. So it looks like when inside renderUI, renderDataTable just creates the output without requiring a dataTableOutput in the UI.
This seems to allow (for better or worse) to easily render different tables in different tabs without corresponding output entries in the UI.
else if(input$radio==3){
tabsetPanel(
id="tabC",
type = "tabs",
tabPanel("Constituents",
renderDataTable({
mtcars
})
),
tabPanel("Clusters" ),
tabPanel("Index")
)
}
else if(input$radio==4){
tabsetPanel(
id="tabD",
type = "tabs",
tabPanel("Constituents",
renderDataTable({
iris
})
),
tabPanel("Clusters" ),
tabPanel("Index")
)
}
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)
I am trying to a multi tab app, I want the the second tab's page layout to be conditional on an input from the first panel. Basically if the value in the first panel is 1 I want the second panel to display 1 set of file inputs if the user puts in the value 2 in the first panel then I want the second panel to display 2 file inputs. Currently my code displays both conditions, and I am unsure why. See the reproducible code below.
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",accept = c("text/csv","text/comma-separated-values",".csv"), multiple = F),
p("Click the button to check the data was read in correctly")
),
fixedRow(
column(12,
verbatimTextOutput("errorText")
)
)
)
)
),
conditionalPanel(condition = "input.n_values == 2",
fixedPage(theme = "flatly",
fixedRow(
column(2,"First Column",
fileInput("File1", "Choose a CSV files",accept = c("text/csv","text/comma-separated-values",".csv"), multiple = F),
p("Click the button to check the data was read in correctly")
),
column(2,"Second Column",
fileInput("File2", "Choose a CSV files",accept = c("text/csv","text/comma-separated-values",".csv"), multiple = F),
p("Click the button to check the data was read in correctly")
),
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.')
)
})
}
shinyApp(ui, server)
That's because you have verbatimTextOutput("errorText") twice in your UI. You can't do that in Shiny. An output must be included at one place only.