How can I pass additional arguments to a reactive context in Shiny? The purpose is to handover the arguments to the reactive context ("callback") when it is evaluated.
Think of the following Shiny server code. How can I make output$some print "some", output$different print "different" and so on?
for(i in c("some","different","values"){
output[[i]] <- renderText({
# i gets evaluated at some later point in time,
# and thus will always print "values"
i
})
}
The example below is intended to make the two render contexts reactive to the corresponding reactive value text1 and text2, but of course it only makes both depend on text2.
library(shiny)
ui <- fluidPage(
titlePanel("Test"),
sidebarLayout(
sidebarPanel(
),
mainPanel(
htmlOutput("text1"),
textOutput("text2"),
actionButton("test_btn1",label="test1"),
actionButton("test_btn2",label="test2")
)
)
)
server <- function(input, output) {
rv <- reactiveValues(
"text1"=NULL,
"text2"=NULL
)
bindings <- list(
list("var"="text1",
"function"=renderUI),
list("var"="text2",
"function"=renderText)
)
for(i in bindings){
output[[i[["var"]]]] <- i[["function"]]({
# i is always the second element unfortunately
rv[[i[["var"]]]]
})
}
observeEvent(input$test_btn1,{
rv$text1 <- tags$p("new value 1")
})
observeEvent(input$test_btn2,{
rv$text2 <- "new value 2"
})
}
shinyApp(ui = ui, server = server)
Try Map() instead of the for loop so the function gets called through each iteration:
library(shiny)
ui <- fluidPage(
titlePanel("Test"),
sidebarLayout(
sidebarPanel(
),
mainPanel(
htmlOutput("text1"),
textOutput("text2"),
actionButton("test_btn1",label="test1"),
actionButton("test_btn2",label="test2")
)
)
)
server <- function(input, output) {
rv <- reactiveValues(
"text1"=NULL,
"text2"=NULL
)
bindings <- list(
list("var"="text1",
"function"=renderUI),
list("var"="text2",
"function"=renderText)
)
Map(function(i){
output[[bindings[[i]][["var"]]]] <- bindings[[i]][["function"]]({
# i is always the second element unfortunately
rv[[bindings[[i]][["var"]]]]
})
}, 1:2)
observeEvent(input$test_btn1,{
rv$text1 <- "new value 1"
})
observeEvent(input$test_btn2,{
rv$text2 <- "new value 2"
})
}
shinyApp(ui = ui, server = server)
Related
Shiny newbie here, struggling with a trivial problem.
Goal: Build a list of names from user input. Each time the user enters a name and clicks Save, append that name to a character vector of names, and update the output with the new contents of that vector.
Problem: Every time they click Save, the character vector has been reinitialized to an empty vector, so the first name is gone, and the new name they entered becomes the only contents of the vector.
ui <- fluidPage(
fluidRow(
textInput("name", "Name:"),
actionButton("btnSave", "Save")
),
fluidRow(
h5("Output:"),
verbatimTextOutput("out")
)
)
server <- function(input, output, session) {
nameList <- as.character(NULL)
observeEvent(input$btnSave, {
newList <- append(nameList, isolate(input$name))
nameList <- reactive(newList)
output$out <- renderPrint(nameList())
})
}
library(shiny)
ui <- fluidPage(
fluidRow(
textInput("name", "Name:"),
actionButton("btnSave", "Save")
),
fluidRow(
h5("Output:"),
verbatimTextOutput("out")
)
)
server <- function(input, output, session) {
nameList <- reactiveVal()
observeEvent(input$btnSave, {
nameList(append(nameList(), input$name))
})
output$out <- renderPrint(nameList())
}
shinyApp(ui = ui, server = server)
It looks like you need to have 2 things:
rename newList to nameList.
Within observeEvent give nameList a global assignment (<<-)
ui <- fluidPage(
fluidRow(
textInput("name", "Name:"),
actionButton("btnSave", "Save")
),
fluidRow(
h5("Output:"),
verbatimTextOutput("out")
)
)
server <- function(input, output, session) {
nameList <- as.character(NULL)
observeEvent(input$btnSave, {
nameList <<- append(nameList, isolate(input$name))
nameListReactive <- reactive(nameList)
output$out <- renderPrint(nameListReactive())
})
}
shiny::shinyApp(ui,server)
I want to be able to design a set of UI that can call R's built-in functions, but the current problem lies in the data selection when calling the function. I need to return the calculation result of a function to my UI interface so that another function can be arbitrary Select the variables in the current environment as the input of the function. This is my current code. Can anyone give me some suggestions or some cases?
library(shiny)
function_choose = c("sin","cos")
ui <- fluidPage(
selectInput('f', 'function_choose', function_choose,
selected = function_choose[[1]]),
sidebarPanel(
conditionalPanel(condition = "input.f=='sin'",
mainPanel(
selectInput('sin_dat','data',c("I want to show all the variables in the workspace here ")),
actionButton(inputId = "sin_run",label = "RUN")
)
),
conditionalPanel(condition = "input.f=='cos'",
mainPanel(
selectInput('workspace','data',c("I want to show all the variables in the workspace here "))),
actionButton(inputId = "cos_run",label = "RUN")
)
),
mainPanel(
textOutput("text")
)
)
server <- function(input, output,session) {
data <- c(0.1,0.2,0.3)
observeEvent(input$sin_run,{
data_sined <- sin(data)
output$text <- renderText({
"data_sined is created"
})
})
observeEvent(input$cos_run,{
data_cosed<- cos(data)
output$text <- renderText({
"data_cosed is created"
})
})
}
shinyApp(ui = ui, server = server)
I changed the logic of your app to make it less complicated, I hope this is still ok for your purpose. We can use ls() to get a character vector of all variables in the global (or any other) environment. If we define a vector function_choose in the global environment, then this will be available too. We could easily circumvent this by defining the choices argument inside selectInput or by specifying a names pattern that is selected by ls(). Once we have selected a variable, the input$data returns a character vector. To access the underyling data based on a character vector we use get().
library(shiny)
function_choose = c("sin","cos")
shinyApp(
ui = fluidPage(
sidebarPanel(
selectInput('f', 'function_choose', choices = function_choose,
selected = function_choose[1]),
selectInput('data','data', choices = ls()),
actionButton(inputId = "run",label = "RUN")
),
mainPanel(
textOutput("text")
)
),
server = function(input, output,session) {
res <- eventReactive(input$run, {
dat <- get(input$data)
switch(input$f,
sin = sin(dat),
cos = cos(dat)
)
})
output$text <- renderText({
res()
})
})
I want to generate a boxPlus around my DT-Output. Now when I start my APP, the frame of the box is already there. How do I manage that the box is only displayed when the tableoutput is finished? As input I use a text input.
In my UI I use for the Input:
textInput("name", "Insert Number:")
the final box I create with:
uiOutput("box")
On Serverside I do:
output$name <- renderText(input$name)
New_input <- reactive({
list(input$name)
})
and the box I create like this:
output$box <- renderUI({
boxPlus(
div(style = 'overflow-x: scroll;'), dataTableOutput("table")
)
})
I tried it with: Similar Problem but I can not resolve the problem. Without the box everything works fine.
Never use reactive expressions inside a renderText function.
You have to wrap tagList around your two elements to return a SINGLE element (a list in your case).
Here is a reproduceable example.
library(shiny)
library(shinydashboardPlus)
library(dplyr)
# Define UI for application that draws a histogram
ui <- fluidPage(
# Application title
titlePanel("Hide box"),
# Sidebar with a slider input for number of bins
sidebarLayout(
sidebarPanel(
textInput("name", "Insert Number to filter cyl:")
),
mainPanel(
uiOutput("box")
)
)
)
server <- function(input, output) {
resultdf <- reactive({
mtcars %>%
filter(cyl > input$name)
})
output$box <- renderUI({
output$table <- renderDataTable({
resultdf()
})
if(input$name == "") {
return(NULL)
} else {
return(
tagList(
boxPlus(
div(style = 'overflow-x: scroll;'), dataTableOutput("table")
)
)
)
}
})
}
# Run the application
shinyApp(ui = ui, server = server)
As an extension of this example:
https://shiny.rstudio.com/gallery/creating-a-ui-from-a-loop.html
Say you would like the for loop to be of a length determined by a numeric input. So for example, extending the linked example (using just the second part of it):
ui <- fluidPage(
title = 'Creating a UI from a dynamic loop length',
sidebarLayout(
sidebarPanel(
# Determine Length of Loop
numericInput(inputId = "NumLoop", "Number of Loops", value = 5, min = 1, max = 5, step = 1)
),
mainPanel(
# UI output
lapply(1:input.NumLoop, function(i) {
uiOutput(paste0('b', i))
})
)
)
)
server <- function(input, output, session) {
reactive({
lapply(1:input$NumLoop, function(i) {
output[[paste0('b', i)]] <- renderUI({
strong(paste0('Hi, this is output B#', i))
})
})
})
}
shinyApp(ui = ui, server = server)
As far as I can tell there are two problems with the code:
In the UI, I don't know how to legitimately use the input from NumLoop in the for loop of the UI output. I have experimented with the conditionalPanel function with no luck.
In the server, once I put the loop behind a reactive function to make use of input$NumLoop I no longer have access to those renderUI outputs in the UI.
Any ideas of how to solves these issues would be much appreciated.
This should do the trick, as per #Dean, yes the second renderUI shouldn't be there
library(shiny)
ui <- fluidPage(
title = 'Creating a UI from a dynamic loop length',
sidebarLayout(
sidebarPanel(
# Determine Length of Loop
numericInput(inputId = "NumLoop", "Number of Loops", value = 5, min = 1, max = 10, step = 1)
),
mainPanel(
# UI output
uiOutput('moreControls')
)
)
)
server <- function(input, output, session) {
output$moreControls <- renderUI({
lapply(1:input$NumLoop, function(i) {
strong(paste0('Hi, this is output B#', i),br())
})
})
}
shinyApp(ui = ui, server = server)
I am pretty new to Shiny and dealing with the following problem, upon pressing an actionButton in shiny, I want it to do multiple calculations. I use the handler of observeEvent.
An example:
library(shiny)
ui <- fluidPage(
sidebarLayout(
sidebarPanel(`
actionButton("calc","calculate stuff")),
mainPanel(
textOutput("result")
)
)
)
server <- function(input,output){
observeEvent(input$calc, {output$result <- renderText({"only this is not enough"}) })
}
shinyApp(ui,server')`
Now what I would want is where the output$result is made in the server-observeEvent, I would like to perform additional tasks, say assign a variable a <- 12, calculate B4 <- input$ID1*inputID2 etc.
This can not be hard I imagine.. but I am just not getting there.
kind regards,
Pieter
You can use isolate, see this example:
library(shiny)
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
numericInput(inputId = 'x', label = 'Select a value for x', value = 1),
actionButton( "calc", "calculate stuff" )
),
mainPanel(
textOutput("result")
)
)
)
server <- function(input, output) {
output$result <- renderText({
input$calc
isolate({
y<- input$x *2
paste("The result is:", y)
})
})
}
shinyApp(ui, server)