Shiny: How to make reactive value initialize with default value - r

Consider the following actionButton demo:
http://shiny.rstudio.com/gallery/actionbutton-demo.html
server.R:
shinyServer(function(input, output) {
# builds a reactive expression that only invalidates
# when the value of input$goButton becomes out of date
# (i.e., when the button is pressed)
ntext <- eventReactive(input$goButton, {
input$n
})
output$nText <- renderText({
ntext()
})
})
ui.R:
shinyUI(pageWithSidebar(
headerPanel("actionButton test"),
sidebarPanel(
numericInput("n", "N:", min = 0, max = 100, value = 50),
br(),
actionButton("goButton", "Go!"),
p("Click the button to update the value displayed in the main panel.")
),
mainPanel(
verbatimTextOutput("nText")
)
))
In this example, prior to the action button being pressed, the right-hand side panel is empty. I would instead like the text with default value "50" to be rendered by default.
How to I get the output to display with default inputs if the action button has not yet been pressed?

eventReactive also takes ignoreNULL as documented here, which lets you initialise the object without an if statement.
By adding the ,ignoreNULL = FALSE to the original post (give or take some formatting), verbatimTextOutput shows 50 on startup.
This makes for a bit of economy on the server side I guess.
ui <- fluidPage(titlePanel("actionButton test"),
sidebarLayout(
sidebarPanel(
numericInput(
"n",
"N:",
min = 0,
max = 100,
value = 50
),
br(),
actionButton("goButton", "Go!"),
p("Click the button to update the value displayed in the main panel.")
),
mainPanel(verbatimTextOutput("nText"))
))
server <- function(input, output) {
ntext <- eventReactive(input$goButton, {
input$n
}
# Adding this parameter to the original example makes it work as intended
# with 50 in the output field to begin with
, ignoreNULL = FALSE
)
output$nText <- renderText({
ntext()
})
}
shinyApp(ui = ui, server = server)

shinyServer(function(input, output) {
values <- reactiveValues(default = 0)
observeEvent(input$goButton,{
values$default <- input$goButton
})
# builds a reactive expression that only invalidates
# when the value of input$goButton becomes out of date
# (i.e., when the button is pressed)
ntext <- eventReactive(input$goButton, {
input$n
})
output$nText <- renderText({
if(values$default == 0){
50
}
else{
ntext()
}
})
})

Related

How to build a shiny app that shows the output ONLY when the user clicks a click button?

I want to build a simple shiny app, that takes a number input$number and prints this number only when the user clicks (input$click).
So far, I have tried this:
library(shiny)
ui = fluidPage(
sliderInput("number", "number", value = 10, min = 0, max = 50),
actionButton("click", "Change output"),
textOutput("text")
)
server = function(input, output, session) {
observeEvent(input$click, {
output$text = renderText({
print(input$number)
})
})
}
shinyApp(ui, server)
When the app launches for the first time, it waits for the user to click before it shows the output text. However, after clicking for the first time, the app does not care if you click or not, it will automatically show the chosen number with slider.
What am I missing?
You can use isolate to prevent reactivity
library(shiny)
ui = fluidPage(
sliderInput("number", "number", value = 10, min = 0, max = 50),
actionButton("click", "Change output"),
textOutput("text")
)
server = function(input, output, session) {
output$text = renderText({
input$click
req(input$click) #to prevent print at first lauch
isolate(print(input$number))
})
}
shinyApp(ui, server)
An alternative that I find helpful is to store values in a reactiveValues list and then update them using event observers.
library(shiny)
SLIDER_INIT <- 10
ui = fluidPage(
sliderInput("number", "number", value = SLIDER_INIT, min = 0, max = 50),
actionButton("click", "Change output"),
textOutput("text")
)
server = function(input, output, session) {
# Store values that will need to be displayed to the user here.
AppValues <- reactiveValues(
slider_number = 10
)
# Change reactive values only when an event occurs.
observeEvent(
input$click,
{
AppValues$slider_number <- input$number
}
)
# Display the current value for the user.
output$text = renderText({
AppValues$slider_number
})
}
shinyApp(ui, server)

How to to update data by clicking actionButton in R in runtime

