How do I use an actionButton to delay a defined function? - r

I can see how to use actionButton to delay an output, but I haven't seen an example relevant to what I am trying to do, which is delay the start of a defined function that is called within another output.
Simplified for the MRE, let's say I have an output to create the mean of a data set. I have three ways to calculate the mean. One of those ways takes a long time though (simulated here by Method 2). Here is the way it is structured now.
How can I get algo(x) to wait until the button is pressed, then start the calculation and return the value?
library(shiny)
# Define UI
ui <- fluidPage(
# Application title
titlePanel("Old Faithful Geyser Data"),
# Sidebar with a slider input for number of bins
sidebarLayout(
sidebarPanel(
sliderInput("bins",
"Number of bins:",
min = 1,
max = 50,
value = 30),
radioButtons(inputId = "calc_t",label = "Select Calculation",choices = c("Method 1"=1,"Method 2 (long)"=2,"Method 3"=3)),
actionButton(inputId = "go_algo",label = "Start Algo")
),
# Show a plot of the generated distribution
mainPanel(
plotOutput("distPlot"),
textOutput("analyze")
)
)
)
# Define server logic required to draw a histogram
server <- function(input, output) {
output$distPlot <- renderPlot({
# generate bins based on input$bins from ui.R
x <- faithful[, 2]
bins <- seq(min(x), max(x), length.out = input$bins + 1)
# draw the histogram with the specified number of bins
hist(x, breaks = bins, col = 'darkgray', border = 'white',
xlab = 'Waiting time to next eruption (in mins)',
main = 'Histogram of waiting times')
})
output$analyze <- renderText({
calc_type<-input$calc_t
x <- faithful[, 2]
if(calc_type==1){
output<-paste("Mean 1 = ",mean(x))
} else if (calc_type==2){
output<-paste("Mean 2 = ",algo(x))
} else if(calc_type==3){
output<-paste("Mean 3 = ",sum(x)/length(x))
}
})
algo<-function(x){
mean_x<-mean(x)
#stuff that would take a long time
output<-mean_x+100
return(output)
}
}
# Run the application
shinyApp(ui = ui, server = server)

I would suggest using an observeEvent for the action button for the function that needs to wait for the button. For this observeEvent a req is required to limit the button to work only for this choice. Then you can use another observeEvent for the the other choices and again limit what is allowed to run without a button click with req.
Here's the updated server code:
server <- function(input, output) {
output$distPlot <- renderPlot({
# generate bins based on input$bins from ui.R
x <- faithful[, 2]
bins <- seq(min(x), max(x), length.out = input$bins + 1)
# draw the histogram with the specified number of bins
hist(x, breaks = bins, col = 'darkgray', border = 'white',
xlab = 'Waiting time to next eruption (in mins)',
main = 'Histogram of waiting times')
})
observeEvent(input$calc_t, {
req(input$calc_t!=2)
output$analyze <- renderText({
calc_type<-input$calc_t
x <- faithful[, 2]
if(calc_type==1){
output<-paste("Mean 1 = ",mean(x))
} else if(calc_type==3){
output<-paste("Mean 3 = ",sum(x)/length(x))
}
})
})
observeEvent(input$go_algo, {
req(input$calc_t==2)
output$analyze <- renderText({
isolate(calc_type<-input$calc_t)
x <- faithful[, 2]
output<-paste("Mean 2 = ",algo(x))
})
})
algo<-function(x){
mean_x<-mean(x)
#stuff that would take a long time
output<-mean_x+100
return(output)
}
}

Related

How can I trigger an output when a value changes in a different output?

