msmarchena
msmarchena

Reputation: 113

How to store reactive outputs values in a vector to be used in a function?

This is an extension of the question

How to isolate the output of a reactive (function) and save to a data.frame?

Basically I want to construct a table based on a vector with predetermined and added values. I want to show as tableoutput the original vector and a column with the roll mean of the previous 4 values of this vector. For instance, if the user added the value 200, I will have

d <- c(rep(100,4),200) 

and using zoo::rollapply() I have the roll mean of the previous 4 values of d

md <- rollapply(d , mean , fill = NA, width = list(-1:-4))

the expected result

cbind(d,md)

       d  md
[1,] 100  NA
[2,] 100  NA
[3,] 100  NA
[4,] 100  NA
[5,] 200 100

In my shiny app I am not able to use my function, the app close when I add a value. But if I use other function like input$c1 + 5 it works. I think that the problem is that I do not know how to capture the updated vector and use it to run a function that needs a vector as input. Furthermore, to run the app I needed to match the same number of rows in the new column.

Here is my UI code:

library(shiny)

fluidPage(
  sidebarPanel(textInput("c1","example"),

           actionButton("update", "Update Table")
  ),

 mainPanel(tableOutput("example")

 )
)

and the server

library(shiny)
library(zoo)

function(input, output) {

  #Example
  d <- c(rep(100,4))
  m <- c(rep(100,4))

  md <- reactive(
 rollapply(values$df , mean , fill=NA , width=list(-1:-4))
 )

  values <- reactiveValues(df = data.frame('D' = d, 'M_D'= m))
  newEntry <- observe({
    if(input$update > 0) {
        values$df <- isolate(rbind(values$df,data.frame('D' =input$c1, 
   'M_D' = md())))
    }
  })

  output$example <- renderTable({values$df})

} 

Upvotes: 3

Views: 4319

Answers (1)

Mike Wise
Mike Wise

Reputation: 22827

So I would say were using too many different shiny mechanisms and they were tripping over each other. I made the following changes:

  • changed observe to observeEvent so as to confine the calculations to when you pres the update button.
  • did away with the isolate usage as it is not needed in an observeEvent as opposed to an observe.
  • got rid of the reactive md() function as you already have that data stored in a reactiveValues list.
  • made the rollingapply operate only on the relevant columns instead of the entire data frame.
  • cleaned up the syntax a bit - got rid if extraneous quotes, c() in c(rep(...)), etc.
  • compressed it a bit.
  • added the as.numeric to the input$c1 processing otherwise it was causing that column to convert to a factor and change its values.

So here is the code:

library(shiny)
library(zoo)

u <- fluidPage(
  sidebarPanel(textInput("c1","example"),
               actionButton("update", "Update Table")
  ),
  mainPanel(tableOutput("example")
  )
)
s <- function(input, output) {

  #Example
  d <- rep(100,4)
  m <- rep(100,4)

  values <- reactiveValues(df = data.frame(D=d, M_D=m))

  newEntry <- observeEvent(input$update,{
    d_new <- c(values$df$D,as.numeric(input$c1))
    m_d_new <- rollapply(d_new, mean , fill=NA , width=list(-1:-4))
    values$df <- data.frame(D=d_new,M_D=m_d_new)
  })
  output$example <- renderTable({values$df})
} 
shinyApp(u,s)

Which yields the following after entering 200 and pressing Update Table a few times:

enter image description here

Upvotes: 4

Related Questions