How to make R Shiny react to slider changes, but not recalculate everything if I just want to plot another part of solution

Hello all!

I am new to shiny, and although I have managed to get my code working, there is something that I just cannot get my head around. Below is a code that solves a system of two differential equations, with coefficients being selected using Shiny sliders, and in the main panel I am trying to select which of the two variables to plot. The problem is that since selection of the plotting variable is part of the "input", if I change a variable that I want to plot, this results in the recalculation of the whole thing. I have attached a short code illustrating this problem on the example of a small system, but in reality I have a really large system of ODEs that takes quite a lot of time to solve, so I really need to make sure that if the sliders with parameters are not changed, the system is only solved once, and I can then separately plot each of the variables without a time-consuming recalculation of the whole thing.

I have had a look at "reactive" as an option, but can't see how to make it work for this. I have tried to make it reactive by writing sim=reactive({Run_LV(input)}) but it returns an error message "Error in $: object of type 'closure' is not subsettable" Any idea what I could be doing wrong? I've also tried sim=reactive({as.data.frame(Run_LV(input))}) but get the same error.

Could you please have a look at the short code below and let me know if that's possible, and more specifically, how to make it plot either U or V but without solving the system again.

Thanks a lot in advance!

library(deSolve)
library(shiny)
library(shinyWidgets)
library(plotly)

ui <- fluidPage(
  sidebarLayout(
    sidebarPanel(
      fluidRow(
        column(width=6,
               sliderInput("a", "Coef 1",0, 5, 1, step=0.2),
               sliderInput("b", "Coef 2", 0, 5, 1, step=0.2)
        )
      )
    ),
    mainPanel(
      selectInput("Var",
                  label = "Choose variable to plot:",
                  choices = c("First"="U", "Second"="V"), 
                  selected = c("U")
                  ),

      plotlyOutput("plot0")

    )
  )
)

LV=function(t,y,p){ # define Lotka-Volterra system
  with(as.list(p),{
    z=rep(0,2)
    z[1]=y[1]-a*y[1]*y[2]
    z[2]=b*y[1]*y[2]-y[2]

  return(list(z))
})
}

Run_LV=function(p){ # run the simmulation
t = seq(from=0, to=10, by=0.1)
y0=c(1.5,0.7) # initial condition
para=c(list("a"=p$a,"b"=p$b)) # values of parameters

out = ode(y=y0, times=t, func=LV, parms=para ,method="ode45")

return(list("out"=out))
}

server <- function(input, output) {

  output$plot0=renderPlot({

  sim=Run_LV(input)

   sol=sim$out
   xvar=sol[,1] # time
   if(input$Var=="U"){
     yvar=sol[,2] # will plot U component
   }else{
     yvar=sol[,3] # will plot V component
   }

   data<- data.frame(xvar,yvar)
   p=plot_ly(data,x=~xvar, y=~yvar, type = 'scatter', mode = 'lines')
   p

  })

}
shinyApp(ui = ui, server = server)
library(deSolve)
library(shiny)
library(shinyWidgets)
library(plotly)

ui <- fluidPage(
  sidebarLayout(
    sidebarPanel(
      fluidRow(
        column(width=6,
               sliderInput("a", "Coef 1",0, 5, 1, step=0.2),
               sliderInput("b", "Coef 2", 0, 5, 1, step=0.2)
        )
      )
    ),
    mainPanel(
      selectInput("Var",
                  label = "Choose variable to plot:",
                  choices = c("First"="U", "Second"="V"), 
                  selected = c("U")
      ),
      
      plotlyOutput("plot0")
      
    )
  )
)

LV<-function(t,y,p){ # define Lotka-Volterra system
  with(as.list(p),{
    z<-rep(0,2)
    z[1]<-y[1]-a*y[1]*y[2]
    z[2]<-b*y[1]*y[2]-y[2]
    
    return(list(z))
  })
}

Run_LV<-function(a,b){ # run the simmulation
  t <- seq(from=0, to=10, by=0.1)
  y0<-c(1.5,0.7) # initial condition
  para<-c(list("a"=a,"b"=b)) # values of parameters
  
  out <- ode(y=y0, times=t, func=LV, parms=para ,method="ode45")
  
  return(list("out"=out))
}

server <- function(input, output) {
  
  solution <- reactive({
    sim<-Run_LV(input$a,input$b)
    sim$out
  })
  output$plot0<-renderPlotly({
    sol <- req(solution())
    xvar<-sol[,1] # time
    if(input$Var=="U"){
      yvar<-sol[,2] # will plot U component
    }else{
      yvar<-sol[,3] # will plot V component
    }
    
    data<- data.frame(xvar,yvar)
    plot_ly(data,x=~xvar, y=~yvar, type = 'scatter', mode = 'lines')
  })
  
}
shinyApp(ui = ui, server = server)

@nirgrahamuk This is great, thanks a lot!

This topic was automatically closed 54 days after the last reply. New replies are no longer allowed.