使用纯 ggplot2 解决方案在 Shiny 中悬停工具提示
Hover tooltip in Shiny using pure ggplot2 solution
此处的目标是使用纯 ggplot2 解决方案在悬停时呈现工具提示,而无需任何 javascript 黑客攻击。
这是一个天真的尝试性解决方案(不起作用)
library(tidyverse)
library(shiny)
shinyApp(
ui = fluidPage(
plotOutput("plotCars", hover="hover", width=700,height=300),
verbatimTextOutput("info")),
server = function(input, output) {
hovered <- reactive(nearPoints(mtcars, input$hover, maxpoints = 1) %>%
rownames_to_column("model"))
output$plotCars <- renderPlot({
ggplot(mtcars, aes(x=wt, y=mpg)) +
geom_point() +
geom_point(color="red",data=hovered()) +
geom_label(aes(label=model),data=hovered(),
hjust="inward",vjust="inward",
size=4,color="red",alpha=0.5)+
xlab("Weight(1000 lbs)")+ylab("Miles/gallon")
})
output$info <- renderPrint({
hovered()
})
})
这里的问题是,一旦重新渲染绘图,包括悬停信息(例如标签),悬停事件就会自动重置为 NULL
,从而使绘图无效。
在实践中,上述解决方案 几乎 有效,悬停点的工具提示会短暂显示,但 input$hover
事件立即被新情节和绘图的重新渲染删除了工具提示,因为悬停事件现在是 NULL
。事实上工具提示闪烁一次然后消失。
解决方法是保留悬停数据点的前一个值,避免失效。这个objective可以使用observeEvent()
method and a reactiveVal()
来实现。解决方案是这样的:
悬停点信息是一个反应值 (reactiveVal()
),用 zero-row tibble 初始化,与绘制的数据集具有相同的列。
这个初始值允许在 ggplot2 层中进行平滑的可视化,将它初始化为 NULL
.
是不可能的
该值响应悬停事件而更新,当事件变为NULL
时函数observeEvent()
默认忽略(ignoreNULL = TRUE
),因此当 input$hover
无效为 NULL
时,该值不会更新并保持与之前相同
在绘图渲染中,hovered()
值最初是一个 zero-row tibble(但仍然具有与绘图默认数据兼容的正确列)因此不显示任何东西,稍后当在一个点附近执行悬停时,它将包含点信息。
library(tidyverse)
library(shiny)
shinyApp(
ui = fluidPage(
plotOutput("plotCars", hover="hover", width=700,height=300),
verbatimTextOutput("info")),
server = function(input, output) {
hovered <- reactiveVal(mtcars %>% filter(FALSE) %>% rownames_to_column("model"))
observeEvent(input$hover, {
hovered(nearPoints(mtcars, input$hover, maxpoints = 1) %>%
rownames_to_column("model"))
})
output$plotCars <- renderPlot({
ggplot(mtcars, aes(x=wt, y=mpg)) +
geom_point() +
geom_point(color="red",data=hovered()) +
geom_label(aes(label=model),data=hovered(),
hjust="inward",vjust="inward",
size=4,color="red",alpha=0.5)+
xlab("Weight(1000 lbs)")+ylab("Miles/gallon")
})
output$info <- renderPrint({
hovered()
})
})
此处的目标是使用纯 ggplot2 解决方案在悬停时呈现工具提示,而无需任何 javascript 黑客攻击。
这是一个天真的尝试性解决方案(不起作用)
library(tidyverse)
library(shiny)
shinyApp(
ui = fluidPage(
plotOutput("plotCars", hover="hover", width=700,height=300),
verbatimTextOutput("info")),
server = function(input, output) {
hovered <- reactive(nearPoints(mtcars, input$hover, maxpoints = 1) %>%
rownames_to_column("model"))
output$plotCars <- renderPlot({
ggplot(mtcars, aes(x=wt, y=mpg)) +
geom_point() +
geom_point(color="red",data=hovered()) +
geom_label(aes(label=model),data=hovered(),
hjust="inward",vjust="inward",
size=4,color="red",alpha=0.5)+
xlab("Weight(1000 lbs)")+ylab("Miles/gallon")
})
output$info <- renderPrint({
hovered()
})
})
这里的问题是,一旦重新渲染绘图,包括悬停信息(例如标签),悬停事件就会自动重置为 NULL
,从而使绘图无效。
在实践中,上述解决方案 几乎 有效,悬停点的工具提示会短暂显示,但 input$hover
事件立即被新情节和绘图的重新渲染删除了工具提示,因为悬停事件现在是 NULL
。事实上工具提示闪烁一次然后消失。
解决方法是保留悬停数据点的前一个值,避免失效。这个objective可以使用observeEvent()
method and a reactiveVal()
来实现。解决方案是这样的:
悬停点信息是一个反应值 (
是不可能的reactiveVal()
),用 zero-row tibble 初始化,与绘制的数据集具有相同的列。 这个初始值允许在 ggplot2 层中进行平滑的可视化,将它初始化为NULL
.该值响应悬停事件而更新,当事件变为
NULL
时函数observeEvent()
默认忽略(ignoreNULL = TRUE
),因此当input$hover
无效为NULL
时,该值不会更新并保持与之前相同在绘图渲染中,
hovered()
值最初是一个 zero-row tibble(但仍然具有与绘图默认数据兼容的正确列)因此不显示任何东西,稍后当在一个点附近执行悬停时,它将包含点信息。
library(tidyverse)
library(shiny)
shinyApp(
ui = fluidPage(
plotOutput("plotCars", hover="hover", width=700,height=300),
verbatimTextOutput("info")),
server = function(input, output) {
hovered <- reactiveVal(mtcars %>% filter(FALSE) %>% rownames_to_column("model"))
observeEvent(input$hover, {
hovered(nearPoints(mtcars, input$hover, maxpoints = 1) %>%
rownames_to_column("model"))
})
output$plotCars <- renderPlot({
ggplot(mtcars, aes(x=wt, y=mpg)) +
geom_point() +
geom_point(color="red",data=hovered()) +
geom_label(aes(label=model),data=hovered(),
hjust="inward",vjust="inward",
size=4,color="red",alpha=0.5)+
xlab("Weight(1000 lbs)")+ylab("Miles/gallon")
})
output$info <- renderPrint({
hovered()
})
})