My app takes multiple inputs (some fixed, some defined by the user) and produces multiple outputs using a long and complex reactive code. Outputs are stored in a list for convenient referencing.
Among the outputs is a plot of one of the inputs (all its possible values) against one of the outputs. So I need to stop reactivity for this one input to produce the plot. But i want to avoid repetition of the long code inside renderPlot(). Any ideas of how to achieve that?
Illustrating example plotting y1 against x1 is given below. It should help the user to see what value of x1 produces desirable y1, other parameters fixed.
My full app written with repetitions: https://katrine.shinyapps.io/salmoncycleupd1/
library(shiny)
library(bslib)
#fixed parameters
a<-10
b<-20
ui <- page_sidebar (
title = "updatable shiny1",
sidebar = sidebar(
sliderInput(
"Input1",
tags$strong("Define Input1"),
min = 1,
max = 15,
value = 5,
step = 1
),
sliderInput(
"Input2",
tags$strong("Define Input2"),
min = 100,
max = 1000,
value = 100,
step = 100
),
sliderInput(
"Input3",
tags$strong("Define Input3"),
min = 7,
max = 17,
value = 12
)
),
tabPanel(tags$h4("Outputs"),
layout_columns(
card(card_header(tags$span("Output1", style="color:tomato")),tableOutput("Output1")),
card(card_header(tags$span("Output2", style="color:tomato")),tableOutput("Output2")),
card(card_header(tags$span("Optimal", style="color:tomato")),plotOutput("Optimal")),
)
)
)
server <- function(input, output) {
mymodel <- reactive({
x1 <- input$Input1
x2 <- input$Input2
x3 <- input$Input3
#long and complex calculations
y1 <- x1+x2+x3
y2 <- x1*a
y3 <- x2*b
y4 <- x3+a+b
# Store all results in a list for use in different tables
list("y1" = y1, "y2" = y2, "y3" = y3, "y4" <- y4)
})
output$Output1 <- renderTable({
table1 <- data.frame(matrix(ncol = 2, nrow = 2))
colnames(table1) <- c("element1", "element2")
table1$element1 <- c(a, b)
table1$element2 <- c(mymodel()$y1, mymodel()$y2)
table1
})
output$Output2 <- renderTable({
table2 <- data.frame(matrix(ncol = 2, nrow = 2))
colnames(table2) <- c("element1", "element2")
table2$element1 <- c(a, b)
table2$element2 <- c(mymodel()$y3, mymodel()$y4)
table2
})
output$Optimal <- renderPlot({
#plot y1 against x1, when x2 and x3 are still reactive
#x1 is no longer reactive
x2 <- input$Input2
x3 <- input$Input3
optim <- function (x1) { # have to copy parts from mymodel here,
# cannot use y1 from the list as it is all reactive
y1 <- x1+x2+x3
}
y1_range <- c(optim(1), optim(2), optim(3), optim(4), optim(5), optim(6), optim(7),optim(8), optim(9), optim(10), optim(11), optim(12), optim(13), optim(14), optim(15))
x1_range <- c(1:15)
plot(x1_range,y1_range, type="l", xlab="x1, other parameters fixed", ylab= "y1", col="darkgreen", lwd=2)
})
}
shinyApp(ui = ui, server = server)
I have looked into isolate() function, but could not make it work.
Katrine Eriksen is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
I tried to separate function from reactive datas from data plot.
Be careful of two typos
- in the list :
"y4" = y4
(was"y4" <- y4
) - in
optim()
:y1 <- x1+x2+x3
at the end of a function return nothing.
options(shiny.reactlog=TRUE)
library(shiny)
library(bslib)
#fixed parameters
a<-10
b<-20
ui <- page_sidebar (
title = "updatable shiny1",
sidebar = sidebar(
sliderInput(
"Input1",
tags$strong("Define Input1"),
min = 1,
max = 15,
value = 5,
step = 1
),
sliderInput(
"Input2",
tags$strong("Define Input2"),
min = 100,
max = 1000,
value = 100,
step = 100
),
sliderInput(
"Input3",
tags$strong("Define Input3"),
min = 7,
max = 17,
value = 12
)
),
tabPanel(tags$h4("Outputs"),
layout_columns(
card(card_header(tags$span("Output1", style="color:tomato")),tableOutput("Output1")),
card(card_header(tags$span("Output2", style="color:tomato")),tableOutput("Output2")),
card(card_header(tags$span("Optimal", style="color:tomato")),plotOutput("Optimal")),
)
)
)
server <- function(input, output) {
MyComplexCalc <- function(x1 , x2, x3) {
#long and complex calculations
y1 <- x1+x2+x3
y2 <- x1*a
y3 <- x2*b
y4 <- x3+a+b
# Store all results in a list for use in different tables
list("y1" = y1, "y2" = y2, "y3" = y3, "y4" = y4,
"x1" = x1, "x2" = x2, "x3" = x3)
}
mymodel <- reactive({
MyComplexCalc(
x1 = input$Input1,
x2 = input$Input2,
x3 = input$Input3
)
})
output$Output1 <- renderTable({
table1 <- data.frame(matrix(ncol = 2, nrow = 2))
colnames(table1) <- c("element1", "element2")
table1$element1 <- c(a, b)
table1$element2 <- c(mymodel()$y1, mymodel()$y2)
table1
})
output$Output2 <- renderTable({
table2 <- data.frame(matrix(ncol = 2, nrow = 2))
colnames(table2) <- c("element1", "element2")
table2$element1 <- c(a, b)
table2$element2 <- c(mymodel()$y3, mymodel()$y4)
table2
})
y_DatasPlot <- reactive({
optim <- function (x1,datas) {
MyComplexCalc(
x1 = x1,
x2 = datas$x2,
x3 = datas$x3
)$y1
}
datas2 <- mymodel()
c(optim(1,datas2), optim(2,datas2), optim(3,datas2), optim(4,datas2), optim(5,datas2), optim(6,datas2),
optim(7,datas2),optim(8,datas2), optim(9,datas2), optim(10,datas2), optim(11,datas2), optim(12,datas2),
optim(13,datas2), optim(14,datas2), optim(15,datas2))
})
output$Optimal <- renderPlot({
y1_range <- y_DatasPlot()
x1_range <- c(1:15)
plot(x1_range,y1_range, type="l", xlab="x1, other parameters fixed", ylab= "y1", col="darkgreen", lwd=2)
})
}
shinyApp(ui = ui, server = server)
PS: Your full written app has very clean appareance.