Reactivity的示例程序與Hello Text很相似,但是用到了反應(yīng)式編程里更多細(xì)節(jié)的概念,要運行該例子,請鍵入:
> library(shiny)
> runExample("03_reactivity")
前面幾個例子給你了個初步印象——Shiny應(yīng)用程序的代碼長成什么樣子。前面解釋了反應(yīng)式編程的一點概念,不過略過了大部分細(xì)節(jié)。 在本節(jié),我們會更進一步講解這些細(xì)節(jié)。如果你想更深入學(xué)習(xí)這些細(xì)節(jié),請看《理解反應(yīng)式設(shè)計》這節(jié),從反應(yīng)式設(shè)計概述開始。
什么是反應(yīng)式設(shè)計
Shiny的web框架從本質(zhì)上說是使從頁面中獲取輸入值并傳遞給R變得更容易,然后把R代碼的結(jié)果以輸出值的形式返回給頁面。
input values => R code => output values
因為Shiny程序是交互式的,輸入值可以隨時改變,輸出值也應(yīng)該立即更新,以反映輸入輸入值的改變。
Shiny中有反應(yīng)式編程的庫,你可以用它來定義你的應(yīng)用程序邏輯。使用這個庫,改變輸入值會自動引發(fā)R代碼中相應(yīng)的部分重新執(zhí)行,反過來會更新輸出結(jié)果。
反應(yīng)式編程基礎(chǔ)
反應(yīng)式編程是種編程風(fēng)格,這種風(fēng)格以反應(yīng)值開始,反應(yīng)值是隨時間變化的值,或者由用戶輸入的值,在反應(yīng)值之上綁定有反應(yīng)表達式(reactive expression),反應(yīng)表達式會接收到反應(yīng)值并執(zhí)行其他反應(yīng)表達式。
反應(yīng)表達式有趣的地方在于,當(dāng)它執(zhí)行的時候,會自動跟蹤讀取到的反應(yīng)值以及調(diào)用的其他反應(yīng)表達式。如果反應(yīng)表達式所依賴的反應(yīng)值和反應(yīng)表達式發(fā)生了改變,那么該反應(yīng)表達式的返回值也應(yīng)該變化(原文是If those “dependencies” become out of date, then they know that their own return value has also become out of date)。因為有這種跟蹤機制,所以改變一個反應(yīng)值會自動引發(fā)依賴于它的反應(yīng)表達式重新執(zhí)行。
在shiny中使用反應(yīng)值時,最常見的方式是使用input
對象。input
對象會被傳遞給shinyServer
函數(shù)中,讓你可以用類似列表的語法來訪問網(wǎng)頁上的輸入值。從代碼上看,你好像是從列表或者數(shù)據(jù)框里讀取了值,但實際上你讀取的是反應(yīng)值。你不必寫監(jiān)測輸入值變化的代碼,只需要寫反應(yīng)表達式來讀取所需的反應(yīng)值,Shiny會處理好什么時候調(diào)用它們。
創(chuàng)建反應(yīng)表達式很簡單,只需要把一個正常的表達式傳遞給reactive
函數(shù)就行。在本節(jié)的示例程序中,下面這個簡單的反應(yīng)表達式的功能是,基于用戶在表單中選擇的選項來返回R數(shù)據(jù)框。
datasetInput
<-
reactive({
switch(input$dataset,
"rock"
=
rock,
"pressure"
=
pressure,
"cars"
=
cars)
})
為了將反應(yīng)值轉(zhuǎn)化為可以在網(wǎng)頁上呈現(xiàn)的輸出,我們要將它們賦值給output
對象(同樣傳遞給shinyServer
函數(shù))。下面是個賦值給輸出值的例子,輸出值依賴于我們剛才定義的反應(yīng)表達式datasetInput
,以及input$obs
:
output$view
<-
renderTable({
head(datasetInput(),
n
=
input$obs)
})
不管是 datasetInput
還是input$obs
,一旦它們的值發(fā)生改變,上面這個表達式將會重新執(zhí)行(它的輸出也會在瀏覽器里重新渲染)。
回到代碼上
現(xiàn)在我們已經(jīng)對一些核心概念有了更多了解,我們再來看看源代碼,并嘗試更深層次理解。用戶接口的定義中,增加了來用定義說明文字(caption)的文本輸入框,盡管它與前一個例子還是很相似。
library(shiny)
# Define UI for dataset viewer application
shinyUI(pageWithSidebar(
# Application title
headerPanel("Reactivity"),
# Sidebar with controls to provide a caption, select a dataset, and
# specify the number of observations to view. Note that changes made
# to the caption in the textInput control are updated in the output
# area immediately as you type
sidebarPanel(
textInput("caption",
"Caption:",
"Data Summary"),
selectInput("dataset",
"Choose a dataset:",
choices
=
c("rock",
"pressure",
"cars")),
numericInput("obs",
"Number of observations to view:",
10)
),
# Show the caption, a summary of the dataset and an HTML table with
# the requested number of observations
mainPanel(
h3(textOutput("caption")),
verbatimTextOutput("summary"),
tableOutput("view")
)
))
服務(wù)端腳本
服務(wù)端腳本聲明了反應(yīng)表達式datasetInput
和三個反應(yīng)輸出值。下面有每個定義的詳細(xì)注釋描述了在反應(yīng)式系統(tǒng)中是如何運作的:
library(shiny)
library(datasets)
# Define server logic required to summarize and view the selected dataset
shinyServer(function(input,
output)
{
# By declaring datasetInput as a reactive expression we ensure that:
#
# 1) It is only called when the inputs it depends on changes
# 2) The computation and result are shared by all the callers (it
# only executes a single time)
# 3) When the inputs change and the expression is re-executed, the
# new result is compared to the previous result; if the two are
# identical, then the callers are not notified
#
datasetInput
<-
reactive({
switch(input$dataset,
"rock"
=
rock,
"pressure"
=
pressure,
"cars"
=
cars)
})
# The output$caption is computed based on a reactive expression that
# returns input$caption. When the user changes the "caption" field:
#
# 1) This expression is automatically called to recompute the output
# 2) The new caption is pushed back to the browser for re-display
#
# Note that because the data-oriented reactive expression below don't
# depend on input$caption, those expression are NOT called when
# input$caption changes.
output$caption
<-
renderText({
input$caption
})
# The output$summary depends on the datasetInput reactive expression,
# so will be re-executed whenever datasetInput is re-executed
# (i.e. whenever the input$dataset changes)
output$summary
<-
renderPrint({
dataset
<-
datasetInput()
summary(dataset)
})
# The output$view depends on both the databaseInput reactive expression
# and input$obs, so will be re-executed whenever input$dataset or
# input$obs is changed.
output$view
<-
renderTable({
head(datasetInput(),
n
=
input$obs)
})
})








暫無數(shù)據(jù)