我熟悉闪亮的基础知识但在这里挣扎。我希望能够在点击一个点时添加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。
答案 0 :(得分:12)
请试试这个:
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()
,它会在点击一个点时更新全局变量。
str(selected_points)
可能有助于可视化工作,但可以删除。
使用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
。
这种方法避免了全局变量。相反,它使用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中输入$ click的虚拟调用不太直观。方法3需要彻底了解反应性并在正确的位置使用isolate()
。