在闪亮/闪亮的仪表板中为反应性数据框创建新列

时间:2018-02-06 21:23:46

标签: r shiny shinydashboard

在我的shinyApp服务器中,我根据输入创建了一个数据帧。但是,我想添加一个新列,该列使用该数据帧的两列。

server <- function(input, output, session) {
  l.out <- reactive({
    BatchGetSymbols(tickers = input$stock, 
                first.date = Sys.Date() - as.integer(input$length),
                last.date = Sys.Date())
  })
  stock_info <- reactive({
    l.out()$df.tickers
  })
  stock_info()$return <- reactive({
    rep(0, length(stock_info()$ref.date))
  })
  stock_info()$return <- reactive({
    for (i in 2:length(stock_info()$ref.date)){
      stock_info()$return[i] <- ((stock_info()$price.close[i] - 
stock_info()$price.close[i - 1]) / stock_info$price.close[i - 1])
    }
  })

我已经尝试过这样做,直到我尝试创建stock_info()$ return,然后我不断收到NULL留下的错误。 有什么提示吗?

1 个答案:

答案 0 :(得分:0)

我不熟悉BatchGetSymbols包,但下面示例中的概念也适用于您的用例。

首先,由于缺乏优雅的说法,我非常肯定这个表达......

  stock_info()$return <- reactive({
    rep(0, length(stock_info()$ref.date))
  })

...实际上并不是shiny反应对象和相关语法的工作方式。

看起来你可以通过将一堆中间步骤压缩成单个表达式来简化代码。如果您只有一组反应数据,您将在所有输出中使用,这可能是一种更直接的方法。

library(shiny)

ui <- fluidPage(
  textInput('stock','stock',"GE"),
  sliderInput('length', 'length', min = 1, max = 10, value = 5),
  dataTableOutput('my_table')
)

server <- function(input, output, session) {

  ## This will update whenever either input$length or input$stock change
  stock_info <- reactive({

    length <- as.integer(input$length)

    temp_stock_info <- data.frame(stock = input$stock,
                                  foo = seq_len(length),
                                  bar = rnorm(length))

    temp_stock_info$baz <- paste("xxx",length)

    return(temp_stock_info)
  })

  ## Return an output
  output$my_table <- renderDataTable({
    stock_info()
  })
}

shinyApp(ui, server)

但是,如果您将中间对象l.out用于各种结束输出,那么将它作为自己的反应对象可能是有意义的。然后,只要相关输入发生变化,我们就可以更新l.out,然后使用该中间变量通过其他下游反应来级联更新。

此外,我们可以根据不会影响stock_info的其他条件更新下游的被动对象,例如l.out,而不必每次都重新运行l.out

library(shiny)

ui <- fluidPage(
  textInput('stock','stock',"GE"),
  sliderInput('length', 'length', min = 1, max = 100, value = 50),
  sliderInput('displayLength', 'displayLength', min = 1, max = 20, value = 5),
  dataTableOutput('my_table')
)

server <- function(input, output, session) {

  ## l.out will change with input$length and input$stock
  ## but NOT input$displayLength
  l.out <- reactive({
    data.frame(stock = input$stock,
               foo = rnorm(input$length),
               l.out_update_time = Sys.time())
  })

  ## stock_info will update whenever l.out changes or the displayLength changes. 
  ## l.out will NOT be updated if only input$displayLength changes
  stock_info <- reactive({
    tmp_stock_info <- head(x = l.out(), n = input$displayLength)
    tmp_stock_info$stock_info_update_time <- Sys.time()
    return(tmp_stock_info)
  })

  ## Return an output
  output$my_table <- renderDataTable({
    stock_info()
  })
}

shinyApp(ui, server)