I have an output that takes user input to select which of a number of calculations to use and results in 5 numbers. That output pushes out the results of this and other calculations as an HTML table. The individual calculations are not particularly complicated, but user selections choose which of many approaches they are using, so I don't really want to replicate all that code in other outputs that are going to use just those 5 numbers.
My thought was to use the double-arrow to make those numbers available to the other outputs (in my case some plots). My goal is to generate graphs from numbers already generated in a different output, however that gets accomplished. I am not attached to the approach below, it is just where I am right now.
I ran into a number of problems just using <<- and tried a lot of things to get it to work. I won't complicate this further with all the things I tried and the problems they created.
The MRE below replicates this by calculating a number in one output that is then to be used in another output. If you enter different numbers of bins, the second output is never triggered to update to the new number. For this MRE I could of course directly use the user input to calculate that number but that is what I am trying to avoid in the real app. I also don't want to use a "Go!" button if I can avoid it since part of the fun is watching how things change in response to your various selections.
# Define UI for application that draws a histogram
ui <- fluidPage(
# Application title
titlePanel("Old Faithful Geyser Data"),
# Sidebar with a slider input for number of bins
sidebarLayout(
sidebarPanel(
numericInput("bins",
"Number of bins:",
min = 1,
max = 50,
value = 30)
),
# Show a plot of the generated distribution
mainPanel(
plotOutput("distPlot"),
textOutput("binnum")
)
)
)
# Define server logic required to draw a histogram
server <- function(input, output) {
a_number<-0
output$distPlot <- renderPlot({
# generate bins based on input$bins from ui.R
x <- faithful[, 2]
bins <- seq(min(x), max(x), length.out = input$bins + 1)
a_number<<-bins[2]/5}
# draw the histogram with the specified number of bins
hist(x, breaks = bins, col = 'darkgray', border = 'white')
})
output$binnum<-renderText({
a_number
})
}
# Run the application
shinyApp(ui = ui, server = server)
Could you just treat bins and a_number as reactive?
# Define UI for application that draws a histogram
ui <- fluidPage(
# Application title
titlePanel("Old Faithful Geyser Data"),
# Sidebar with a slider input for number of bins
sidebarLayout(
sidebarPanel(
numericInput("bins",
"Number of bins:",
min = 1,
max = 50,
value = 30)
),
# Show a plot of the generated distribution
mainPanel(
plotOutput("distPlot"),
textOutput("binnum")
)
)
)
# Define server logic required to draw a histogram
server <- function(input, output) {
# a_number<-0
# generate bins based on input$bins from ui.R
data(faithful)
x <- faithful[, 2]
bins <- reactive({
seq(min(x), max(x), length.out = input$bins + 1)
})
a_number <- reactive({
req(bins())
-bins()[2]/5
})
output$distPlot <- renderPlot({
# draw the histogram with the specified number of bins
hist(x, breaks = bins(), col = 'darkgray', border = 'white', xlab = paste0("a = ", -bins()[2]/5))
})
output$binnum<-renderText({
a_number()
})
}
# Run the application
shinyApp(ui = ui, server = server)

How do I add plus and minus arrows to sliderInput() in shiny?

