2017-04-11 121 views
0

我正在使用Shiny应用程序,其中有两个滑块输入。这些输入值不同地对数据帧进行子集合,然后将该数据帧的子集绘制成散点图。如果从Shiny中的isolate()函数中创建对象,则找不到对象

我试图防止scatterplot被重新绘制,除非用户点击“Go!”按钮。为了达到这个目的,我在滑块输入值上使用了isolate()函数,以便数据框和图只在“Go!”时更新。按钮被改变。

这似乎工作正常,但我也试图让用户在Plotly中使用选择工具,并看到与该选择对应的数据框行。但是,当我尝试这样做时,我收到一个错误(“Error:object'datInput'not found”)。此行在以下示例中进行了评论:

library(shiny) 
library(plotly) 

ui <- shinyUI(pageWithSidebar(
    headerPanel("Click the button"), 
    sidebarPanel(
    sliderInput("val1", "Value 1:", min = 0, max = 1, value=0.5, step=0.1), 
    sliderInput("val2", "Value 2:", min = 0, max = 1, value=0.5, step=0.1), 
    actionButton("goButton", "Go!") 
), 
    mainPanel(
    plotlyOutput("plot1"), 
    verbatimTextOutput("click") 
) 
)) 

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

    set.seed(1) 
    dat <- data.frame(Case = paste0("case",1:15), val1=runif(15,0,1), val2=runif(15,0,1)) 
    dat$Case <- as.character(dat$Case) 

    xMax = max(dat$val1) 
    xMin = min(dat$val1) 
    yMax = max(dat$val2) 
    yMin = min(dat$val2) 
    maxTemp = max(abs(xMax), abs(xMin)) 

    observeEvent(input$goButton, 
     output$plot1 <- renderPlotly({ 
     # Use isolate() to avoid dependency on input$val1 and input$val2 
     datInput <- isolate(subset(dat, val1 > input$val1 & val2 > input$val2)) 
     p <- qplot(datInput$val1, datInput$val2) +xlim(0, ceiling(maxTemp)) +ylim(0,1) 
     ggplotly(p) 
     }) 
) 

    d <- reactive(event_data("plotly_selected")) 

    output$click <- renderPrint({ 
    if (is.null(d())){ 
     "Click on a state to view event data" 
    } 
    else{ 
     #str(d()$pointNumber) #Seems to be working 
     datInput[d()$pointNumber,] #Error: object 'datInput' not found 
    } 
    }) 
}) 

shinyApp(ui, server) 

有关此问题的解决方法的任何建议,我们将不胜感激!

编辑:

这里是溶液按@mlegge。我简单地添加用户之后,输出选择特定点:

library(shiny) 
library(plotly) 

ui <- shinyUI(pageWithSidebar(
    headerPanel("Click the button"), 
    sidebarPanel(
    sliderInput("val1", "Value 1:", min = 0, max = 1, value=0.5, step=0.1), 
    sliderInput("val2", "Value 2:", min = 0, max = 1, value=0.5, step=0.1), 
    actionButton("goButton", "Go!") 
), 
    mainPanel(
    plotlyOutput("plot1"), 
    verbatimTextOutput("click") 
) 
)) 

set.seed(1) 
dat <- data.frame(Case = paste0("case",1:15), val1=runif(15,0,1), val2=runif(15,0,1)) 
dat$Case <- as.character(dat$Case) 

xMax = max(dat$val1) 
xMin = min(dat$val1) 
yMax = max(dat$val2) 
yMin = min(dat$val2) 
maxTemp = max(abs(xMax), abs(xMin)) 

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

    # datInput only validated once the go button is clicked 
    datInput <- eventReactive(input$goButton, { 
    subset(dat, val1 > input$val1 & val2 > input$val2) 
    }) 

    output$plot1 <- renderPlotly({ 
    # will wait to render until datInput is validated 
    plot_dat <- datInput() 

    p <- qplot(plot_dat$val1, plot_dat$val2) + xlim(0, ceiling(maxTemp)) +ylim(0,1) 
    ggplotly(p) 
    }) 

    d <- reactive(event_data("plotly_selected")) 
    output$click <- renderPrint({ 
    if (is.null(d())){ 
     "Click on a state to view event data" 
    } 
    else{ 
     #str(d()$pointNumber) 
     datInput()[d()$pointNumber+1,] #Working now 
    } 
    }) 
}) 

shinyApp(ui, server) 

回答

2

您没有使用正确isolate,更好的解决方案是一个eventReactive

library(shiny) 
library(plotly) 

ui <- shinyUI(pageWithSidebar(
    headerPanel("Click the button"), 
    sidebarPanel(
    sliderInput("val1", "Value 1:", min = 0, max = 1, value=0.5, step=0.1), 
    sliderInput("val2", "Value 2:", min = 0, max = 1, value=0.5, step=0.1), 
    actionButton("goButton", "Go!") 
), 
    mainPanel(
    plotlyOutput("plot1") 
) 
)) 

set.seed(1) 
dat <- data.frame(Case = paste0("case",1:15), val1=runif(15,0,1), val2=runif(15,0,1)) 
dat$Case <- as.character(dat$Case) 

xMax = max(dat$val1) 
xMin = min(dat$val1) 
yMax = max(dat$val2) 
yMin = min(dat$val2) 
maxTemp = max(abs(xMax), abs(xMin)) 

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

    # datInput only validated once the go button is clicked 
    datInput <- eventReactive(input$goButton, { 
    subset(dat, val1 > input$val1 & val2 > input$val2) 
    }) 

    output$plot1 <- renderPlotly({ 
    # will wait to render until datInput is validated 
    plot_dat <- datInput() 

    p <- qplot(plot_dat$val1, plot_dat$val2) + xlim(0, ceiling(maxTemp)) +ylim(0,1) 
    ggplotly(p) 
    }) 
}) 

shinyApp(ui, server) 

你会发现,你的数据生成已移到server之外,这是因为它只需要运行一次。

你也不应该在观察者中包装一个output对象,而应该用反应控制输入数据。

enter image description here

+0

谢谢你的有用的答案!你能不能解释一下“你会注意到你的数据生成已经被移出了服务器,这是因为它只需要运行一次。”我如何能够知道这一点,是否有任何缺点?具体来说,在服务器外部生成数据会使大数据集变慢(我正在努力实现的目标!)谢谢。 – LanneR

+1

每当某个东西无效时,运行'server',因此总是要在'global.R'中(或者只在你的会话中,如果你正在运行一个'app.R')加载/创建大型数据集到避免一次又一次地进行大量的数据处理。 – mlegge

+1

下面是我在谈论的https://shiny.rstudio.com/articles/scoping.html#objects-visible-across-all-sessions和https://shiny.rstudio.com/articles/scoping.html #global-objects – mlegge

相关问题