Add n reactive radioButtons to shiny app depending on user input - r

I am trying to create a shiny app in which the user can select variables from a data frame in order to subset the data. The output will (eventually) be a data table with the users subset. I need to create n number of input boxes depending on the number of variables the user selects for the subset. Ideally, the input boxes will be dynamic radio buttons (for subsetting factors). I have not yet gotten to printing the data frame, but I have been able to create multiple radio buttons. I have used to following code with the mtcars dataset to achieve this:
server.R
library(shiny)
shinyServer( function(input, output, session) {
output$variables <- renderUI({
numVar <- length(as.integer(input$in0))
lapply(1:numVar, function(i) {
list(radioButtons("dynamic", input$in0,
choices = c("Choice one" = "one", "Choice two" = "two"), selected = "one"))
})
})
})
ui.R
library(shiny)
shinyUI(pageWithSidebar (
headerPanel("mtcars subset"),
sidebarPanel(
selectInput(inputId = 'in0', label = 'Choose variables',
choices = colnames(mtcars),
multiple = TRUE, selectize = TRUE),
uiOutput("variables")
),
mainPanel()
))
The code creates n number of radio buttons; however, for some reason it defaults to printing two sets of buttons. Also, the name of each new set of buttons is always the name of the first variable selected. Moreover, selecting choice one in one set changes the choice of the other sets. I would like each radio button set to have a name corresponding to the variable in the data frame and I would like the choice of each button to be independent of the other selected buttons.

Your problem (see warnings) is that you always use same name for each radioButtons, while you should index them with i:
lapply(1:numVar, function(i) {
list(radioButtons(paste0("dynamic",input$in0[i]), input$in0[i],
choices = c("Choice one" = "one", "Choice two" = "two"), selected = "one"))
})
Or a bit more elegant:
lapply(input$in0, function(x) {
list(radioButtons(paste0("dynamic",x), x,
choices = c("Choice one" = "one",
"Choice two" = "two"), selected = "one"))
})

Related

Different behavior of conditional panels in shinyApp when using do.call(fluidRow, ...)

This is a bit esoteric, but I am interested in the reason for this strange behavior.
I have a shiny app where I have a checkbox input for the user to select which menus they want to display. For each one they check, an additional "hidden" menu appears. I was interested in doing this programmatically with do.call to include an arbitrary number of menus. However, using do.call to execute fluidRow causes different behavior than calling fluidRow directly. Specifically, multiple rows are created instead of a single row, with some unwanted text between each row. Below is a reprex showing this behavior. Can anyone explain why this behavior is occurring and how to fix it?
Code
# Define function to show hidden menu.
hidden_menu <- function(i) {
column(width = 3,
conditionalPanel(
condition = paste0('input.display_menus.includes("', i, '")'),
checkboxGroupInput(paste0("categories_", i), "Select categories",
choiceNames = letters[1:2],
choiceValues = letters[1:2],
selected = letters[1:2]
)
)
)
}
# UI
ui <- fluidPage(
# Checkboxes of which menus to display
fluidRow(
checkboxGroupInput("display_menus", "Select menus to display",
choiceNames = c("one", "two", "three"),
choiceValues = 1:3,
selected = 1:3
)
),
# Menus displayed one way
fluidRow(
hidden_menu(1),
hidden_menu(2),
hidden_menu(3)
),
# Menus displayed another way; shouldn't this be identical to the one above?
do.call(fluidRow, sapply(1:3, hidden_menu))
)
library(shiny)
shinyApp(ui = ui, server = function(input, output) {})
Output
This shows the output with menus 1 and 3 selected. The first way of doing it, calling fluidRow directly, works as intended. The second way of doing it, using do.call, has a different orientation and some unwanted text output.

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)

R shiny: Create reactively drop down choices or autocompletion with multiple data sets

I would like to provide reactively drop down choices (autocomplete suggestions) to the user depending on the input he provides. User input and autocomplete suggestions should be in the same widget.
The problem is, that I have a large data set (1 million rows+) from which the user should be able to choose names from. Since preloading this large data set would slow down the app, I would like to work with multiple splitted data sets, which I load depending on first letter of the user input.
The goal is to provide something like a textInput widget where the user is able to start typing a name. Depending on the first letter of this user input, I would like to present suggestions to the user from which he should be able to choose from.
Unfortunately this is not possible with:
textInput (lacks of drop down with suggestions)
selectInput / selectizeInput / select2Input (lacks of ability to work with non-pre loaded data)
Here are my failed trails with different input widgets to get this to work.
library(shiny)
library(shinysky)
#ui
ui <- fluidPage(
#Text Input
textInput(inputId = "txtInput", label = "Text Input", value = NULL),
#Select Input
selectInput(inputId = "selectInput", label = "Select Input", choices = NULL),
#Selectize Input
selectizeInput(inputId = "selectizeInput", label = "Selectize Input", choices = NULL),
#Select2Input from shinysky
select2Input(inputId = "select2Input", label = "Select2 Input", choices = NULL)
)
#server
server <- function(input, output, session) {
#Create reactive values
rv <- reactiveValues()
#Function for loading specific data set
f.populate.values <- function(start.letter) {
data.set <- c()
if(start.letter == "a") {
#Example toy list
data.set <- c("aaa", "abc", "adb", "adf")
}
if(start.letter == "b") {
#Example toy list
data.set <- c("baa", "bbc", "bdb", "bdf")
}
return(data.set)
}
#Failed trials to update / generate a dropdown with the loaded data set from "f.populate.values"
observeEvent(input$txtInput, {
#Store loaded data depending on first typed character
rv$names <- f.populate.values(substring(input$txtInput, 1, 1))
#Trials to update suggestions in widgets
updateTextInput(inputId = "txtInput", value = rv$names, session = session)
updateSelectInput(inputId = "selectInput", choices = rv$names, session = session)
updateSelectizeInput(inputId = "selectizeInput", choices = rv$names, session = session)
updateSelect2Input(inputId = "select2Input", choices = rv$names, label = "Select 2 Input", session = session)
})
}
shinyApp(ui, server)

shiny app for a taking input of multiple fields

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

Resources