假设我有一个非常基本的Shiny设置:
shinyServer(function(input, output) {
output$plot_1 <- renderPlot({
DF <- DF[which(DF$column==input$num), ]
p <- ggplot()
...
plot(p))}
一切都很棒。所以,在此之后我创建了另一个ggplot,基于相同的输入,除了一行额外的代码:
输出$ plot_2&lt; - renderPlot({
DF <- DF[which(DF$column==input$num), ]
DF <- *doing something different here*
p <- ggplot()
...
plot(p))}
所以我已经开始创造了10个这样的情节,彼此之间都有微小的变化。基本上,它们都有一两行不同,但都是独一无二的。 (请放心,我已经使用grid
包将它们全部压缩到一页上,看起来并不坏一半。
没问题!但我开始得到一些哲学问题。
对于每一个情节,Shiny都被迫重新发明(大部分)车轮。我是:
1)获得boated代码
2)为每个绘图重新运行相同的操作 - 例如,数据框由input$num
等子集化的所有工作,这在图中是一致的。
为什么和我这样?因为,据我所知,每个renderPlot
内的范围是本地的。我不能在任何单独的反应函数之外全局修改我的数据帧。为了证明这一点,如果我试图将代码拉到被动呼叫之外:
shinyServer(function(input, output) {
DF <- DF[which(DF$column==input$num), ] #no longer within the renderPlot call
output$plot_1 <- renderPlot({
p <- ggplot()
...
plot(p))}
我收到错误
Error in .getReactiveEnvironment()$currentContext() :
Operation not allowed without an active reactive context. (You tried to do something that can only be done from inside a reactive expression or observer.)
我的情节缓慢而笨拙地出现。有大量的代码(超过90%)被运行十次,我觉得应该运行一次!
我的问题是:如何在反应环境中最好地重复修改?如何使一个输入(例如,input$num
)影响我的数据帧一次,并将更改提供给我的所有10个输出?
答案 0 :(得分:1)
关于使用makeReactiveBinding()
的单个文件应用。
library(shiny)
server <- function(input, output) {
DF <- data.frame(c(2,3,5), c("aa", "bb", "cc"), c(TRUE, FALSE, TRUE))
makeReactiveBinding("DF")
modifData <- reactive({
DF <- DF[,input$num, drop=FALSE]
})
output$dataTable <- renderDataTable({
# Data modification is now done in reactive expression which caches the value, which means
# that calculation is done again only when input$num changes
DF <- modifData()
# Unique modifications here
return(DF)
})
}
ui <- shinyUI(fluidPage(
sidebarLayout(
sidebarPanel(
sliderInput("num", "Column:", min = 1, max = 3, value = 1)
),
mainPanel(dataTableOutput("dataTable"))
)
))
shinyApp(ui = ui, server = server)