I am developing a shiny app and want to improve the accuracy of the slider (the slider ranges from 0 to 1000 and it's very difficult to accurately adjust the slider with a step of 1). I can't find an answer to this anywhere.
This is the code for one of my sliders:
sliderInput("mean2", "", min=0, max=1000, value=500, step=1)
Try arranging your code like such:
library(shiny)
ui <- fluidPage(
# Application title
titlePanel("Old Faithful Geyser Data"),
actionButton("minus", "Minus"),
actionButton("plus", "Plus"),
# Sidebar with a slider input for number of bins
sidebarLayout(
sidebarPanel(
sliderInput("mean2",
"Number of bins:",
min = 0,
max = 1000,
value = 500,
step= 1)
),
# Show a plot of the generated distribution
mainPanel(
plotOutput("distPlot")
)
)
)
server <- function(input, output, session) {
v <- reactiveValues(data = 500)
observeEvent(input$minus, {
v$data <- input$mean2 - 1
updateSliderInput(session,"mean2", value = input$mean2 - 1)
})
observeEvent(input$plus, {
v$data <- input$mean2 + 1
updateSliderInput(session,"mean2", value = input$mean2 + 1)
})
observeEvent(input$mean2, {
v$data <- input$mean2
})
output$distPlot <- renderPlot({
# generate bins based on input$bins from ui.R
x <- faithful[, 2]
bins <- seq(min(x), max(x), length.out = v$data + 1)
# draw the histogram with the specified number of bins
hist(x, breaks = bins, col = 'darkgray', border = 'white')
})
}
shinyApp(ui, server)

Counter that increments each second and updates a plot, in R Shiny

I'm trying to create a timed counter within a Shiny app. When it increments each second, it should refresh a plot with some new characteristic that depends on the counter. Here's an example based on the 'Old Faithful' app. It doesn't work, but it gets at the idea. I tried to have reactiveTimer() refresh the plot, and a counter recorded with reactiveValues().
server.R
library(shiny)
shinyServer(function(input, output) {
refreshPlot <- reactiveTimer(intervalMs = 1000)
vals <- reactiveValues(counter = 0)
output$distPlot <- renderPlot({
refreshPlot()
vals$counter <- isolate(vals$counter) + 1
# generate bins based on input$bins from ui.R
x <- faithful[, 2]
n_bins <- input$bins + vals$counter
bins <- seq(min(x), max(x), length.out = n_bins)
# draw the histogram with the specified number of bins
hist(x, breaks = bins, col = 'darkgray', border = 'white')
})
})
ui.R
library(shiny)
shinyUI(fluidPage(
# Application title
titlePanel("Old Faithful Geyser Data"),
# Sidebar with a slider input for number of bins
sidebarLayout(
sidebarPanel(
sliderInput("bins",
"Number of bins:",
min = 1,
max = 50,
value = 30)
),
# Show a plot of the generated distribution
mainPanel(
plotOutput("distPlot")
)
)
invalidateLater is what I'm looking for. Thanks, Dieter. Below is the server.R that works.
library(shiny)
shinyServer(function(input, output, session) {
vals <- reactiveValues(counter = 0)
output$distPlot <- renderPlot({
invalidateLater(millis = 1000, session)
vals$counter <- isolate(vals$counter) + 1
# generate bins based on input$bins from ui.R
x <- faithful[, 2]
n_bins <- input$bins + vals$counter
bins <- seq(min(x), max(x), length.out = n_bins)
# draw the histogram with the specified number of bins
hist(x, breaks = bins, col = 'darkgray', border = 'white')
})
})

Few panels within the sidebarPanel in shiny

I am building my first app in shiny. The problem to solve is like this.
I've ui
shinyUI(fluidPage(
# Application title
titlePanel("My"),
# Sidebar with a slider input for number of bins
sidebarLayout(
sidebarPanel("Variables",
sliderInput("bins",
"Number of circles:",
min = 1,
max = 50,
value = 30),
sliderInput("bins",
"Number of triangels:",
min = 1,
max = 50,
value = 1)
),
# Show a plot of the generated distribution
mainPanel(tabsetPanel(
tabPanel("Data", plotOutput("distPlot")),
tabPanel("Data1", textOutput("text1")),
tabPanel("Data2", plotOutput("distPlot1")))
)
)
))
and server
shinyServer(function(input, output) {
output$distPlot <- renderPlot({
# generate bins based on input$bins from ui.R
x <- faithful[, 2]
bins <- seq(min(x), max(x), length.out = input$bins + 1)
# draw the histogram with the specified number of bins
hist(x, breaks = bins, col = 'darkgray', border = 'white')
})
output$distPlot1 <- renderPlot({
x <- faithful[, 2]
plot(density(x))
})
output$text1 <- renderText({
"Hello mother"
})
})
The question concern ui part. I'd like to fave 2 panels in the sidebarPanel - triangles and circles, similar to that what is in the mainPanel i.e. Data, Data1, Data2.
Thanks for the comments!

Shiny: Passing on text with a space to chart does not work, but it works without a space

My Shiny script gets input from a drop down list. Based on this, I set (on the server side) a specific string (in a reactive) that should be displayed in the chart (for example as x axis title). This works only if the string contains no spaces, but no string is shown in the chart if contains spaces.
How can I get it to accept any string?
Here's my code (I modified one of the example from the Shiny tutorial to keep it as simple as possible):
# server.r
# Here the string is set depending on what was chosen by the user
shinyServer(function(input, output, session) {
label1_new <- reactive({
if (input$variable1=="pp_pmw") {label1_new <- "PP pmw"}
if (input$variable1=="perc_pp*100") {label1_new <- "PP percent"}
if (input$variable1=="formality") {label1_new <- "Formality"}
})
label1_new2 <- renderText({label1_new()})
output$distPlot <- renderPlot({
x <- faithful[, 2] # Old Faithful Geyser data
bins <- seq(min(x), max(x), length.out = input$bins + 1)
# draw the histogram with the specified number of bins
# xlabel1_new2() contains the string from above
hist(x, breaks = bins, col = 'darkgray', border = 'white', xlab=label1_new2())
})
})
# ui.r
library(shiny)
shinyUI(fluidPage(
# Application title
titlePanel("Hello Shiny!"),
# Sidebar with a slider input for the number of bins
sidebarLayout(
sidebarPanel(
selectInput("variable1", "Circle size:",
list("PP pmw" = "pp_pmw",
"PP percent" = "perc_pp*100",
"Formality" = "formality")),
sliderInput("bins",
"Number of bins:",
min = 1,
max = 50,
value = 30)
),
# Show a plot of the generated distribution
mainPanel(
plotOutput("distPlot")
)
)
))
renderText is for use with ui.r, not for creating strings to be used in server.r
# server.r
# Here the string is set depending on what was chosen by the user
shinyServer(function(input, output, session) {
label1_new <- reactive({
if (input$variable1=="pp_pmw") return("PP pmw")
if (input$variable1=="perc_pp*100") return("PP percent")
if (input$variable1=="formality") return("Formality")
})
output$distPlot <- renderPlot({
x <- as.numeric(unlist(faithful[, 2])) # Old Faithful Geyser data
bins <- seq(min(x), max(x), length.out = input$bins + 1)
# draw the histogram with the specified number of bins
hist(x, breaks = bins, col = 'darkgray', border = 'white', xlab=label1_new())
})
})
(same ui.r)

Resources