shiny app for a taking input of multiple fields - r

I `m trying to build an app like this:-
Choose: # this is selectInput (So only one can be chosen at a time)
choice 1
choice 2
choice 3
once a choice is made then say choice 1 then the scree should display further sub option to that as,
In choice 1 select :
op1
op2
op3
op4
and these are multiple check box that is user can tick mark any number of checkboxs.
After this the relevant output is to be displayed.
and also I want the app to reflect the changes when the inputs are changed.
I have no clue to do this ,I`m trying this from few days but only managed to get the ui part done but nothing much on server.R code

hope this will help you.
UI.R file
library(shinyBS)
library(shiny)
shinyUI(fluidPage(
# input control for first choice
selectInput("first_choice",
label = h1("First Answer a General Question"),
choices = list("select","A","B","C"),
selected = "select"
),
#collapsable panel for second choice
h1("then get into details"),
bsCollapse(
bsCollapsePanel( title = "details",
uiOutput("second_choice")
),
id = "collapser", multiple = FALSE, open = NULL
),
h2("first answer"),
h3(textOutput("first_answer")),
h2("second answer"),
h3(textOutput("second_answer"))
))
server.R file
library(shiny)
shinyServer(function(input, output,session) {
#retrieve selected values and render text from selection
output$first_answer <- renderText({input$first_choice})
output$second_answer <- renderText({input$dynamic})
output$second_choice <- renderUI({
switch(input$first_choice,
"A" = checkboxGroupInput("dynamic", "Dynamic",
choices = c("Aragon","Frodo"),
selected = "option2"),
"B" = checkboxGroupInput("dynamic", "Dynamic",
choices = c("Bilbo","Gandalf","Sauron"),
selected = "option2"),
"C" = checkboxGroupInput("dynamic", "Dynamic",
choices = c("Boromir","Legolas"),
selected = "option2")
)
})
#observe function in order to open the collapsable panel when the first answer is given
observe({
if (input$first_choice != "select") {
updateCollapse(session,"collapser",open = c('details'))
}
})
})
this result in the following shiny app:
where the second menu opens only after the first get an answer and the options for the second question are dynamically changed based on the first answer.
selected answers are assigned to first_answer and second_answer.
Please note the use of shinyBS package for the collapsable panel.
You can find more on dynamic UI changes at the following Rstudio sources:
http://shiny.rstudio.com/articles/dynamic-ui.html
http://shiny.rstudio.com/gallery/dynamic-ui.html

Related

Shiny: updateSelectInput() selected argument issue with observe()

I'm using observe() to change a value of a selectInput after a user selects TRUE/FALSE in the Categorical drop down list. In the first tab of my program if you set Categorical to TRUE then Impute gets updated to mode and mean otherwise. I'm then able to change the Impute value as desired without it reverting to the value that appears when TRUE/FALSE is selected.
In the second tab I have a multiple selectInput list with a similar interface as the first tab; the interface is created for every value selected in Select covariates. In this section I also used observe() to update each selected covariates' Impute drop down list accordingly to the logic of the first tab (i.e. if TRUE is selected then Impute gets updated to mode and mean otherwise). However, the value in Impute appers to be locked in the sense that I'm not able to switch between values as I did in the first tab.
I don't know how to correct this issue and I was wondering if anyone out there has encountered this similar problem and has been able to fix it. Any advice or help would be greatly appreciated.
The code to my app can be seen below and can be ran in a single file.
library(shiny)
library(shinyjs)
ui <- shinyUI(fluidPage(
shinyjs::useShinyjs(),
navbarPage("Test",id="navbarPage",
tabPanel("First tab", id = "first_tab",
sidebarLayout(
sidebarPanel(
selectInput('covariate.L.categorical', 'Categorical', c("",TRUE,FALSE)),
selectInput('covariate.L.impute', "Impute", c("","default","mean","mode","median"))
),
mainPanel()
)
),
tabPanel("Second tab", id = "second_tab",
sidebarLayout(
sidebarPanel(
selectInput('covariates', 'Select covariates', choices = c("age","sex","race","bmi"), multiple=TRUE, selectize=TRUE),
tags$hr(),
uiOutput("covariateop")
),
mainPanel()
)
))
))
server <- shinyServer(function(input, output, session) {
rv <- reactiveValues(cov.selected = NULL)
observe({
updateSelectInput(session, "covariate.L.impute", selected = ifelse(input$covariate.L.categorical,"mode","mean"))
})
output$covariateop <- renderUI({
lapply(input$covariates, function(x){
tags$div(id = paste0("extra_criteria_for_", x),
h4(x),
selectInput(paste0(x,"_categorical"), "Categorical",
choices = c("",TRUE,FALSE)),
selectInput(paste0(x,"_impute"), "Impute",
choices = c("","default","mean","mode","median")),
textInput(paste0(x,"_impute_default_level"), "Impute default level"),
tags$hr()
)
})
})
observe({
lapply(input$covariates, function(x){
updateSelectInput(session, paste0(x,"_impute"), selected = ifelse(as.logical(reactiveValuesToList(input)[[paste0(x,"_categorical")]])==TRUE,"mode","mean"))
})
})
})
# Run the application
shinyApp(ui = ui, server = server)
In your observe in the second tab, you use reactiveValuesToList(input)[[paste0(x,"_categorical")]]. This means that this observe is reactive to any changes in any input element, so also if you change the "Imputation" input. You can just use input[[paste0(x,"_categorical")]] instead to get rid of this behaviour.
Note that the implementation of dynamic UI with lapply leads to the deletion and anew rendering of already existing input selections when an additional variable is selected. Maybe you can have a look at insertUI/removeUI to get a bit nicer UI.

