不允许从闪亮的输出对象中读取对象?

Reading objects from shiny output object not allowed?

我正在尝试编写一个小应用程序,允许用户制作散点图,select 图中点的子集,然后以 .csv 格式输出 table只是那些 selected 点。我想出了如何让页面向上和 运行 以及如何使用 brushedPoints select 点。出现带有 selected 点的 table,但是当我按下下载按钮时,出现错误 "Reading objects from shinyoutput object not allowed."。我是否无法下载我可以在屏幕上看到的 .csv 格式的 table?如果是这样,是否有解决方法?

我使用下面的鸢尾花数据集重现了这个问题。任何帮助弄清楚为什么我无法下载显示行的 table 的帮助将不胜感激。

data(iris)

ui <- basicPage(
  plotOutput("plot1", brush = "plot_brush"),
  verbatimTextOutput("info"),mainPanel(downloadButton('downloadData', 'Download'))
)


server <- function(input, output) {
  output$plot1 <- renderPlot({
ggplot(iris,aes(x=Sepal.Width,y=Sepal.Length)) +
    geom_point(aes(color=factor(Species))) + 
    theme_bw()
  })

  output$info <- renderPrint({
brushedPoints(iris, input$plot_brush, xvar = "Sepal.Width", yvar = "Sepal.Length")
  })

  output$downloadData <- downloadHandler(
      filename = function() { 
        paste('SelectedRows', '.csv', sep='') },
        content = function(file) {
        write.csv(output$info, file)
      }
  )

}


shinyApp(ui, server)

问题是输出对象也在生成所有网络显示内容。相反,您需要单独拉取数据以供下载。您可以在下载代码中再次调用 brushedPoints 来完成此操作。然而,更好的方法是使用 reactive() 函数只执行一次,然后在需要的任何地方调用它。以下是我将如何修改您的代码以使其工作:

data(iris)

ui <- basicPage(
  plotOutput("plot1", brush = "plot_brush"),
  verbatimTextOutput("info"),mainPanel(downloadButton('downloadData', 'Download'))
)


server <- function(input, output) {
  output$plot1 <- renderPlot({
    ggplot(iris,aes(x=Sepal.Width,y=Sepal.Length)) + geom_point(aes(color=factor(Species))) + theme_bw()
  })


  selectedData <- reactive({
    brushedPoints(iris, input$plot_brush)
  })

  output$info <- renderPrint({
    selectedData()
  })

  output$downloadData <- downloadHandler(
    filename = function() { 
      paste('SelectedRows', '.csv', sep='') },
    content = function(file) {
      write.csv(selectedData(), file)
    }
  )

}


shinyApp(ui, server)

(注意,使用ggplot2,你不需要在brushedPoints中显式设置xvaryvar。所以,我在这里删除它以增加灵活性的代码。)

我不知道 shiny 中有任何 "lasso" 风格的自由绘图功能(不过,给它一个星期——他们会不断添加有趣的工具)。但是,您可以通过允许用户 select 多个区域 and/or 单击单个点来模仿该行为。服务器逻辑变得更加混乱,因为您需要将结果存储在 reactiveValues 对象中以便能够重复使用它。我做了类似的事情,允许我在一个地块上 select 点,在其他地块上 highlight/remove 它们。这比你在这里需要的更复杂,但下面应该有效。您可能想添加其他 buttons/logic(例如,"reset" 和 select 离子),但我相信这应该可行。我确实在图中添加了 selection 的显示,以便您可以跟踪 selected 的内容。

data(iris)

ui <- basicPage(
  plotOutput("plot1", brush = "plot_brush", click = "plot_click")
  , actionButton("toggle", "Toggle Seletion")
  , verbatimTextOutput("info")
  , mainPanel(downloadButton('downloadData', 'Download'))
)


server <- function(input, output) {
  output$plot1 <- renderPlot({

    ggplot(withSelected()
           , aes(x=Sepal.Width
                 , y=Sepal.Length
                 , color=factor(Species)
                 , shape = Selected)) +
      geom_point() +
      scale_shape_manual(
        values = c("FALSE" = 19
                   , "TRUE" = 4)
      , labels = c("No", "Yes")
      , name = "Is Selected?"
      ) +
      theme_bw()
  })

  # Make a reactive value -- you can set these within other functions
  vals <- reactiveValues(
    isClicked = rep(FALSE, nrow(iris))
  )


  # Add a column to the data to ease plotting
  # This is really only necessary if you want to show the selected points on the plot
  withSelected <- reactive({
    data.frame(iris
               , Selected = vals$isClicked)
  })



  # Watch for clicks
  observeEvent(input$plot_click, {

    res <- nearPoints(withSelected()
                      , input$plot_click
                      , allRows = TRUE)

    vals$isClicked <-
      xor(vals$isClicked
          , res$selected_)
  })


  # Watch for toggle button clicks
  observeEvent(input$toggle, {
    res <- brushedPoints(withSelected()
                         , input$plot_brush
                         , allRows = TRUE)

    vals$isClicked <-
      xor(vals$isClicked
          , res$selected_)
  })

  # pull the data selection here
  selectedData <- reactive({
    iris[vals$isClicked, ]
  })

  output$info <- renderPrint({
    selectedData()
  })

  output$downloadData <- downloadHandler(
    filename = function() { 
      paste('SelectedRows', '.csv', sep='') },
    content = function(file) {
      write.csv(selectedData(), file)
    }
  )

}


shinyApp(ui, server)