I want to update output data on update button every time.
Here is my code which show the output on update button for the first time I run the code but in runtime if the input is changed, the output is updated automatically.
library(shiny)
ui <- fluidPage(
titlePanel("My Shop App"),
sidebarLayout(
sidebarPanel(
helpText("Controls for my app"),
selectInput("item",
label = "Choose an item",
choices = list("Keyboard",
"Mouse",
"USB",
sliderInput("price",
label = "Set Price:",
min=0, max = 100, value=10),
actionButton ("update","Update Price")
),
mainPanel(
helpText("Selected Item:"),
verbatimTextOutput("item"),
helpText("Price"),
verbatimTextOutput("price")
)
)
)
server <- function(input, output) {
SelectInput <- eventReactive (input$update , {
output$item = renderText(input$item)
output$price = renderText(input$price)
})
output$item <- renderText(SelectInput())
output$price <- renderText(SelectInput())
}
shinyApp(ui = ui, server = server)
Either create a dependency and put them into the reactive and return it:
server <- function(input, output) {
SelectInput <- eventReactive(input$update,{
list(item = input$item, price = input$price)
})
output$item <- renderText(SelectInput()$item)
output$price <- renderText(SelectInput()$price)
}
Or you can isolate, but then you have to add the button reaction to each listener
server <- function(input, output) {
output$item <- renderText({
req(input$update)
input$update
isolate(input$item)
})
output$price <- renderText({
req(input$update)
input$update
isolate(input$price)
})
}

R Shiny: refreshing/overriding actionButton() output

I am trying to adapt R Shiny: automatically refreshing a main panel without using a refresh button to a new minimal working example:
ui <- fluidPage(
pageWithSidebar(
headerPanel("actionButton test"),
sidebarPanel(
numericInput("n", "N:", min = 0, max = 100, value = 50),
br(),
actionButton("goButton", "Go!"),
p("Click the button to update the value displayed in the main panel."),
actionButton("newButton", "New Button"),
actionButton("newButton2", "Another New Button")
),
mainPanel(
verbatimTextOutput("nText"),
textOutput("some_text_description"),
plotOutput("some_plot")
)
)
)
server <- function(input, output, session) {
# builds a reactive expression that only invalidates
# when the value of input$goButton becomes out of date
# (i.e., when the button is pressed)
ntext <- eventReactive(input$goButton, {
input$n
})
output$nText <- renderText({
ntext()
})
# Prep some text for output
output$some_text_description <- renderText({
if (input$newButton == 0) {return(NULL)}
else {
"Lorem ipsum dolorom."
}
})
# Prep some figure for output
# Simple Bar Plot
output$some_plot <- renderPlot({
if (input$newButton2 == 0) {return(NULL)}
else {
counts <- table(mtcars$gear)
barplot(counts, main="Car Distribution", xlab="Number of Gears")
}
})
}
shinyApp(ui = ui, server = server)
In the code above, I have three actionButton commands, one which produces a plot, one which produces text output, and one which produces a number (as verbatim text output). As you click through each button, new output appears alongside previously generated output (from the last button you pressed).
Without needing to implement a refresh button that clears everything manually, how do I get each actionButton to override (i.e., wipe) the output of the others automatically without them all stacking atop of each other in the main panel. My understanding is that I need to use some combination of observeEvent, NULL, and reactiveValues but my attempts have so far been unsuccessful.
You can use renderUI() for that.
output$all <- renderUI({
global$out
})
Within a global reactiveValue global$out you can store which ui element you would like to display. (Initially it should be empty, therefore NULL).
global <- reactiveValues(out = NULL)
And then listen for the clicks in the Buttons and update global$out accordingly.
observeEvent(input$goButton, {
global$out <- verbatimTextOutput("nText")
})
observeEvent(input$newButton, {
global$out <- textOutput("some_text_description")
})
observeEvent(input$newButton2, {
global$out <- plotOutput("some_plot")
})
Full app would read:
library(shiny)
ui <- fluidPage(
pageWithSidebar(
headerPanel("actionButton test"),
sidebarPanel(
numericInput("n", "N:", min = 0, max = 100, value = 50),
br(),
actionButton("goButton", "Go!"),
p("Click the button to update the value displayed in the main panel."),
actionButton("newButton", "New Button"),
actionButton("newButton2", "Another New Button")
),
mainPanel(
uiOutput("all")
)
)
)
server <- function(input, output, session) {
global <- reactiveValues(out = NULL)
observeEvent(input$goButton, {
global$out <- verbatimTextOutput("nText")
})
observeEvent(input$newButton, {
global$out <- textOutput("some_text_description")
})
observeEvent(input$newButton2, {
global$out <- plotOutput("some_plot")
})
output$all <- renderUI({
global$out
})
output$nText <- renderText({
input$n
})
output$some_text_description <- renderText({
"Lorem ipsum dolorom."
})
# Simple Bar Plot
output$some_plot <- renderPlot({
counts <- table(mtcars$gear)
barplot(counts, main="Car Distribution", xlab="Number of Gears")
})
}
shinyApp(ui = ui, server = server)

Update a variable with input data

I'm trying to append a value taken from an input (in the present case input$n) to a list (in the present case the variable "keyword_list"), when the user presses the an action button (in the present case the button input$goButton).
ui.R
library(shiny)
pageWithSidebar(
headerPanel("actionButton test"),
sidebarPanel(
#numericInput("n", "N:", min = 0, max = 100, value = 50),
textInput("n", "Caption", "Enter next keyword"),
br(),
actionButton("goButton", "Go!"),
p("Click the button to update the value displayed in the main panel.")
),
mainPanel(
verbatimTextOutput("nText"),
dataTableOutput('mytable')
)
)
})
server.R
library(shiny)
# Define server logic required to summarize and view the selected
# dataset
function(input, output,session) {
#prepare data
keyword_list <- matrix()
makeReactiveBinding('keyword_list')
observe({
if (input$goButton == 0)
return()
isolate({
keyword_list <- append(keyword_list,input$n) })
})
ntext <- eventReactive(input$goButton, {
input$n
})
output$nText <- renderPrint({
#input$n
ntext()
})
output$mytable = renderDataTable({
as.data.frame(keyword_list)
})
}
How about this:
library(shiny)
ui <- pageWithSidebar(
headerPanel("actionButton test"),
sidebarPanel(
#numericInput("n", "N:", min = 0, max = 100, value = 50),
textInput("n", "Caption", "Enter next keyword"),
br(),
actionButton("goButton", "Go!"),
p("Click the button to update the value displayed in the main panel.")
),
mainPanel(
verbatimTextOutput("nText"),
dataTableOutput('mytable')
)
)
})
library(shiny)
# Define server logic required to summarize and view the selected
# dataset
server <- function(input, output,session) {
global <- reactiveValues(keyword_list = "")
observe({
if (input$goButton == 0)
return()
isolate({
global$keyword_list <- append(global$keyword_list, input$n)
})
})
ntext <- eventReactive(input$goButton, {
input$n
})
output$nText <- renderPrint({
#input$n
ntext()
})
output$mytable = renderDataTable({
as.data.frame(global$keyword_list)
})
}
shinyApp(ui, server)

