如果从Shiny中的isolate()函数创建,则找不到对象

时间:2017-04-11 18:03:35

标签: r shiny plotly

我正在开发一个Shiny应用程序,其中有两个滑块输入。这些输入值以不同方式对数据帧进行子集化,然后将该数据帧的子集绘制成散点图。

我试图阻止散点图被重新绘制,除非用户点击" Go!"按钮。为了尝试实现这一点,我在滑块输入值上使用了isolate()函数,这样数据框和图只会在" Go!"按钮已更改。

这似乎工作正常,但我也试图让用户在Plotly中使用选择工具,并查看与该选择对应的数据框行。但是,当我尝试这样做时,我收到一个错误("错误:对象' datInput'未找到")。此行在以下示例中进行了注释:

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)

1 个答案:

答案 0 :(得分:1)

您没有正确使用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