R shiny教程-6:使用响应表达式reactive()

stockVis app

Shiny apps构建好之后,其运行与反应要快速才会吸引用户;因此,在构建Shiny apps时,耗时计算代码的放置显得尤为重要。

#例子 - stockVis

##创建stockVis Shiny app

  • 创文件夹:stockVis
  • 下载: app.R 和helpers.R
  • 安装quantmod包:install.packages("quantmod")
  • 运行:runApp("stockVis")
stockVis app

stockVis应用程序根据股票代码查找股票价格,并将结果显示为折线图。

  • 选择要检查的股票
  • 选择一系列要回顾的日期
  • 选择是否在y轴上绘制股票价格或股票价格的对数,
  • 决定是否根据通货膨胀调整价格。

注:注意,“为通货膨胀调整价格”复选框还不能工作。本节的任务之一是修复这个复选框。

默认情况下,stockVis会显示SPY代码(整个标普500的一个指数)。要查找不同的股票,请键入雅虎财经能够识别的股票符号。你可以在这里查看雅虎的股票代码:here。一些常见的符号是GOOG(谷歌)、AAPL (Apple)和GS (Goldman Sachs)。

stockVis非常依赖quantmod包中的两个功能:

  • 使用getsymbols直接从雅虎财经(Yahoo finance)和圣路易斯联邦储备银行(Federal Reserve Bank of St. Louis)等网站下载金融数据。
  • 使用chartSeries在一个吸引人的图表中显示价格。
  • stockVis还依赖于一个名为helpers.R脚本。它包含一个根据通货膨胀调整股票价格的函数。

#复选框和日期范围

stockVis应用程序使用了一些新的小部件:

  • 日期范围选择器,使用dateRangeInput
  • 用checkboxInput创建的几个复选框。复选框小部件非常简单。当复选框被选中时,它们返回TRUE,当复选框未被选中时返回FALSE。
  • 这些复选框在ui对象中被命名为log和adjust,这意味着您可以在服务器函数中将它们作为inputadjust进行查找。

#简化计算

检查当您点击“在对数尺度上绘制y轴”时会发生什么。input$log的值会改变,这会导致renderPlot中的整个表达式重新运行:

output$plot <- renderPlot({
  data <- getSymbols(input$symb, src = "yahoo",
                     from = input$dates[1],
                     to = input$dates[2],
                     auto.assign = FALSE)

  chartSeries(data, theme = chartTheme("white"),
              type = "line", log.scale = input$log, TA = NULL)
})

当renderPlot重新运行时:

  • 它使用getSymbols从Yahoo finance重新获取数据
  • 它重新绘制图表。

这并不好,因为您不需要重新获取数据来重新绘制绘图。事实上,如果你过于频繁地重新获取数据,雅虎财经(Yahoo finance)会切断你的服务(因为你开始看起来像个爬虫机器人)。但更重要的是,重新运行getSymbols是不必要的工作,这会降低应用程序的速度并消耗服务器。

#响应表达式

可以限制在使用反应表达式的反应期间重新运行的内容。
使用reactive函数创建一个响应表达式,就像渲染render*函数。
例如,下面是一个反应式表达式,它使用stockVis的小部件从Yahoo获取数据。

dataInput <- reactive({
  getSymbols(input$symb, src = "yahoo",
    from = input$dates[1],
    to = input$dates[2],
    auto.assign = FALSE)
})

当您运行表达式时,它将运行getSymbols并返回结果。您可以通过调用dataInput()在renderPlot中使用价格数据。

output$plot <- renderPlot({    
  chartSeries(dataInput(), theme = chartTheme("white"),
    type = "line", log.scale = input$log, TA = NULL)
})

响应表达式比常规R函数更聪明一些。它们缓存数据。并知道它们的值何时已经更新。

第一次运行反应表达式时,该表达式将其结果保存在计算机的内存中。下一次调用响应表达式时,它可以返回这个保存的结果,而不进行任何计算(这会使应用程序更快)。

反应表达式只有在知道结果是最新的情况下才会返回保存的结果。如果反应表达式获悉结果已经更新了(因为改变了小部件),表达式将重新计算结果。然后返回新的结果并保存一个新的副本。反应表达式将使用这个新的副本,直到它也更新为止。

reactive()优势:

  • 反应式表达式在第一次运行时保存其结果。
  • 下一次调用响应表达式时,它检查保存的值是否已更新(即,它所依赖的小部件是否已更改)。
  • 值没更新,就可以调用先前保存的值,不进行任何计算;更新了的话,重新运算表达式计算结果。

可以用reactive()来防止Shiny重新运行不必要的代码。考虑一下反应表达式将如何在下面的新stockVis应用程序中工作。

server <- function(input, output) {

  dataInput <- reactive({
    getSymbols(input$symb, src = "yahoo",
               from = input$dates[1],
               to = input$dates[2],
               auto.assign = FALSE)
  })

  output$plot <- renderPlot({

    chartSeries(dataInput(), theme = chartTheme("white"),
                type = "line", log.scale = input$log, TA = NULL)
  })

}

当你点击“Plot y axis on the log scale”,输入input$log将改变,renderPlot将重新执行。

  • renderPlot将调用dataInput()
  • dataInput将检查dates和symb小部件是否没有更改
  • dataInput将返回其保存的股票价格数据集,而无需重新从雅虎获取数据
  • renderPlot将用选择的的轴表达方式重新绘制图表。

#依赖性

当在Shiny app修改了股票代码,Shiny 也会知道,并且重新画图。

当遇到以下两种情况,Shiny会重新运行:

  • 对象的render*函数中的input中的值发生变化,
  • 对象的render*函数中的反应性表达式已经更新

可以将反应表达式看作连接,链接input和output中的对象。output中的对象将响应链中任何下游所做的更新。(可以设计一个长链,因为反应表达式可以调用其他反应表达式)

#修复 “Adjust prices for inflation”

现在来修复 “Adjust prices for inflation”,用户就能够根据通货膨胀调整的价格和未调整的价格之间切换。

server <- function(input, output) {

  dataInput <- reactive({
    getSymbols(input$symb, src = "yahoo",
        from = input$dates[1],
        to = input$dates[2],
        auto.assign = FALSE)
  })

  output$plot <- renderPlot({   
    data <- dataInput()
    if (input$adjust) data <- adjust(dataInput())

    chartSeries(data, theme = chartTheme("white"),
        type = "line", log.scale = input$log, TA = NULL)
  })
}

#总结

通过使用reactive()模块化代码,可以加快应用程序的速度.

  • reactive()接受输入值或其他反应表达式的值,并返回一个新值
  • reactive()保存它们的结果,并且只会在输入发生更改时重新计算
  • 使用reactive({ })创建响应表达式
  • 调用reactive()结果,使用reactive expressions名称加括号
    • dataInput <- reactive({})的结果调用方法是dataInput();dataInput() 中有多个对象时,使用dataInput()$对象名调用
  • 只有在reactive()render* 中可以使用reactive()

#原文:

Use reactive expressions

系列文章:
R shiny教程-1:一个 Shiny app的基本组成部分
R shiny教程-2:布局用户界面
R shiny教程-3:添加小部件到Shiny App
R shiny教程-4:Shiny app响应式结果展示
R shiny教程-5:调用R程序和导入数据
Shiny Server安装

你可能感兴趣的:(R shiny教程-6:使用响应表达式reactive())