带有nearPoints()的动态ggplot图层闪亮

2024-05-14

我熟悉闪亮的基础知识,但在这里遇到了一些困难。我希望能够在单击某个点以突出显示该点时添加 ggplot 图层。我知道 ggvis 可以做到这一点,并且画廊中有一个很好的例子,但我希望能够使用nearPoints()捕获点击作为 ui 输入。

我尝试过一些(见下文),除了 ggplot 图层出现然后消失之外,它还能工作。我已经尝试过对此进行各种编辑reactive(), eventReactive()等等。

任何帮助深表感谢...

library(shiny)
library(ggplot2)

shinyApp(
  ui = shinyUI(
        plotOutput("plot", click = "clicked")
    ),

  server = shinyServer(function(input, output) {
    output$plot <- renderPlot({
      ggplot(mtcars, aes(x = mpg, y = wt)) +
        geom_point() +
        geom_point(data = nearPoints(mtcars, input$clicked), colour = "red", size = 5)
    })
  })
)

我想我从概念上理解为什么这不起作用。该情节依赖于input$clicked这意味着当input$clicked更改绘图重新渲染,但这又会重置input$clicked。有点像第22条军规的情况。


请尝试这个:

方法一(推荐)

library(shiny)
library(ggplot2)

# initialize global variable to record selected (clicked) rows
selected_points <- mtcars[0, ]
str(selected_points)


shinyApp(
  ui = shinyUI(
    plotOutput("plot", click = "clicked")
  ),

  server = shinyServer(function(input, output) {

    selected <- reactive({
      # add clicked
      selected_points <<- rbind(selected_points, nearPoints(mtcars, input$clicked))
      # remove _all_ duplicates if any (toggle mode) 
      # http://stackoverflow.com/a/13763299/3817004
      selected_points <<- 
        selected_points[!(duplicated(selected_points) | 
                            duplicated(selected_points, fromLast = TRUE)), ]
      str(selected_points)
      return(selected_points)
    })

    output$plot <- renderPlot({
      ggplot(mtcars, aes(x = mpg, y = wt)) +
        geom_point() +
        geom_point(data = selected(), colour = "red", size = 5)
    })
  })
)

如果您单击某个点一次,该点就会突出显示。如果您第二次单击它,突出显示将再次关闭(切换)。

代码中使用了全局变量selected_points存储实际突出显示(选定)的点和反应表达式selected()每当单击一个点时,它就会更新全局变量。

The str(selected_points)可能有助于可视化工作,但可以删除。

方法 2(替代)

有一种稍微不同的方法,它使用observe()代替reactive()并引用全局变量selected_points直接而不是从函数返回对象:

library(shiny)
library(ggplot2)

selected_points <- mtcars[0, ]
str(selected_points)


shinyApp(
  ui = shinyUI(
    plotOutput("plot", click = "clicked")
  ),

  server = shinyServer(function(input, output) {

    observe({
      # add clicked
      selected_points <<- rbind(selected_points, nearPoints(mtcars, input$clicked))
      # remove _all_ duplicates (toggle)
      # http://stackoverflow.com/a/13763299/3817004
      selected_points <<- 
        selected_points[!(duplicated(selected_points) | 
                            duplicated(selected_points, fromLast = TRUE)), ]
      str(selected_points)
    })

    output$plot <- renderPlot({
      # next statement is required for reactivity
      input$clicked
      ggplot(mtcars, aes(x = mpg, y = wt)) +
        geom_point() +
        geom_point(data = selected_points, colour = "red", size = 5)
    })
  })
)

当然也可以使用全局变量selected_points直接在ggplot调用而不是调用反应函数selected()。但是,您必须确保renderPlot()每当input$clicked被改变了。因此,虚拟参考input$clicked必须包含在代码中renderPlot().

现在,反应函数selected()不再需要,可以用observe()表达。相对于reactive(), observe()不返回值。它只是更新全局变量selected_points每当input$clicked被修改。

方法 3(无功值)

这种方法避免了全局变量。相反,它使用reactiveValues创建一个类似列表的对象rv具有反应式编程的特殊功能(请参阅?reactiveValues).

library(shiny)
library(ggplot2)

shinyApp(
  ui = shinyUI(
    plotOutput("plot", click = "clicked")
  ),

  server = shinyServer(function(input, output) {

    rv <- reactiveValues(selected_points = mtcars[0, ])

    observe({
      # add clicked
      rv$selected_points <- rbind(isolate(rv$selected_points), 
                                           nearPoints(mtcars, input$clicked))
      # remove _all_ duplicates (toggle)
      # http://stackoverflow.com/a/13763299/3817004
      rv$selected_points <- isolate(
        rv$selected_points[!(duplicated(rv$selected_points) | 
                               duplicated(rv$selected_points, fromLast = TRUE)), ])
      str(rv$selected_points)
    })

    output$plot <- renderPlot({
      ggplot(mtcars, aes(x = mpg, y = wt)) +
        geom_point() +
        geom_point(data = rv$selected_points, colour = "red", size = 5)
    })
  })
)

请注意,在observer部分参考rv需要封装在isolate()以确保仅更改为input$clicked将触发执行代码observer。否则,我们将陷入无限循环。执行renderPlot每当无功值被触发rv被改变了。

结论

就我个人而言,我更喜欢使用反应函数的方法 1,这使得依赖关系(反应性)更加明确。我发现方法 2 中对 input$clicked 的虚拟调用不太直观。方法 3 需要彻底了解反应性并使用isolate()在正确的地方。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

带有nearPoints()的动态ggplot图层闪亮 的相关文章

随机推荐