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

stockVis app

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

#例子 - stockVis

##创建stockVis Shiny app

  • 创文件夹:stockVis
  • 下载: app.Rhelpers.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,这意味着您可以在服务器函数中将它们作为inputlog和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安装

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,332评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,508评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,812评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,607评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,728评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,919评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,071评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,802评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,256评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,576评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,712评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,389评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,032评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,026评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,473评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,606评论 2 350