Action button and selectInput in R Shiny: Passing input of selectInput to a function after clicking an action button

I have a question regarding R Shiny.
I have defined a function in my global.R that takes 3 arguments and then displays a plot, so:
get.plot(mode, threshold, names = names)
In my Shiny App I have set up a sidebarPanel with a selectInput (multiple = FALSE) for mode, selectInput (multiple = TRUE) for names and a sliderInput for the threshold. In the mainPanel of my ShinyApp I dynamically render the plot using the inputs of the two selectInput objects and the sliderInput, which works perfectly fine.
The names list in my function contains 10 different names (all are shown in default setting) that can be combined in any way using the selectInput (multiple = FALSE). The problem is that my function is quite long and the calculations take long because it recalculates the function each time I delete a name in the selectInput. For example, if I want to display only 2 names, I have to remove 8 names of the selectInput, which means the function recalculates 8 times, which then takes very long.
I thought about showing an action button ("Apply Names") that can be clicked after the names have been selected. However, I still want the plot to adjust dynamically to the other arguments mode and threshold, and the button should only change the names argument.
Do you have any idea how I could solve that? Or do you have any other suggestions?
My setup looks approximately the following:
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
selectInput(inputId = "network_names",
label = "Select multiple names",
choices = names,
multiple = TRUE,
selected = names
),
selectInput(inputId = "network_mode",
label = "Select a mode",
choices = list("Mode 1",
"Mode 2")
),
sliderInput(inputId = "threshold",
label = "Threshold",
min = 1,
max = 10,
value = 3)
)
server <- function(input, output){
output$network <- renderPlot({
if(input$network_mode == "Mode 1") {
get.plot(1, input$threshold, names = input$network_names)
} else if(input$network_mode == "Mode 2") {
get.plot(2, input$threshold, names = input$network_names)
}
})
}
Any help is appreciated. Thank you very much.

Shiny - conditional panel not recognizing input

