动态ggplot图层闪亮nearPoints() [英] dynamic ggplot layers in shiny with nearPoints()
问题描述
我熟悉闪亮的基础知识,但在这里挣扎着。我希望能够添加一个ggplot图层,当一个点被点击时突出显示该点。我知道这可能与ggvis,并在画廊有一个很好的例子,但我希望能够使用 nearPoints()
捕获点击作为用户界面输入。
我尝试了一些东西(见下文),它与ggplot层分离,然后消失。我尝试过对 reactive()
, eventReactive()
等进行各种编辑。
任何帮助非常感谢......
library(shiny)
库(ggplot2)
$ b $ 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),color =red,size = 5)
})
})
)
我想我理解这是行不通的。该图依赖于输入$ clicked
,这意味着当输入$点击
时改变绘图重新渲染,但是这个依次重置输入$点击
。
请试试这个:
< h1>方法1(推荐)
库(闪亮)
库(ggplot2)
#初始化全局变量以记录所选行(单击)
selected_points < b ui = shinyUI(
plotOutput(plot,click =clicked)
),
server = shinyServer(function(input,output){
selected < - 反应性({
#添加点击
selected_points<< - rbind(selected_points,nearPoints(mtcars,input $ clicked))
#remove _all_ duplicates if任何(切换模式)
#http://stackoverflow.com/a/13763299/3817004
selected_points<< -
selected_points [!(duplicated(selected_points)|
重复(selected_points,fromLast = TRUE)),]
str(selected_point s)
return(selected_points)
})
输出$ plot < - renderPlot({
ggplot(mtcars,aes(x = mpg,y = wt ))+
geom_point()+
geom_point(data = selected(),color =red,size = 5)
})
})
)
如果您每次点击一个点,它都会高亮显示。如果再次单击它,突出显示会再次关闭(切换)。
代码使用全局变量 selected_points
存储实际突出显示的点(选定)和一个反应表达式 selected()
,该点更新全局变量,每当一个点被点击时。
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(fu (输入,输出){
观察({
#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)
})
输出$ plot< - renderPlot({
#下一个语句是反应性需要
输入$单击
ggplot(mtcars,aes(x = mpg,y = wt))+
geom_point()+
geom_point(data = selected_points,color =red,size = 5)
})
})
)
当然,您可以直接在 ggplot
调用中使用全局变量 selected_points
调用被动函数 selected()
。但是,只要 input $ clicked
发生更改,您必须确保执行 renderPlot()
。因此,必须在 renderPlot()
中的代码中包含对 input $ clicked
的虚引用。
现在,被动函数 selected()
不再需要,可以用观察代替()
表达式。与 reactive()
不同, observe()
不返回值。只要修改了 input $ clicked
,它就会更新全局变量 selected_points
。
方法3(反应值)
这种方法避免了全局变量。相反,它使用 reactiveValues
创建一个类似列表的对象 rv
,它具有反应式编程的特殊功能(请参阅<$ c
$ p $库$
库(ggplot2)
$ b shinyApp(
ui = shinyUI(
plotOutput(plot,click =clicked)
),
server = shinyServer(函数(输入,输出){
rv < - reactiveValues(selected_points = mtcars [0,])
观察({
#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 $ sel ect_point)
})
输出$ plot < - renderPlot({
ggplot(mtcars,aes(x = mpg,y = wt))+
geom_point ()+
geom_point(data = rv $ selected_points,color =red,size = 5)
})
})
)
请注意,在观察者
部分引用 rv
需要封装在 isolate()
中,以确保只改变输入$点击
会触发观察者
中代码的执行。否则,我们会得到一个无限循环。执行 renderPlot
会在被动值 rv
发生变化时触发。
结论
就个人而言,我更喜欢使用反应函数的方法1,这使得依赖性(反应性)更加明确。我发现在方法2中输入$点击的虚拟调用较不直观。方法3需要彻底了解反应性,并在正确的地方使用 isolate()
。
I'm familiar with the basics of shiny but struggling with something here. I would like to be able to add a ggplot layer when a point is clicked to highlight that point. I know this is possible with ggvis and there is a nice example in the gallery, but I would like to be able to use nearPoints()
to capture the click as ui input.
I have tried something (see below) which works apart from the ggplot layer appears and then disappears. I have tried all kinds of edits to this with reactive()
, eventReactive()
and so on.
Any help is much appreciated...
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)
})
})
)
I think I understand conceptually why this doesn't work. The plot has a dependency on input$clicked
which means that when input$clicked
changes the plot re-renders but this in turn resets input$clicked
. Bit of a catch 22 situation.
Please, try this:
Approach 1 (recommended)
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)
})
})
)
If you click a point one time it is highlighted. If you click it a second time the highlight is turned off again (toggling).
The code uses a global variable selected_points
to store the actually highlighted (selected) points and an reactive expression selected()
which updates the global variable whenever a point is clicked.
The str(selected_points)
may help to visualize the working but can be removed.
Approach 2 (alternative)
There is a slightly different approach which uses observe()
instead of reactive()
and references the global variable selected_points
directly instead of returning the object from a function:
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)
})
})
)
Of course, you can use the global variable selected_points
directly in the ggplot
call instead of calling the reactive function selected()
. However, you have to ensure that renderPlot()
is executed whenever input$clicked
is changed. Therefore, the dummy reference to input$clicked
has to be included in the code within renderPlot()
.
Now, the reactive function selected()
is no longer needed and can be replaced by an observe()
expression. As opposed to reactive()
, observe()
doesn't return a value. It just updates the global variable selected_points
whenever input$clicked
is modified.
Approach 3 (reactive values)
This approach avoids a global variable. Instead, it uses reactiveValues
to create a list-like object rv
with special capabilities for reactive programming (see ?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)
})
})
)
Please, note that in the observer
part references to rv
need to be encapsulated in isolate()
to ensure that only changes to input$clicked
will trigger execution of the code in observer
. Otherwise, we'll get an endless loop. Execution of renderPlot
is triggered whenever the reactive value rv
is changed.
Conclusion
Personally, I prefer approach 1 using reactive functions which make the dependencies (reactivity) more explicit. I find the dummy call to input$clicked in approach 2 less intuitive. Approach 3 requires a thorough understanding of reactivity and using isolate()
in the right places.
这篇关于动态ggplot图层闪亮nearPoints()的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!