Access input ID of reactive radioButtons in shiny app - r

I am trying to create a shiny app which includes radioButtons which are reactive to some user input.
I was successful to implement the code from this related question:
Add n reactive radioButtons to shiny app depending on user input
However, in this question it is not described how to access this values.
Here is the example:
server.R
library(shiny)
shinyServer( function(input, output, session) {
output$variables <- renderUI({
numVar <- length(as.integer(input$in0))
lapply(input$in0, function(x) {
list(radioButtons(paste0("dynamic",x), x,
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()
))
What I have tried so far:
numVar <- length(as.integer(input$in0))
for(i in 1:numVar){
in <- noquote(paste0("dynamic",input$in0[i]))
input$in
}
However, this does not work. Any suggestions?

I'm not sure exactly of your use case but to access the values you could edit your code as below:
numVar <- length(as.integer(input$in0))
for(i in 1:numVar){
value <- paste0("dynamic",input$in0[i])
input[[value]]
}
Basically you need to use input[[value]] as opposed to input$value in this case. It doesn't seem that R allows you to use in as a variable (probably because it's already used in other contexts). You don't need noquote() anymore.

Welcome to stackoverflow!
You were almost there. However, you'll have to make sure, that you are accessing the inputs in a reactive context.
Here is a working example:
library(shiny)
ui <- fluidPage(
pageWithSidebar (
headerPanel("mtcars subset"),
sidebarPanel(
selectInput(inputId = 'in0', label = 'Choose variables',
choices = colnames(mtcars),
multiple = TRUE, selectize = TRUE),
uiOutput("variables")
),
mainPanel(
textOutput("myChoicesDisplay")
)
)
)
server <- function(input, output, session) {
output$variables <- renderUI({
lapply(input$in0, function(x) {
list(radioButtons(paste0("dynamic", x), x,
choices = c("Choice one" = "one",
"Choice two" = "two"), selected = "one"))
})
})
myChoices <- reactive({
dynInputList <- list()
for(dynInputs in paste0("dynamic", input$in0)){
dynInputList[[dynInputs]] <- input[[dynInputs]]
}
return(dynInputList)
})
output$myChoicesDisplay <- renderText({
paste(input$in0, myChoices(), sep = ": ", collapse = ", ")
})
}
shinyApp(ui, server)

Related

making selectizeInput function in Rshiny to print out all selected variables at once

I am new to Rshiny and practising how to use reactive values, reactive expressions and selectizeInput. I would like to have all brands printed at once after pressing the button without the sentence "The brands selected are as follows: " to be printed multiple times:
here is my code:
ui <- fluidPage(
titlePanel("This is a Test"),
sidebarLayout(
sidebarPanel(
selectizeInput('brand', label = 'Car brand',
multiple = T, choices = mtcars %>% rownames(),
selected = NULL, width = '100%',
options = list('plugins' = list('remove_button')))
),
mainPanel(
actionButton("show_brands", "Show brands"),
textOutput("brands")
)
)
)
server <- function(input, output, session) {
values <- reactiveValues(
brandname = NULL,
mpgdata = NULL
)
output$brands <- renderText({
allbrands <- values$brandname()
paste("The brands seleted are as follows: ", allbrands)
})
values$brandname <- eventReactive(input$show_brands, {
input$brand
})
}
shinyApp(ui, server)
and here is the output after selecting three of the brands:
We can wrap input$brand in another paste() call:
library(shiny)
ui <- fluidPage(titlePanel("This is a Test"),
sidebarLayout(
sidebarPanel(
selectizeInput(
'brand',
label = 'Car brand',
multiple = TRUE,
choices = rownames(mtcars),
selected = NULL,
width = '100%',
options = list('plugins' = list('remove_button'))
)
),
mainPanel(
actionButton("show_brands", "Show brands"),
textOutput("brands")
)
))
server <- function(input, output, session) {
output$brands <- renderText({
paste("The brands seleted are as follows: ", paste(input$brand, collapse = ", "))
}) |> bindEvent(input$show_brands)
}
shinyApp(ui, server)
PS: There is no need to use reactiveValues

How to have a user input text and create a list with shiny? R

I have the following app which allows for text to be entered and it is then saved as VALUE and printed on a panel.
Although it looks like I can only do this with one text input at a time - even if I click add (so I don't believe this button is working). On top of that I would like for the user to be able to add multiple inputs (like I have below).
And then my VALUE function should be list with multiple inputs.
code below
library(shiny)
ui <- fluidPage(
headerPanel("R Package App"),
sidebarPanel(
# selectInput("options", "options", choices=c('abc','def')),
textInput("textbox", "Enter R Package Name", ""),
actionButton("add","Add")
),
mainPanel(
textOutput("caption")
)
)
server <- function(input, output, session) {
observe({
VALUE <- ''
if(input$add>0) {
isolate({
VALUE <- input$textbox
})
}
updateTextInput(session, inputId = "textbox", value = VALUE)
})
output$caption <- renderText({
input$textbox
})
}
shinyApp(ui = ui, server = server)
Have you considered using selectizeInput with it's create option?
library(shiny)
packagesDF <- as.data.frame(installed.packages())
ui <- fluidPage(
headerPanel("R Package App"),
sidebarPanel(
selectizeInput(
inputId = "selectedPackages",
label = "Enter R Package Name",
choices = packagesDF$Package,
selected = NULL,
multiple = TRUE,
width = "100%",
options = list(
'plugins' = list('remove_button'),
'create' = TRUE,
'persist' = TRUE
)
)
),
mainPanel(textOutput("caption"))
)
server <- function(input, output, session) {
output$caption <- renderText({
paste0(input$selectedPackages, collapse = ", ")
})
}
shinyApp(ui = ui, server = server)

Display/plot filtered data (user selected) into newly created navbar tab in Shiny

I am currently facing a problem in Shiny where I am unable to display filtered data (user selected) into a newly created navbar tab. This had also led to another strange new tab removal problem.
Problem: I am stuck with the select data, appendtab (in navbar), outputUI and display/plot logic sequence in Shiny.
Scenario:
User selected data from local computer
User makes first selection from drop down list
Click on Add new tab
User makes second selection from drop down list
Click on Add new tab
Data used:
I don't know how to upload data on stackover flow but a simple csv table with two columns A and B will replicate the result below
Result:
Tab A: shows "Error: cannot coerce type 'closure' to vector of type 'character'"
Tab B: Delete tab function is now broken as well
My end goal to give more context: To be able to use this user selected data display charts, calcs, tables in the new tab.
What I did before it started erroring: I have followed similar logic to this post to display user filtered data in a new tab (not new navbartab though):
How to reuse a dataset in different objects when renderUI is used to create tabs in ShinyR
Also some help I got from Stackoverflow before this problem started. This may help with providing more context, all the answers from contributors worked:
Append and remove tabs using sidebarPanel
Can't get disable button to work with observeEvent with if statement in ShinyR
As always thank you very much for looking into my problem.
Cheers
library(shiny)
library(plyr)
library(dplyr)
library(DT)
library(shinyjs)
library(data.table)
ui <- fluidPage(
useShinyjs(),
navbarPage(title = "Stackoverflow help", id = "tabs",
tabPanel("Home",
sidebarPanel(
fileInput("file", "Upload data",
accept = c(
"text/csv",
"text/comma-separated-values,text/plain",
".csv")
),
#checkboxInput("header", "Header", TRUE),
actionButton("append", "Add new tab"),
uiOutput('tabnamesui')
),
mainPanel(
)
)
)
)
server <- function(input, output, session) {
userfile <- reactive({
input$file
})
filereact <- reactive({
read.table(
file = userfile()$datapath,
sep = ',',
header = T,
stringsAsFactors = T
)
})
tabsnames <- reactive({
names(filereact())
})
output$tabnamesui <- renderUI({
req(userfile())
selectInput(
'tabnamesui',
h5('Tab names'),
choices = as.list(tabsnames()),
selected="",multiple = FALSE
)
})
tabnamesinput <- reactive({
input$tabnamesui})
#Delete selected tab logic
observeEvent(input$append,{
appendTab(inputId = "tabs",
tabPanel(input$tabnamesui,
sidebarPanel(
actionButton(paste0("remove_", input$tabnamesui), "Delete")),
mainPanel(
uiOutput("tabsets") #This is where I think something is broken
)
)
)
})
observeEvent(lapply(grep(pattern = "^remove_", x = names(input), value = TRUE), function(x){input[[x]]}),{
if(input$tabs != "Home"){
removeTab(inputId = "tabs", target = input$tabs)
updateSelectInput(session, "tabnamesui", selected = input$tabnamesui) # keep the selection when re-rendering sidebarPanel
}
})
#New tab logic to prevent inserting same tab twice with enable/disable action button
forcecombine = function(idtab,checker) {
colnames(idtab) = colnames(checker)
rbind(idtab,checker)
}
checker<-as.data.frame("checker")
idtab<-as.data.frame("checkers")
#only allow tab entry once
observeEvent(input$append, {
idtab <- paste0(tabnamesinput())
idtab<-as.data.frame(idtab)
checkerx<-forcecombine(idtab,checker)
repeated<-length(grep(idtab,checkerx))
if(repeated==1)
{
shinyjs::disable("append")
}
else {shinyjs::enable("append")
}
})
observeEvent(tabnamesinput(), {
shinyjs::enable("append")
})
shinyjs::disable("append")
observeEvent(input$file, {
shinyjs::enable("append")
})
#Subdata section, I want to only use the data the user has selected for the new Navbar tab
output$tabsets<-renderUI({
req(userfile())
tabtable<-reactive({
lapply(tabnamesinput(), function(x)
dataTableOutput(paste0('table',x)))
})
})
subsetdata<-reactive({
list_of_subdata<-lapply(tabnamesinput(), function(x) {
as.data.table((select(filereact(),x)))
})
names(list_of_subdata)<-tabnamesinput()
return(list_of_subdata)
})
observe(
lapply(tabnamesinput(), function(x) {
output[[paste0('table',x)]] <-
renderDataTable({
subsetdata()[[x]]
})}))
}
shinyApp(ui, server)
You cannot output same ID in multiple tabs. Once you fix that, it works. You still need to define what you wish to display in each tab. I am just displaying a filtered table and a sample plot. Also, tab removal required minor tweak. Working code is shown below.
ui <- fluidPage(
useShinyjs(),
navbarPage(title = "Stackoverflow help", id = "tabs",
tabPanel("Home",
sidebarPanel(
fileInput("file", "Upload data",
accept = c(
"text/csv",
"text/comma-separated-values,text/plain",
".csv")
),
#checkboxInput("header", "Header", TRUE),
actionButton("append", "Add new tab"),
uiOutput('tabnamesui')
),
mainPanel(
)
)
)
)
server <- function(input, output, session) {
userfile <- reactive({
input$file
})
filereact <- reactive({
read.table(
file = userfile()$datapath,
sep = ',',
header = T,
stringsAsFactors = T
)
})
tabsnames <- reactive({
names(filereact())
})
output$tabnamesui <- renderUI({
req(userfile())
selectInput(
'tabnamesui',
h5('Tab names'),
choices = as.list(tabsnames()),
selected="",multiple = FALSE
)
})
tabnamesinput <- reactive({
input$tabnamesui})
#Append selected tab logic
observeEvent(input$append,{
appendTab(inputId = "tabs",
tabPanel(input$tabnamesui,
sidebarPanel(
actionButton(paste0("remove_", input$tabnamesui), "Delete")),
mainPanel(
#uiOutput("tabsets") #This is where I think something is broken
DTOutput(paste0("table",input$tabnamesui)),
plotOutput(paste0("plot",input$tabnamesui))
)
)
)
})
# Delete selected tab logic
observeEvent(lapply(grep(pattern = "^remove_", x = names(input), value = TRUE), function(x){input[[x]]}),{
if(input$tabs != "Home"){
if (input[[paste0("remove_",input$tabs)]]) { ## remove tab only if delete button has been clicked
removeTab(inputId = "tabs", target = input$tabs)
updateSelectInput(session, "tabnamesui", selected = input$tabnamesui) # keep the selection when re-rendering sidebarPanel
}
}
})
#New tab logic to prevent inserting same tab twice with enable/disable action button
forcecombine = function(idtab,checker) {
colnames(idtab) = colnames(checker)
rbind(idtab,checker)
}
checker<-as.data.frame("checker")
idtab<-as.data.frame("checkers")
#only allow tab entry once
observeEvent(input$append, {
idtab <- paste0(tabnamesinput())
idtab<-as.data.frame(idtab)
checkerx<-forcecombine(idtab,checker)
repeated<-length(grep(idtab,checkerx))
if(repeated==1)
{
shinyjs::disable("append")
}
else {shinyjs::enable("append")
}
})
observeEvent(input$tabnamesui, {
shinyjs::enable("append")
output[[paste0("plot",input$tabnamesui)]] <- renderPlot(plot(cars))
lapply(tabnamesinput(), function(x) {
df <- as.data.table(filereact()[[as.name(tabnamesinput())]])
output[[paste0('table',x)]] <- renderDT({
df
#subsetdata()[[x]]
})})
})
shinyjs::disable("append")
observeEvent(input$file, {
shinyjs::enable("append")
})
}
shinyApp(ui, server)
Try this:
library(plotly)
library(shiny)
library(DT)
ui <- fluidPage(
mainPanel(
plotlyOutput("SepalPlot"),
DT::dataTableOutput("Sepal"),
plotlyOutput("PetalPlot"),
DT::dataTableOutput("Petal")
)
)
server <- function(input, output) {
output$SepalPlot<- renderPlotly({
plot_ly(iris, x = ~Sepal.Length, y = ~Sepal.Width, type = 'scatter', mode = 'markers')
})
sep<-data.frame(c(iris$Sepal.Length, iris$Sepal.Width))
output$Sepal<-renderDataTable({datatable(sep)})
output$PetalPlot<- renderPlotly({
plot_ly(iris, x = ~Petal.Length, y = ~Petal.Width, type = 'scatter', mode = 'markers')
})
pet<-data.frame(c(iris$Petal.Length, iris$Petal.Width))
output$Petal<-renderDataTable({pet})
}
shinyApp(ui = ui, server = server)

R shiny favourites in long selectInput lists

How do I deal with long lists of options? In the example below, I have a subset of the options as favourites, but want to be able to select all options including the non-favourites. How do I get the input$selected to return what I selected last based on both the radiogroupbutton() and the selectInput()?
EDIT: I would like to keep the look, which has radiobuttons AND a drop down list. Therefore, I assume both will need different inputID's which then could be combined (somehow) in the server site (as Joris suggested). I am not sure how to combine them on the server site, and how to identify what was selected last.
ALL.options <- apply(expand.grid(LETTERS, LETTERS), 1, function(x){paste(x, collapse="")})
favourites <- sample(ALL.options, 20)
ui <- fluidPage(
h3("Favourites:"),
radioGroupButtons(inputId="selected",
choices = sort(favourites),
individual = TRUE,
selected = NULL,
width="20%"),
selectInput(inputId="selected", label = "Other options",
choices = ALL.options,
selected = NULL),
h3("THIS IS YOUR SELECTION:"),
verbatimTextOutput("choice")
)
)
server <- function(input, output) {
output$choice <- renderPrint(
input$selected
)
}
shinyApp(ui, server)
Perhaps it suffices to use a single selectInput or selectizeInput that lists the Favourites and Other options in separate option groups (see e.g. Shiny: Option groups for selectize input):
library(shiny)
ALL.options <- apply(expand.grid(LETTERS, LETTERS), 1, function(x){paste(x, collapse="")})
favourites <- sample(ALL.options, 20)
ui <- fluidPage(
selectizeInput(inputId = "selected", label = "All options", choices = list(
Favourites = favourites,
`Other options` = setdiff(ALL.options, favourites)
),
options = list(
placeholder = '<None selected>',
onInitialize = I('function() { this.setValue(""); }')
)
),
h3("THIS IS YOUR SELECTION:"),
verbatimTextOutput("choice")
)
server <- function(input, output) {
output$choice <- renderPrint({
validate(need(input$selected, "None selected"))
input$selected
})
}
shinyApp(ui, server)
NB: If you instead use two separate inputs (radioGroupButtons and selectInput) you could combine the selected choices server-side in a reactive object. For instance:
library(shiny)
library(shinyWidgets)
ALL.options <- apply(expand.grid(LETTERS, LETTERS), 1, function(x){paste(x, collapse="")})
favourites <- sample(ALL.options, 20)
ui <- fluidPage(
h3("Favourites:"),
radioGroupButtons(inputId = "radio",
choices = sort(favourites),
individual = TRUE,
selected = character(0),
width="20%"),
selectizeInput(inputId="select", label = "Other options",
choices = ALL.options,
options = list(
placeholder = '<None selected>',
onInitialize = I('function() { this.setValue(""); }')
)
),
h3("THIS IS YOUR SELECTION:"),
verbatimTextOutput("choice")
)
server <- function(input, output) {
## initialize reactive value
currentSelected <- reactiveVal(NULL)
## update based on radioGroupButtons
observeEvent(input$radio, {
currentSelected(input$radio)
})
## update based on selectInput
observeEvent(input$select, {
currentSelected(input$select)
})
output$choice <- renderPrint({
validate(need(currentSelected(), "None selected"))
currentSelected()
})
}
shinyApp(ui, server)
Created on 2019-06-17 by the reprex package (v0.3.0)
I am not sure if I understand fully what you are trying to achieve. I also notice that both the radioGroupButtons and the selectInput have the same inputId. If the idea is to print both the choices, you could change the inputId of the selectInput to say, select and just modify the renderPrint as:
output$choice <- renderPrint(
c(input$selected, input$select)
)
Is this what you are looking for?

Reactive radiobuttons depending on choice of other radionButtons

I have this shiny app where I want to use a set of radioBuottons to determine the vector of choices for another set of radioBuottons. I've tried using conditionalPanel but I cannot figure out how to bind different sets of radioBuottons to a single output entry (if that is even possible).
So I came up with defining a list for the second set of radioBuottons and try to select them depending on the choice of the first set of radioBuottons.
Here is an example of code:
ui.r:
library(shiny)
secondInput <- list(
"a" = c("one", "two", "three"),
"b" = c("four", "five")
)
shinyUI(fluidPage(
titlePanel("Test reactive RadioButtons"),
column(4,
radioButtons("input1", label = "1st input", choices = c("a","b"))),
column(4,
radioButtons("input2", label = "2nd input depend on 1st input", choices = secondInput[[input$input1]])),
column(4,
textOutput("IN1"))
))
server.r:
library(shiny)
shinyServer(function(input, output) {
out <- reactive(input$input1)
output$IN1 <- renderText(out())
})
I get an error saying that object 'input' was not found.
How can I manage this?
I think the updateRadioButtons would be better as there is no need to re-create the widget every time input1 changes
library(shiny)
secondInput <- list(
"a" = c("one", "two", "three"),
"b" = c("four", "five")
)
ui <- fluidPage(
titlePanel("Test reactive RadioButtons"),
column(4,radioButtons("input1", label = "1st input", choices = c("a","b"))),
column(4,radioButtons("input2", label = "2nd input depend on 1st input", choices = "")),
column(4,textOutput("IN1"))
)
# Define server logic
server <- function(input, output, session) {
observeEvent(input$input1,{
updateRadioButtons(session,"input2",choices = secondInput[[input$input1]])
})
out <- reactive(input$input1)
output$IN1 <- renderText(out())
}
# Run the application
shinyApp(ui = ui, server = server)
The radioButtons that you generated are not reactive. If you want to use one input to make another input or output dependent on it, you have to build the logic for that in reactive expressions in the server. You could use uiOutput and renderUI for this. A working example is given below, hope this helps!
library(shiny)
secondInput <- list(
"a" = c("one", "two", "three"),
"b" = c("four", "five")
)
ui <- fluidPage(
radioButtons("input1", label = "1st input", choices = c("a","b")),
uiOutput('radiobuttons2')
)
server <- function(input, output, session) {
output$radiobuttons2 <- renderUI({
radioButtons('input2',label='2nd input', choices = secondInput[[input$input1]])
})
}
shinyApp(ui, server)

Resources