I'm working with shiny and I'm having difficulty having R recognize input when using conditionalPanel. I have two such panels in my app because I need them to produce a certain list depending on which of the radio buttons a user selects.
Everything is rendered fine from the UI perspective, but for some reason R is unable to pick up any input when the 'Name' option is passed through the conditional panel, even if an item is entered in the field. The correct list is used, but for some reason it doesn't detect any input. Here's a screenshot of the selections and results.
I have no issues if I choose the other option from within the radio buttons and enter an item--it works as expected. Here's the code I'm working with.
ui <- fluidPage(
sidebarPanel(
# the user can choose from two options within the radio buttons
radioButtons("items_type", label = "Choose items for analysis"
, choices = list("Items - Item number & name" = "Both", "Items - Item name only" = "Name")
, selected = "Both")
# if the 'Both' option is selected, the items_list_names_id option is used
, conditionalPanel(
condition = "output.items_type == 'Both'"
, selectInput("items", label = NULL, choices = items_list_names_id, multiple = TRUE))
# if the 'Name' option is selected, the items_list_names option is used. input
# is not being detected here for some reason, and I'm wondering if it's because
# I use "items" for both selectInputs
, conditionalPanel(
condition = "output.items_type == 'Name'"
, selectInput("items", label = NULL, choices = items_list_names, multiple = TRUE))
# action button so the user can submit for analysis based on their selected options
, actionButton("go", "Run", style = "color: white; background-color: #2759aa")
)
)
server <- function(input, output){
# this portion is used to detect if the user alternates between either option from the radio buttons and uses the appropriate selectInput option
output$items_type <- reactive({
input$items_type
})
outputOptions(output, "items_type", suspendWhenHidden = FALSE)
Results <- eventReactive(input$go, {
# this portion is simply for testing for me to see how R recognizes the inputs
observe({print(input$items_type)})
observe({print(input$items)})
# checks to make sure the user selects at least 1 item. For some reason,
# this portion is triggered when at least 1 item is selected under the 'Name'
# condition from the conditional panel.
validate(
need(input$items > 0, 'Please select at least 1 item for analysis')
)
#other steps start here, but the above is the more pertinent part
}
EDIT: So it looks like having the same input id for both selectInput options is what's causing R to not recognize the input when it switches between the conditional panels. However, it would be ideal to have one input id because intput$item is used in other portions of my code not shown above. Rewriting the code so that it would use two variables, input$item1 and input$item2 for example, for each condition would be potentially very troublesome. I'm open to any suggestions to avoid this.
EDIT 2: I was thinking maybe using a single conditonalPanel and using a switch statement to alternate between the two lists depending on the user's selection. This should work, theoretically, and would be a convenient solution without modifying all of my other code. It looks like this:
, conditionalPanel(
condition = "output.items_list_selection"
, selectInput("items", label = 'Select items'
, choices = switch("output.items_list_selection", "Both" = items_list_names_id, "Name" = items_list_names)
, multiple = TRUE))
But a drop down menu doesn't appear as it's supposed to with this revision.
A possible solution is to use updateSelectInput , so there is no problem with two id having the samedi inputId
library(shiny)
items_list_names_id = c("id1", "id2")
items_list_names = c('name1', 'name2')
ui <- fluidPage(
sidebarPanel(
# the user can choose from two options within the radio buttons
radioButtons("items_type", label = "Choose items for analysis"
, choices = list("Items - Item number & name" = "Both", "Items - Item name only" = "Name")
, selected = "Both"),
# if the 'Both' option is selected, the items_list_names_id option is used
selectInput("items", label = NULL, choices = c('init'), multiple = TRUE),
# action button so the user can submit for analysis based on their selected options
actionButton("go", "Run", style = "color: white; background-color: #2759aa")
)
)
server <- function(input, output, session){
# change the choices depending on the value of input$intems_type
observeEvent(input$items_type, {
if(input$items_type == 'Both'){
updateSelectInput(session, 'items', label = NULL, choices = items_list_names)
}
if(input$items_type == 'Name'){
updateSelectInput(session, 'items', label = NULL, choices = items_list_names_id)
}
})
# check if it's working
observeEvent(input$go,{
print(input$items)
print(input$items_type)
})
}
shinyApp(ui, server)

Force no default selection in selectInput()

The Shiny documentation mentions that for selectInput():
selected The value (or, if none was supplied, the title) of the navigation item that should be selected by default. If NULL, the first navigation will be selected.
What if by default I don't want to select any value from select list?
Actually my select value is getting selected by default and rest part of app is getting executed automatically. But I don't want to select any value initially. What should I supply to the selected argument in selectInput() to do that?
Indeed, I don't want anything to be selected automatically. I used the code below but still it's selecting first available value from the list. I want there to be no selection by default, so the user can then select any option.
output$Choose_App <- renderUI({
selectInput("app",
"Select App:",
choices = as.character(mtrl_name),
selected = NULL ,
multiple = FALSE
)
})
Going through the documentation I noticed that the selection can be empty only if I select multiple=TRUE. Is this correct?
When I changed to multiple=TRUE, then it it's not getting selected by default, which is what I want. But unfortunately before making any selection I am also getting following error message:
ERROR: bad 'file' argument
Does anybody know about this if I am doing something wrong? But if I select this file then error is gone.
I am using following code for this:
# server.R
setwd("/opt/shiny-server/samples/sample-apps/P-Dict_RDS2")
mtrl_name <- try(system("ls | grep -i .rds", intern = TRUE))
shinyServer(function(input, output) {
# First UI input (Service column) filter clientData
output$Choose_Molecule <- renderUI({
selectInput("molecule",
"Select Molecule:",
choices = as.character(mtrl_name),
selected = input$molecule,
multiple = TRUE
)
})
You can use the selectize input instead of the select input, with some custom selectize options to set the initial selection to be empty. An example has been provided in the Shiny Gallery. In particular, see the example #6.
# make sure you have shiny >= 0.9.1
selectizeInput(
'e6', '6. Placeholder', choices = state.name,
options = list(
placeholder = 'Please select an option below',
onInitialize = I('function() { this.setValue(""); }')
)
)
BTW, for the error "ERROR: bad 'file' argument", I do not think anybody can help you without seeing the source code of your app, and it may be a separate question.
Faced a similar issue. The solution I found is based of #MKa's answer. You do not want to set multiple=T if your code can't handle multiple values. What I suggest is:
selectInput("molecule",
"Select Molecule:",
choices = c("",as.character(mtrl_name)),
selected = NULL,
multiple = F
)
And to retrieve the value selected:
if(!is.null(input$molecule))
{
if(nchar(input$molecule)>1)
{
#do your thing..
}
}
Fixed my problem. Let me know if you found a better solution.
I think you can get around it by adding an empty string to your choice list:
selectInput("app",
"Select App:",
choices = c("", as.character(mtrl_name)),
selected = NULL,
multiple = FALSE)
#Yihui Xie's answer requires selectInput(..., selectize = TRUE). If you want selectize = FALSE, you can still achieve a similar effect as follows.
This is not documented:
selected The initially selected value (or multiple values if multiple = TRUE). If not specified then defaults to the first value for single-select lists and no values for multiple select lists.
But for single-select lists if you can use selectize = FALSE, size = 4 (any non-NULL size would work), then you can set selected = FALSE to force no default selection.
library(shiny)
# Define UI for application that draws a histogram
ui <- fluidPage(
mainPanel(
uiOutput("Choose_Molecule")
)
)
# Define server logic required to draw a histogram
server <- function(input, output) {
# First UI input (Service column) filter clientData
output$Choose_Molecule <- renderUI({
selectInput("molecule",
"Select Molecule:",
choices = rownames(mtcars),
selected = FALSE,
multiple = FALSE
, selectize = FALSE, size = 4 ##needed for `selected = FALSE` to work
)
})
}
# Run the application
shinyApp(ui = ui, server = server)
A cleaner solution is to use selectizeInput, allow multiple selections, but then limit the maximum number of selections to 1. This means the default selection will be NULL, the user can only select 1 option, and you don't have to add an empty string to your choices or similar workarounds previously listed here.
selectizeInput(
"tag",
"Label",
choices = choices,
multiple = TRUE,
options = list(maxItems = 1)
)
A workaround would be to use updateSelectInput. The point here is that you set your selected = argument to length(your_vector_with_choices).
You can create a reactiveValues if you want your selectInput to be updated at the very beginning (in that case only observed at program start).
library(shiny)
shinyApp(
ui = fluidPage(
selectInput("state", "Choose a state:", NULL),
textOutput("result")
),
server = function(input, output, session) {
values <- reactiveValues(start = NULL)
observe({
choiceList <- list(`East Coast` = list("NY", "NJ", "CT"),
`West Coast` = list("WA", "OR", "CA"),
`Midwest` = list("MN", "WI", "IA"))
updateSelectInput(session, "state", choices = choiceList, selected = choiceList[length(choiceList)])
})
output$result <- renderText({
paste("You chose", input$state)
})
}
)
Answering after 6 years, as I got the same error now. We can write
selected = character(0)
to force not selecting any user input.
A modification of #rookieJoe answer is to use req() instead of the ifs. Read this page for an intro to the req() usage (in this specific question, the fact that req() takes the string "" as a "falsy" value).
For example, if the selectInput is like his:
selectInput("molecule",
"Select Molecule:",
choices = c("", as.character(mtrl_name)),
selected = NULL,
multiple = F
)
To retrive the value in a reactive as:
my_reactive <- reactive({
req(input$molecule)
# do your stuff
})

R Shiny - how to force submit button to affect not all inputs

I am facing a problem with submitButton usage in my Shiny application (which I use as some time-consuming rendering is done with the data supplied by the app-user). I also use some radioButtons with conditionalPanel to define the variables group of which user may choose the parameters. Please see the attached image to get the idea (user is selecting a list type, and - based on his list choice - a particular list appears (conditionalPanel is working) from which the user is selecting a parameter), or run a reprodicible example supplied below.
Of course, only the parameter is a value that is using in rendering an output, and I would like to force a submitButton to pass only the parameter in an automatic way. The problem is that submitButton affects also the radioButtons element, which unables the use to choose the desired value (as the values list are not switching).
QUESTION: Is there any way to define which UI elements are to be stop-from-automatic-update by submitButton so as to solve my problem? Thank you for any help!
UI:
library(shiny)
shinyUI(pageWithSidebar(
headerPanel("Problem with submit button"),
sidebarPanel(
radioButtons("selectionway", "Choose list type", c(number='number', letter='letter')),
conditionalPanel(
condition = "input.selectionway == 'number'",
selectInput("numberlist", "Choose NUMBER:", choices = c("11111", "22222", "33333"))
),
conditionalPanel(
condition = "input.selectionway == 'letter'",
selectInput("letterlist", "Choose LETTER:", choices = c("A", "B", "C"))
),
submitButton("submitButton")
),
mainPanel(
verbatimTextOutput("list"),
verbatimTextOutput("value")
)
))
SERVER:
library(shiny)
shinyServer(function(input, output) {
selected.value <- reactive({
if(input$selectionway=="letter"){
return(input$letterlist)
} else {
return(input$numberlist)
}
})
output$list <- renderText({
input$selectionway
})
output$value <- renderText({
selected.value()
})
})

Resources