Dynamically add UI elements and gather their input in a dataframe in shiny

My ui.R function is as shown below.
library(shiny)
shinyUI(pageWithSidebar(
headerPanel("Add Features"),
sidebarPanel(width=4,
fluidRow(
column(6, selectInput("features", label = h3("Features"),
choices = list("Feature1","Feature2","Feature3"), selected = "Feature1")),
br(),
br(),
column(6, numericInput("n", label="",min = 0, max = 100, value = 50)),
br(),
column(2, actionButton("goButton", "Add!"))
#column(3, submitButton(text="Analyze"))
)),
mainPanel(
verbatimTextOutput("nText"),
textOutput("text2")
)
))
My server.R function is as below:
library(shiny)
shinyServer(function(input, output) {
selFeatures <- data.frame()
valFeatures <- data.frame()
# builds a reactive expression that only invalidates
# when the value of input$goButton becomes out of date
# (i.e., when the button is pressed)
ntext <- eventReactive(input$goButton, {
selFeatures <- rbind(selFeatures,input$features)
valFeatures <- rbind(valFeatures,input$n)
paste("The variables are",input$features,input$n)
paste("The variables are",selFeatures,valFeatures)
})
output$nText <- renderText({
ntext()
})
output$text2 <- renderText({
paste("You have selected", input$features)
})
})
What I want to do is ask user to input some variables. Here Feature1, Feature2, and Feature3. User has to input Feature1 but Feature2 and Feature3 are optional. So, here user selects a feature, inputs its value in numericInput and presses button Add. When Add is pressed after selecting Feature1, user can select to submit the form or add features 2 and 3 using the add button. I finally, want to use these three variables to learn a prediction model. How can I collect all the imputed information in the dataframe to process it. Also, if possible to remove Feature1 from the selectBox after it has been added. I want my UI to look like the following before Pressing the add button
and it should look like the following after pressing the add button.
The feature1 here need not be in the select box, just a way to display that it has been added is fine.
I wasn't quite sure why you wanted to use selectInputs for setting the variable values so here's a general example on how to access inputs from dynamically generated content:
library(shiny)
ui <- shinyUI(pageWithSidebar(
headerPanel("Add Features"),
sidebarPanel(width=4,
fluidRow(column(12,
h3('Features'),
uiOutput('uiOutpt')
)), # END fluidRow
fluidRow(
column(4,div()),
column(4,actionButton("add", "Add!")),
column(4,actionButton('goButton',"Analyze"))
) # END fluidRow
), # END sidebarPanel
mainPanel(
verbatimTextOutput("nText"),
textOutput("text2"),
tableOutput('tbl')
)
))
server <- shinyServer(function(input, output) {
features <- reactiveValues(renderd=c(1))
ntext <- eventReactive(input$goButton, {
out <- lapply(features$renderd,function(i){
fv <- paste0('numInp_',i)
vn <- paste0('Feature',i)
# Get input values by namw
sprintf( 'Variable: %s, Value: %5.3f',input[[vn]],input[[fv]] )
})
do.call(paste,c(out,sep="\n"))
})
df <- eventReactive(input$goButton, {
out <- lapply(features$renderd,function(i){
fv <- paste0('numInp_',i)
vn <- paste0('Feature',i)
data.frame(Variable=input[[vn]], Value=input[[fv]] )
})
do.call(rbind,out)
})
output$nText <- renderText({
ntext()
})
output$text2 <- renderText({
sprintf("You have selected feature: %s", paste(features$renderd,collapse=", "))
})
output$tbl <- renderTable({
df()
})
# Increment reactive values used to store how may rows we have rendered
observeEvent(input$add,{
if (max(features$renderd) > 2) return(NULL)
features$renderd <- c(features$renderd, max(features$renderd)+1)
})
# If reactive vector updated we render the UI again
observe({
output$uiOutpt <- renderUI({
# Create rows
rows <- lapply(features$renderd,function(i){
fluidRow(
column(6, selectInput(paste0('Feature',i),
label = "",
choices = list("Feature1","Feature2","Feature3"),
selected = paste0('Feature',i))),
column(6, numericInput(paste0('numInp_',i), label="",min = 0, max = 100, value = runif(1,max=100)))
)
})
do.call(shiny::tagList,rows)
})
})
})
shinyApp(ui=ui,server=server)
I'm simply storing the ID's of the dynamically generated content in a vector that helps me keep track of what I've generated. To access the values i simply reconstruct the elements ID from the numbers stored in the vector.
Oskar's answer was very useful to me for a similar challenge I faced; for unlimited features, I figured out how to enable a "remove" button and to keep values when pressing the "add" button. For posterity, here are my modifications to Oskar's code:
library(shiny)
ui <- shinyUI(pageWithSidebar(
headerPanel("Add Features"),
sidebarPanel(width=4,
fluidRow(column(12,
h3('Features'),
uiOutput('uiOutpt')
)), # END fluidRow
fluidRow(
column(4,div()),
column(4,actionButton("add", "Add!")),
column(4,actionButton("remove", "Remove!")),
column(4,actionButton('goButton',"Analyze"))
) # END fluidRow
), # END sidebarPanel
mainPanel(
textOutput("text2"),
tableOutput('tbl')
)
))
server <- shinyServer(function(input, output) {
features <- reactiveValues(renderd=c(1),
conv=c(50),
inlabels=c('A'),
outlabels=c('B'))
df <- eventReactive(input$goButton, {
out <- lapply(features$renderd,function(i){
fv <- paste0('numInp_',i)
vn <- paste0('InLabel',i)
data.frame(Variable=input[[vn]], Value=input[[fv]] )
})
do.call(rbind,out)
})
output$nText <- renderText({
ntext()
})
output$text2 <- renderText({
paste(sprintf("You have selected feature: %s", paste(features$renderd,collapse=", ")))
})
output$tbl <- renderTable({
df()
})
# Increment reactive values array used to store how may rows we have rendered
observeEvent(input$add,{
out <- lapply(features$renderd,function(i){
fv <- paste0('numInp_',i)
vn <- paste0('InLabel',i)
vo <- paste0('OutLabel',i)
data.frame(inlabels=input[[vn]],outlabels=input[[vo]], conv=input[[fv]] )
})
df<-do.call(rbind,out)
print(df)
features$inlabels <- c(as.character(df$inlabels),' ')
features$outlabels <- c(as.character(df$outlabels),' ')
print(c(features$inlabels,features$outlabels))
features$renderd <- c(features$renderd, length(features$renderd)+1)
print(features$renderd)
print(names(features))
features$conv<-c(df$conv,51-length(features$renderd))
})
observeEvent(input$remove,{
features$renderd <- features$renderd[-length(features$renderd)]
})
# If reactive vector updated we render the UI again
observe({
output$uiOutpt <- renderUI({
# Create rows
rows <- lapply(features$renderd,function(i){
fluidRow(
# duplicate choices make selectize poop the bed, use unique():
column(4, selectizeInput(paste0('InLabel',i),
label = 'Input Name',selected=features$inlabels[i],
choices=unique(c(features$inlabels[i],features$outlabels[!features$outlabels %in% features$inlabels])),
options = list(create = TRUE))),
column(4, sliderInput(paste0('numInp_',i), label="Conversion",min = 0, max = 100, value = features$conv[i])),
column(4, selectizeInput(paste0('OutLabel',i),
label = "Output Name", selected=features$outlabels[i],
choices=unique(c(features$inlabels,features$outlabels)),
options = list(create = TRUE)))
)
})
do.call(shiny::tagList,rows)
})
})
})
shinyApp(ui=ui,server=server)

Resources